about summary refs log blame commit diff stats
path: root/apps/mu.subx
blob: 5719c79151721073a0441f587bf872aff3d09086 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
7307
7308
7309
7310
7311
7312
7313
7314
7315
7316
7317
7318
7319
7320
7321
7322
7323
7324
7325
7326
7327
7328
7329
7330
7331
7332
7333
7334
7335
7336
7337
7338
7339
7340
7341
7342
7343
7344
7345
7346
7347
7348
7349
7350
7351
7352
7353
7354
7355
7356
7357
7358
7359
7360
7361
7362
7363
7364
7365
7366
7367
7368
7369
7370
7371
7372
7373
7374
7375
7376
7377
7378
7379
7380
7381
7382
7383
7384
7385
7386
7387
7388
7389
7390
7391
7392
7393
7394
7395
7396
7397
7398
7399
7400
7401
7402
7403
7404
7405
7406
7407
7408
7409
7410
7411
7412
7413
7414
7415
7416
7417
7418
7419
7420
7421
7422
7423
7424
7425
7426
7427
7428
7429
7430
7431
7432
7433
7434
7435
7436
7437
7438
7439
7440
7441
7442
7443
7444
7445
7446
7447
7448
7449
7450
7451
7452
7453
7454
7455
7456
7457
7458
7459
7460
7461
7462
7463
7464
7465
7466
7467
7468
7469
7470
7471
7472
7473
7474
7475
7476
7477
7478
7479
7480
7481
7482
7483
7484
7485
7486
7487
7488
7489
7490
7491
7492
7493
7494
7495
7496
7497
7498
7499
7500
7501
7502
7503
7504
7505
7506
7507
7508
7509
7510
7511
7512
7513
7514
7515
7516
7517
7518
7519
7520
7521
7522
7523
7524
7525
7526
7527
7528
7529
7530
7531
7532
7533
7534
7535
7536
7537
7538
7539
7540
7541
7542
7543
7544
7545
7546
7547
7548
7549
7550
7551
7552
7553
7554
7555
7556
7557
7558
7559
7560
7561
7562
7563
7564
7565
7566
7567
7568
7569
7570
7571
7572
7573
7574
7575
7576
7577
7578
7579
7580
7581
7582
7583
7584
7585
7586
7587
7588
7589
7590
7591
7592
7593
7594
7595
7596
7597
7598
7599
7600
7601
7602
7603
7604
7605
7606
7607
7608
7609
7610
7611
7612
7613
7614
7615
7616
7617
7618
7619
7620
7621
7622
7623
7624
7625
7626
                                                     


                                     
                                                          
                                  
 


                                                                              

                                                                         
                                                                         




                                                        

                         
                                                           







                                                                             


                                                                             
                           
                                                        
                                                                 
 


                                                                           



                                                                            

                                                                            
 
                                                                           

















                                                                            

                                
                                                                      
                                                                                        

                                                
                                       


                                                                              

                                       


                    
               
 


                                           
                               
                                                                             

                           
                                  


                           
                        
                               
                              


                       
                                       

                                             


                     
                                    
                                                    


                                 


                                    


                                             
                               
                              


                                              
                               
                              
                              
 
                                    
                                                                         

                                                                            





                                                                                   
                                                                     







                                                                                       
               

                            
                               
                              
                
                                       
                                   

                                       
                                                                   

                                                                            
 





                                                                                
                             


                                  
                               

                                  
                                             
 





























                                                                                  
                               
                                             
                                                                   
                                    


                                   
                                  
                                    
                                   




                          
 
                        











                                                                    


                              

       


                                        
                            
         
                                    
         

                        



                                         
 











                                                                              
         
                                     
         
                                      
            

                                
                                   
            
                            
               
 
                                      
         
                                      
         

                                       
                                           
            
                                         
            
                                        
            
                                          
            
                                                                 
            
                                                                 
            
                                          
            

                                    
                             
               
 
                

         
                                  
         
                          
           
 
                                       
         
                                  
           

                                   
 
                           
         
 
                                           
         
                                      
           

                                                                        
 
                        
            
 
                                
         
                               
         

                                                                   
                                                              
            
                                                          
            
                       
            
 
                         
         
                             
         

                        
 



                                                                    
         

                             
                            
            
 








                                                                                                    
                                                                  
 
                             
         
             
                           
         

                                                              

                                                                    
                 
                                   
         
                                    
           
 
                             
            
 

       
                                                                                      
                                      
                                                            
              
                  
        

                                                                      



                     
                      

                                                                                               
                                                                                     
        
                   


                                                                                                
                                                                      


                                                                                                         

                                                                                                                                     

                                                                             
                                                          
                                                                 






                                                                 
                                 
      
 
                     
                                                                 


                                                             
                                                                              
         




                                                      
                                    
           
                                   
            

                            
 


                                                                          
            










                                                                                                   
         
                                          
           

                                  
 




                        
                                 



                                        
                               
                                    
                                                      
                                      
                              






                                         
                                      



                          
                               
 
                                                                                                                         


                        

                      

                                             

                                            
                                               
                                                        
                                           
                                                    

                                                         
     

                                                    
                                         
                                            
                                                  
                

                         











                                     
                                                     
                                      
                                                      
     
                                                                              







                                                                              




                                     
                                                     
                                      
                                                      



                                           
                                                                              







                                           







                                                                                                                       





                                         




                                     
                                                     
                                      
                                                      





                                           
                                                                              







                                           







                                                                                                                                 
                           







                                                                                                                                  




                        
                               




                                     
                                                     
                                      
                                                      
     
                                                  

                                    
                                                                              







                                           







                                                                                                                       





                                        




                                     
                                                     
                                      
                                                      
     
                                                  


                                                
                                                                              







                                           




                                                                                                                                







                                                                                                                                                    




                        
                                         












                                                          
                                                                              







                                           




                                                                                                                                 







                                                                                                                                                     




                        
                                     








                                                      
                                                                             



                                                        
                                                                              







                                           




                                                                                                                             
                                                                                                                             
                                                                                                                                                 






                                                                                                                              




                        
                                       













                                                                             
                                                                              







                                           





                                                                                                                               
                                                                                                                                                   






                                                                                                                                  




                        
                                         













                                                                             
                                                                              







                                           





                                                                                                                                 
                                                                                                                                                     






                                                                                                                                          




                        
                                            
















                                                                                
                                                                              







                                           




                                                                                                                                    













                                                                                                                                       
                                                                                                                                                         






                                                                                                                                                          




                        









































                                                                                                                                   
                                            









                                                      

                                                

                                    
                                                                              







                                           




                                                                                                                                    









                                                                                                                                                        




                        


































                                                                                                            
                                                                                                                                                                                                







                                                                                 












































                                                                                                                                                                                 
                                                               













                                                      
                                                                              



























                                                                                                                                                                              
                                            









                                                      

                                                             

                                    
                                                                              







                                           




                                                                                                                                    










                                                                                                                                        




                        












































                                                                                                                                                             











































                                                                                                                                                                                                                        
                                                        







                                                      






                                                             
                                                                              





























                                                                                                                                                    




































                                                                                                           
                                                                                                                                                                   







                                                                                
























































                                                                                                                        





















































                                                                                                                                                                   












































                                                                                                                                              





































                                                                                                                                    
                                                                                                                                                                                 






                                                                                                         






































                                                                                                                                                                                               
























                                                                    
                                                      

























                                                                                                                                                        












































                                                                                                                             






































                                                                                                                                                       
                                                                                                                                                                                                    





                               




































                                                                                                                              
                                                                                                                                                          












































                                                                                                                               
                                                                                                                                                            











































                                                                                                                                     
                                                                                                                                                                                   











































                                                                                                                               
                                                                                                                                                            











































                                                                                                                                
                                                                                                                                                              











































                                                                                                                                         
                                                                                                                                                                                           






                                                                                                              
                                                  







                                                      





                                                                    
                                                                              




























                                                                                                                                                 

























































                                                                                                                                                        













































                                                                                                                                       
                                           







                                                      





                                                             
                                                                              




























                                                                                                                                                


































                                                                                                     
                                                                                                                                 







                                                                          
                                              















                                                      
                                                                              







                                           




                                                                                                                                      













                                                                                                                                                            




                        




















































                                                                                                                                                                     
                                                    









                                                      
                                            




                                                  
                                                                              







                                           




                                                                                                                                            













                                                                                                                                                                  




                        




































                                                                                                                    
                                                                                                                                                







                                                                                         
                                                  







                                                      




                                                             
                                                                              




































                                                                                                                                              







                                                               
                                                                              
































                                                                                                                                           
                       







                                                      








                                                               
                                                                              





























                                                                                                                      

















































































                                                                                                                





                                           


























                                                                                                                  




                        















                                                             
                                                                              













































                                                                                                                                     
                                                                              































                                                                                                                                   
                        







                                                      








                                                               
                                                                              

































                                                                                                                                                          
                                                   

















                                                              
                                                                                                                                        







                                                                                                    
                                    
                    
                                          
                      
                                         

                                                                             

                                                                                                                                       





                               
                                  







                                                      





                                                             
                                                                              







                                           













                                                                                                                                                                    




                        
                 













                                                         
                                                                              


























                                                                                                                         








                                                      
     

                                                                                   
                                      


                                                                                     


                                                                    
                                                                              
                                      





                                           
                                                                           






                                                                                                                              

















                                                                                                                                        
                
                        


                 
                                             

















                                                      
                                                                              







                                           




                                                                                                                                     


                                                                                                                                     

















                                                                                                                                                            




                        
                                                   

















                                                         
                                                                              







                                           




                                                                                                                                           


                                                                                                                                           

















                                                                                                                                                                  




                        
                                               

















                                                      
                                                                              







                                           




                                                                                                                                       

















                                                                                                                                                                




                        
                                                          


















                                                               
                                                                              







                                           

























                                                                                                                                                                            




                        
                                                   


                                                                           
















                                                      
                                                                              












                                                                                                                                           




                                                                                                                                           













                                                                                                                                                                  




                        
                                                            


                                                                              







                                                      








                                                  
                                                                              







                                           




























                                                                                                                                                                           
                                                              










                                                                             








                                                  
                                                                              



























                                                                                                                                                                          




                        
                                                             







                                                      









                                                  
                                                                              





































                                                                                                                                                                            
                                                                      







                                                      












                                                      
                                                                              












































                                                                                                                                                                                       



















                                                                         
                                                                              



























































                                                                                                                                                                                         
                                                                              




































                                                                                                                                                                                       


















                                                                        
                                                                              





































                                                                                                                                                                         
                                                                       







                                                      











                                                    
                                                                              






































                                                                                                                                                                                      
                                                              







                                                      











                                                    
                                                                              




































                                                                                                                                                                             
                                                                      







                                                      











                                                    
                                                                              






































                                                                                                                                                                                     
                                                  












                                                         
                                                                              






























                                                                                                                                                            











































                                                                                                                                                                                                                       












































                                                                                                                                                                      














































                                                                                                                                                                 
                     













                                                                       
                                                                              





























                                                                                                                                           
                             







                                                      





                                                                          
                                                                              














                                                                                                                       
                                                                                                                                         
                                                                                                                            
                                                                                                                                           






                                                                                                                       




                        













































                                                                                                                                                  
                                      













                                                               
                                                                              

















                                                                                                                                          
                                                                                                                                                  
                                                                                                                                                     







                                                                                                                                                 




                        


































                                                                                                     





                                          


























                                                                                                                                                                              
                              







                                                      






                                                                            
                                                                              







                                           









                                                                                                                                          








                                                                                                                                                                




                        
















































                                                                                                                                                                         
                                           







                                                      





                                                                            
                                                                              















                                                                                                                                                       
                                                                                                                                  












                                                                                                                                                                   













































                                                                                                                                                                            
                                       














                                                                            
                                                                              





































                                                                                                                                                                                  
                                                    













                                                                          
                                                                              




































                                                                                                                                                                            




















































                                                                                                                                                                                     
                                           







                                                      







                                                                                         
                                                                              

















                                                                                                                                                       
                                                                                                                                                                  













                                                                                                                                                                 


















































                                                                                                                                                                           
                                                    







                                                      







                                                                                         
                                                                              

















                                                                                                                                                                
                                                                                                                                                                                        














                                                                                                                                                                          



















































                                                                                                                                                                                                 
                                          







                                                      










                                                                       
                                                                              







                                           






                                                                                                                                    
                                                                                                                                                      

                                                                                                                                                                  
                                                                                                                                                                   







                                                                                                                                   




                        


































                                                                                                               
                                                                                                                                                           










































                                                                                                              
                                                                                                                                                 







                                                                                   
                                                            







                                                      








                                             
                                                                              



























                                                                                                                                                                      















































                                                                                                                                                                                                   
                                                         



















                                                      
                                                                              







































                                                                                                                                                                        
                                                                           



















                                                                  
                                                                              







































                                                                                                                                                                        

                                                                             
                                                                      






















                                                                     
                                                                              





































                                                                                                                                                                                            
                                                                                                                                                                                   












                                                                                                                                                                      
                                   

















                                                                      
                                                                              







                                           





                                                                                                                           
           

                                                                                                                           
           
                                                                                                                             
         
                                                                                                                                                         
               
                                                                                                                            
               





























                                                                                                                                              
                                                                              

























                                                                                                                                                            




                        

















                                                                      
                                                                              






























                                                                                                                                                                            












































                                                                                                                                                                                                                        












































                                                                                                                                                                                                                             














































                                                                                                                                                                                            



































































                                                                                                                                                             






































                                                                                                         
                                                                                                                                                            
                                   



















































                                                                                                                                                                    















































                                                                                                                                                                                          










































                                                                                                                                                                  





                               
















































                                                                                                                                                                















































                                                                                                                                                            















































                                                                                                                                                            















































                                                                                                                                                                               

























                                                                              



































































































































































                                                                                                                                                           

                                                                    



























                                                                                                                                                             
                                         







                                                      







                                                                                       
                                                                          

                                    
                                                                              

















                                                                                                                                                     
                                                                                                                                                                           












                                                                                                                                                      



















                                                                                   
                                                                              



























































                                                                                                                                                                
                                                                              
































































                                                                                                                                                                
                                                                              
































































                                                                                                                                                                
                                                                              








































                                                                                                                                                         











































                                                                                                                                                                   
 











































                                                                                                                                                                       
 











































                                                                                                                                                                         
 















                                                              
     




























                                                                                                                                                                                       


                        









                                                              
                        






























































































































































































































































                                                                                                                                                                                                    
                                                                                                                                                                                                                  














































































































































                                                                                                                                                                            












































                                                                                                                                                                                     































































































































































































































































































































                                                                                                                                                                 
              
                               
                                            
                                   
                                      
                                  






                                               
                                 


                                                            
                                          
                                        
                                    





                                                            

                                                    
                         
                          
         

                                                                             
                                       
                            
                            

                                
                                             


                                                               
                                                              

                                   
         

                                          








                                                                       





























                                                                         


                                                                                     
                                            




                                                    








                                             
                                                           
                               
                                                                         
                               



                                   

                                          
                       
                                     


                      


                                           

                         
                 
                 


                 

                               




                        
                 
                                                             




                                                                

                     

                                                                                
                                              




                                                                

                     






                        

                     

                                   


                                                     
                                                                                                                                                                        
                 

                                             
                                         

                                               

                  
                                                
                                           



                                                                           
                                     
                                          
                                              
                                

                  
                                                
                                           


                                                                           
                                     
                                                

             





                        

               


                              
                               


                         



                             
                        
                                 
                    



                                                               

                                      
                                    
                                                               

                                       
                                    
                                                               

                                      
                                    
                                                               
                        
                                                     
                          
     
                                             
                                   



                                                                 
                                        
                                        
                                      
                                                               

                                         
                                      
                                   

                                        
                                      
                                                                 
                                                       
                                                                      
                                   


                                                            
                                                                 
                                      
       


                                                                                                      
                              

                                 
                                   
       

                         
                           
     

                                           



                                                                 

                                        
                                      
                                   

                                         
                                      
                                                                 

                                        
                                      
                                                                 
                                                       
                                                                      
                                     


                                                            
                                                                
                                              
                                                               

                                                                                                            

                         
                                  
                                   

                                 
                                  

                         

                 






                        
                                    
                                                        

                                                                                                       
                            
                                            


                                      

                     
                                    








                                                                          


                                                            


                                    






                                                                         

                                                      

                                                                            
                            
                                            


                                      

                     




































































































































































































                                                                                                                                              
                              




                                     
                                               
                              
                                        

                                  


                                       

                        
             
                                                                       











                                                                              


                                                                                                         





                                        





                                                              
                          
                                        

                                  


                                       

                        
             
                                                                       





                                                                                       
                                                







                                                                                                    


                                                                                                                   
                                                










                                                                                                    


                                                                                                                   
                                                










                                                                                                    


                                                                                                                   




                        
                                                    




                                     
                                                                                        
                          
                                        

                                  


                                       

                        
             
                                                                       














                                                                                                    


                                                                                                                               











                                                                                                    


                                                                                                                               











                                                                                                    


                                                                                                                               














                                                                                                                


                                                                                                                                














                                                                                                                


                                                                                                                               




                        
                                 
          
           



                                    
                                                                                                                                                         
                 
                    


                                        
                                                             
                                  
                   
                                                        
                             
                                            
               
                                                             
                        




                        
               




               










                                                      
                      


                         
                                
                                                                                  
                                


                                              
                                   
                                                   



                                    
                                                                                 
                                                                
     
                                    


                                      


                                                           
     
                               
                                                  
                                                             
                         

                               





                         
                 





                           
                                                                

                                                                         
                              
                                              


                                      

                     
                                                                                                                                                            






                                        
                
                                 
                   
                                                   
                              




                                                        
                

                                            
     



                        
               

               

                                       










                                         
                                    
                                    
                                             
                     
                                     
                                    
                                             
                     
                                     
                                    
                                             
                      
                                      
                                    
                                             
                          
                                     
                                    
                                           
                    

                                                       


                                    
     
                           
                                       
                                      
                                   
                                                           
       
                          








                                                        


                                        
                
                                                       
                                                 

                                                                                  
                                      
       
                 
                            
                                                            

















                                                                            
                                                    
                                                  
                                                 
                                    
     
                     
                        
                                    
                                                        
                                                                 
                                          
                                                           
                                                                      


                               
                         

                 
                 




                        

                                                            




                                                                        

                     
                                                                                                                                                                 
                 
                                                        

                   
                                 

                                            




                        
               
               
               

                                       
                                     



                              
                                                                 

                                   
                                           
                    
                                                   
                                                  

                                    
                        

                        
                                              
                            
                                              
                                          
                                                           
                                                                      
                     

                               

                         
                 
                 




                        


                                                           
                                          




                                                         



                                                             
                                                              












                                                              

                                        
                 



                              
                             
                 
                             
                 
                             
                 
                    


                                      



                        
               
               






                              
                                         




                                                    
                               





                                              
                                                  
                              

                                        













                                         
                  






























                                               
     
                                             



                                        
                                 

                                            
                                



                                          





                                                  





                                               


                                         

                                   








                                            
                         

                 
                 
                 




                        
                                                                                               





                                             
                                                
                            






                                          


                                             

                               




                        
                                                                       
                                             
                                                                                     







                        



                                               









                                                                    
                                     
                                               

                                     

                                  

                                            

                                              
                                      
                               



                                 

                        
     
                  

                        
                                    
                                             
                                   









                         








                                          
                                       




                                       
                                    



                             
     
                                                               







                                                                      


                                                                                            








                                      

                                 


                                          
                                       


                        
                                       
                                     
                                    



                             
     
                                                               










                                                                                         


                                                                                                         




                        



                                        

                             


                                          
                                       





                                        



                             
     
                                                               









                                                                                                           


                                                                                                           




                        








                                                     
                                       





                                        



                             
     
                                                               










                                                                                                        


                                                                                                                        




                        








                                          
                                       





                                              



                             
     
                                                               








                                                                                                     
                                                

                                                            
                        
                                                                                                 
                              


                                                                                                   
                                    



                                                                                                   
                                
                                                                                                     




                        


                                                              
                                                          




                                        
                                    
                                             
                                  





                                   
                                           

                                   
                                           



                                   
                                            

                                   
                                            




















                                          
                                       



















                                                             
                                       



















                                                                 
                                       



















                                                        
                                       



















                                                        
                                       



















                                                        
                                       










                                                        
                      
                                     







                                          
                                       










                                                        









                                          
                                       




















                                                        
                                       




















                                                               
                                       



















                                                                       
                                       




















                                                                        
                                       










                                                             
                                                                                                                                                                





                        
               

                            

                              

                                             

                                                          
                                                                       

                               
                 







                                                                                   
                                                                                                                                                                              
                 

                                   
                                      
                                                 
                               
                                        
                                          



                                                                 
                                          




                                                                 
                                      
                                                
                                            


                                                   
                                                  
                                         
                                                                        
                                                  
                                                 
                                                      
                                              
              
                                                
                                           
                 
     



                        
               


               
               
                                     
                                        
                            


                         
                               


                         

                                          
                                                   

                                    
                        




                                                     

                                              
                                

                                          
     
                          


                                        




                                                                       

                                     
                                  

                                          

                                        



                                           
                                            
                         
                                      
                                  






                                                        
                                 
                                        
       

                                
                                        
                                
                                   
                                    




                                       
                                                                                     



                                                  
                                                
       


                                              
                                      
                                   


                                                                         
                                      
                                
                        


                                      
                                           
                                     
                                              


                                                  




                                     
                                                                                                


                                                  
         





                                                
                                        
                                




                                     
                                                                                   


                                                  
         



                                                




                                   
                                                                              



                                                
                         
                     
                                                              

                                          

                              
                              
                              
                    


                                   
                 


                 
                 




                        
                      
                                                              
                                                                                  
                        
                                        


                                      

                     
                                                              



                        
               

               
                                                                 
                            
                                                                
                                       
                                              

                                   
                                   






                            
                                                                



                                                                
                                            






                                                                                 
                            



                        

                                      

                                                                           
                                                 
                                          
                                             

                                      



                                                          
                            


                         
                 




                        
                                                 





                        
                      



                         
                                 

                               
                                    
                                                 






                                           
                                                







                                                                             
                               











                               
                                                                                                                                                                                                       
                 

                            
                              
                                         
                 

                        




                        
               
               
               
                             




                                    
                   

                               
                                 
     
                                                                                           
                    
                               
                               
                               










                                                  
                          

                               
                         
                 
                 
                 




                        
                                                                                                                                                                               



                        
               

               
               


                               
                               


                         




                                                  
                                 
                                                                    
                                
                                    



                                                               
                                               

                              
                               
                                                       





                                                     
                                             
                                                  


                                                       
                                  
                                                                      
                                                                             
                                         
                                   
                                        
                                      
                                                     
       

                                                 
                                                                                                     
     




                                                                             

                      
                                  
                         
                 
                 

                 
                 




                        
                         

                                                                                                

                                                                                                         
                                            















                                                                                         
                                     


                                                                                       









                                                                          
                                             
                                

                   
                        
                                         

                                       



                        
                                                              
                                   

                                    
     

                                                                                    
                                                              

                        
                                                      


                                                                                             

                                                                                                      
                    
                                                            


                                                                                             












                                                                                        
                                             
                                

                   
                        
                                         

                                       



                        
                                                              

















                                                                                                

                                                                                    

                                                                                                          

                                                            


                                                                                                    




                        
                                                                                                                                                                            






                                                                             
                 
                       


                                                

                                  
                                      

                                        
                                                                                  

                                                              

                                        




                        
               
               
               
               
               
                         


                         
                                        
                                








                                                  
                        
                            
                                                  

                                  
                                      
                                  

                            

                                     
                                           
                                     
                                        
                                     
                                 
                                          
                                        












                                                                            
                                      
                                       
                                        
                                                   
         
                                                                                                   
                                                              

                                                                                                   


                           
                                                                                                   

















                                                                                                               

                      
                                  
                         
                 
                 
                 
                 
                 






                                              




                                                       

                     
                                                                                                                                                                                         
                 
                                                         
                  
                                    
                                         
                                                




                        
               
               
               
               
               


                            
                         


                         

                                        



                             
                                                 
                                   

                                                                                                                      


                                                

                                              

                                     

                                         
                                      


                                   
                                      
                                                                     



                                                              

                                                                           
                                
                                                  

                                                             
                                                 






                                                       

                                                                 








                                                                          
                                                 


                                   
                                                                                       
                                           


                                                                                                                   



                                      
                                  

                         
                 
                 
                 
                 
                 





                                        










                                                                

                     
                                                                     




                        
                               






                                
                                   

                                         
                                      
                                                                                            
                                   







                                                                                            
                                  

                                                     
                                      
                             












                                 

                                                                                    
                                                                                                                                                                             



                        
               





                                 
                                    
                                                        
                                    


                                  
                                                                
     

                                                       
                                        
                                      
                              
                               
                                                                                     
                                              
     
                                             
     
                                               
                               
                                      
                                         



                                              
                           
                                                                                  




                           
                 





                             






                                                                

                     
                                                                          
                                                                                                                                                                  


                        

                      
     
                                                                                           


                                   
                                        
                

                         





                        








                                                                

                     
                                                                            
                                                                              
                                                                                                                                                                         
                 
                                                                 

                            
                                     
                            
                  
                    
     



                        
               
               


               
               

                                       



                              
                                       
                                   
                                                    
                                                 
                                      

                                                                        









                                 
     
                        
                              
                               
                                      
                                             
                                      




                                                        
                                      

                                















                                                                            









                                            













                                                                          

                                        

                         
                       

                                  
                         
                 


                 
                 
                 




                        
                          








                                                                      

                     

                                                    






                                                                

                                                                        
                                     
                 


                                                        
                                                      



                                      

                     













































                                                                        








                                                                                        



































                                                    


       
                                                                                                     
                                                                                                                                                                                        



                        
               
     
                                                                                                                                                 
     


                                     
                               
                                                 




                                                                 


                          
                 




                        







                                                     
                                                                                            



                        
               
               
                                                         
                            
                                                                                
                        


                                     
                              





                                                            
                                      



                                
                                   








                                                   
                         

                                                                
       





                              
                 




                        



















































































                                                                                          
                   





                                              
                                         

                                       


                        


                             
                        



                                    
                      




                                     
                 



                                
             
                                                           
















                                                                                           




                        
                              





                                               
                                         

                                       


                        


                             
                        






                                     
     

                        
                 



                                
             
                                                           
















                                                                                                    




                        
                                                                                               



                        
               
               
               
                               
     


                                      
                           



                                        





                                       
                                             

                                      


                         
                 




                        
                                                                                                                                                                                



                        
               


                                      
                                    
                                                     

                                                         

                                                        
                                                 

                                    
                        


                                                  

                                                  
                                            
                                                            
                                                          
                                                   
                         

                               

                         
                 





                           



                                                                
                                               
                                                 
                                                                                                     

                        

                     








                                                                                              
                
                            









                                              
                                          
                            
                                                

                                   



                                                 









                                                      


















                                                                                              
                                                                                            



                        
               
               


                                    
                        


                                          
                                                
                                                 
                               

                                    


                                                  
                                   
                                                  
                                            
                                                            
                                                   
                                                          
                 

                               

                         
                 




                        
                                                                                                   




                        







                                                
                        

                               






                         
                                                                                            



                        
               

               




                                                  
                                                             
                       
                              
                                          

                                          
                 

                         
                 




                        
                                                                                                



                        






                                                  
             
                                                                
                

                                                                
                     
                         
                 




                        
                                                                                                                                 



                        
               
               


                               
                     
                                       


                                                        
                             





                                          

                                       
                            

                                                    

                                                  
                                                      
                              
                                 

                                                                 

                        

                               

                        
                                         
                            
                                           




                               
                 
                         
                 
                 
                 




                        
                                                                                                                                               



                        
               
               

















                                                      
                                           
                      

                                                  

                                                  
                                                          
                              


                                                                         

                        









                                               
                     
                         
                 
                 
                 




                        
                                                                                           



                        
               


                              
                                            
                                                     
                                                                                                                  

                         
                 
                 




                        





                                                                           
                                                                                                          



                        
               


                                       
                        






                                                                              
                                                                       



                                               
                                                                    


                                  
                                             





                                         
                                             

                                      
                               

                               

                         
                 




                        



                                            
                                                                    




                            

                                                                  
     
                                                            
                              

                                                                               
     
                                               





                        















                                                   
                                                                   



                        
               
               









                                                                                
     

                                     
                                   
                                



                                                   
                                                     
                                             
                                              
                                                 

                                      











                                                           
                                     







                                                  

                             

                               
                         

                 
                 
                 




                        
                                                         



                        
               
               

               

                            


                              
                                   


                                            
     
                    

                                     
                              
                     
                                                   

                                      
                                              
                              
                        




                                                  




                         

                 
                 
                 




                        
                                                                                                  



                        
               
               
               
                                           

                   
                        
                                                
                                                             
                                                             

                                    
                                                       
     
                                                                        
                                   
                                                                    



                                                     
                                            
                 

                                          

                                 

                                                                  
                          
                                        
                                                    
                                          
                                            




                                                                  
                                           
                                                                      
     





                                                            
                                        

                               
                         
                 
                 
                 




                        
                                                                                                         



                        
               
               
               




                                                                        
                                                                                   
                                                                                  
                        
                                       
     
                                     
                               

                                               
                                               
                                     
                                               
                                    
                                                   



                                                              
                                               
                                        
                                                   

                                        
     

                   
                        


                            
                                    
                         
                 
                 
                 




                        
                                                                                                                      

                                   
                      










                                                                     
                                                                                                 
                                            

                               


                                       
                                           
                                                       



                        

                                     










                                        
                            






                               







                                        





                                        
                                                     







                                            
                                   





                                              
                                



                                                                           












                                                                                       





                                                              




                                                              
                                                      




                                                                                                 
                                                      

                   
                                         
                                          
                                                     
                             

                                      
                                                
                                               
                                       
                                               

                                        
                                                      

                                   
                                 
                        



                                                          
                    
                   
       
                                     
                                                                             
                                                                          
                                 
                                                                         
                                    
       

                         



                                                                          
                                                                                     

                      
                                   






                         

                               




                        

                                                         
                                                               
                                          



                                     

                     
                         


                                          
                                                                  




                         


                                          
                                                                           



                        
                         


                                          
                                                                  




                         


                                          








                                                                   
                                                                            



                        























                                                                                             
                                     







                         
                                                       







                                                                         
                                                                                


                        
                                    

                                                               

                               
                                     
                              
                                                               

                                                                            


                                

                                                               

                               
                                     
                              
                                                         
                         
                                                                            
                        

                            







                                                                
                                                                                                            











                                      

                                                                         
                                   

                                                                                         
                                                  
                                                                                      


                                                                      


                                                                                                 









                                                                
                                   

                                                              


                                                                                                      

                                                                                        
                                                                 


                              
                                                                
       
                        

                   
                                                              












                                      


                                                             



                                                                            
                                                                                                                


                        

                      
                                                   
                            
                                                            
                        
                                                  
     
                                                                
                               
                                                                        
                          
     
                               
                                                                                       
                         

                         




                        
                                                                                                                


                        






                                    
                            
                                 
                                      
                                                                                               
                                                                                   
                                   
     
                               
                            

                                                






                                                                                        






                                                                                        
                                                   
                                 
                             
     
                                     

                                      

                                                                  
                                                                




                                                



                               




                        


                                                              
                                                                                                       



                        
               
               



               
                               

                                  
                                                                                         
                            


                                                                        
                                        
                                               




                               
                                   
                                                    
                                               
                                       
                                                   

                                        
                                        
                                                                                   
                          


                                                                                           


                                                                                                     
                                           


                                                                                                   
                                            
                                                                                        



                              
                         













                              
                                                                                                                                                                                                          










                            
                                                                                        






                                                           
                                   

                                            
                                     
                                                      
                                             
                                               
                                        
                                                     

                                        




                                                              

                        

                          
                                      
                                           
                                             

                                      
                         



                 





                        














































                                                                                                 
                                          

                                       
                                          


                                       
                                          


                                      
                                              


                                      
                                              














                                                                
                                            
                                 
                                                



                                    
                                            


                                           
                                                
                                 
                                                  

                                                  
                                            


                                                  


                                               
                                                

































                                                                       
                                          
                               
                                              

                                
                                          







                                      
                                                        
                                 
                                                            
                                  
                                        
                                            


                                  

                                     


                                     

                                             
                                                                      

                                     

                                              
                                                                 



                                     
                                                                   
                                 
                                                                   
                                  
                    
                                                      
                                            

                                  


                                     
       
                                     
                    
     
              
                         
                 





                        
                                                       


                                                       
                                                                        


                        

                      
                                                                





                                                                       







                                                                     




                                                                            
                    

















                                                                                                
                                                         







                         
                                                                                                                  














                                                                 
                                                                  








                         
                                                                                                                          


















                                                             
                                                                






                                                         
                                                               






                                                               
                                                               
















                                                                
                                                                                                               




                        
                                                                 

                                            

                              
                                                                      
                                       
     
                                                  
                                                              


                                                                       
     


                                                                      
     










                                                                         







                         









                                                                        










                                                                        














                                                    
                                                    



                                                    







                                                    











                                                     













                                                                    
                                                                              














                          




                                                                                                                    






                                                                        






                                                                      
                                                






                                                                         
                                                






                                                                         
                                                






                                                                         








                                                                     






                                                                       
                                              






                                                                        
                                                              






                                                                                







                                                                             















                                                                          























                                                                                  
                                     
                                                                               

                         

































































































































                                                                                                                                             





                        




































































































                                                                                                                                                



                        

               

               
               
               

                            












                                                                       
     






                                                                        
                              











                                                                                     
     
































                                                                          
                                                                       
                                                                      






























                                                                             
     

                                                                        
     




















                                                                                      
                         
                 
                 

                 

                 




                        
                                        



                                                                








                                                                            
                                     
                                                                             



                        
                                         



                                                                








                                                                    
                                     
                                                                              



                        







                                                                                        
                                                                  





                                                                    
 






                                                                       
                                                                  





                                                                                        
 


                                                                                         
                              












                                                                

                     











                                                                
 








                                                                          
 













                                                                             
 
                                                                                                                     





                        
               




                            
                          
                                                    
                                                                       


                                                                    
                                                                  

                                                                                      
                                                              

                                                            






















                                                                                         
     
                                                                        
                                                

                                      
                                  
                                                                               
                                                                        
















                                                                                        






                                                                               

                          

                                                                

                                                                       



                                                                    
                        

























































                                                                                          




                                                                       

                                                                      

                                                                          
                                    
                                                                     

                                                                  
                         
                                 
                                                            


                                                                              
                                     

                                                                      
                                    
                                                                             






                                                                     



                                                                          

                                                                       



                         
                 

                 




                        
                                               



                                                                



                                                      



                        
                                                



                                                                



                                                                            



                        
                                                            



                                                                



                                                                                             



                        
                                                       



                                                                



                                                                                 



                        
                                          



                                                                








                                                                              
                                     



                                                                  



                        
                                                  



                                                                


























                                                                               



                                                                       
                                                                                        



                        
                                           



                                                                








                                                                               
                                     
                                                                      



                        
                                            



                                                                










                                                                                






                                                           
                                                   



                                                                



                                                         



                        
                                           



                                                                



                                                                   



                        























                                                                                                                              











                                                                                                                           























                                                                                                                        



































                                                                                                                                



                                                                                                                                        








                                                                                 
                           

                      






                            







                                                                          
     


                                     
                                  





                                                                    
                                                     





                                                                                  
                                                                                 

                                          
                                                                
                                 
                                                                          



                                                            
                                                       

                                                              
                                                




















                                                                        
                          

                                                                
                          









                                                 
       

                                       












                                                                    

                                       





























                                                                                
                                                     





                                                                                   
                                                                                 
                            
       

                                                            
                                                       

                                                              
                                                
                                      
       












































                                                                        
       


                                                                        
                          

                                                                
                          









                                                   
       

                                       









                                                                    
       
                                                   
       
                                       
                                    









                                                                    

       
                   






                         

                                               





                                                  
                                                                                                                                                        









                                                            
                                                                     
                 




                        
                                                                                                                                                                  
















                                                     






                                                        
                                                               
     
                                            



                                                                             
                                      

                                                                              
     


















                                                                                      

                                                       

                                                  


















                                                                      
                                                           






                                                                             
                                                           









                           




                                                                                                                                                                                     











                                                                          
                           
                         
                 




                        
                                            


                        

                      
                                                   
                            
                                         
                                             

                                               
                                                 

                                      

                                                            







                                                







                                                  
                                           
     
                                                                
                               
                                                                        
                          
     
                              
                                                        







                         
                                                  




                        
                                                   
                            

                                                            
                                
                          
                                                                             
                        





                                                
                                      
     







                                                  
                                           
     
                                                                
                               
                                                                        
                          
     
                              
                                                        







                         
                                                           




                        
             
                            
                                  
                                                              

                                                  

                                                                      
                                                 
                                    
                                                                        
                      



                                   







                         
                                                                                    
                                                        








                                          
                                                                             

                                                        

                                                                      

                                                                 

                                                                             
                                                    
                                                
                                                     
                                         
                                           
                                  








                         











































                                                                                          



                                                 






                                    
                            
                                 
                              
                                                                                       
                                                                                   


                                   
                            

                                        






                                                                                






                                                                                
                                                  
                                 
                             
     
                                     
                              
                              
                                      
                                                                
                                        

                                    
                          
                     



                               




                        





























































                                                                               
                                                                               





                        
               



                              
                          



                                         
                                           








                                           

                                                  

                                                  
                                






                                                  

                                                      




                                     
                                                      
                                                                      
                        
                                                                      
                                     

                                       
                         
                                            
                                                                             
                        
                                                                             
                                     

                         
                 






                        



                                                       

       
                                                                        

                                      


       
                                                                                              




                        
                                                         
                                                                       
     
                               
                                
                                  
                                                               

                                                                            



                         





                        
                                                                                                                           


                        

                                                   


                      
               
                                  
                                                                                                  
                                                    

                              
                                          

                                        

                        
                                                       
                                                                
     

                                   
                                 
                                                  
                                                                          
     
                                                                           
                                 
                                                                             
                     
                        
                      
                                   
                         
                 






                        
                                                         










                                  
                                                       
                            

                                                                          



                                         


                                                            



                                                              
                                               
                                       
                                               

                                        
                               
                                               

                                 
                              

                                                                
                          
       













                                        
                                                                                                                                                                                   





                        
               







                                     


                                                             
       

                                                         
                                 
                           
                                                                                       

       

                                                         
                                     
                           
         
                                        
                                          
                                      
                                 


                                                               

                                                                                
                                            
                                        
                                        
                                                                 
                                                         

                                           
                                                 
                                                                                    


                                                             
                                                                                                          
             
                                               

                                          
                                                                                             
                                                          
             

               

                                    
                                                                      

                                                                                


                                            
                                                                 

                                                                                                            

                                                                                           
                                                        

               
                                                            
                                                               

                                         
                                                 
                                                                 
                                             






                                                    
                                                                     

                                                                    
                                       

                                                                                
                                            



                                                                                  
                                                                                             



                                                                                 



                                                    


                                                        
               
                                                            

                                        
                                                    





                                                    
                                                                                           



                                                    


                                                        
               
         
                            
                                                                         
                                                    

       

                                                           
                                 
                             

                                                 
                                                 
                                                                                   
         
                                                   

       

                                                               
                                     
                                 
                                                      
                                                                                                             
                                       
                                                                         
         
                                                   
       
                              
                                                     

                                                                

                         
                                  
                                                                          
                              
                                                               
                                                               


                         
                 






                        
                                                                                                                                             
                                                                                                                                                                                                                                    



                        
               
               
               

                              

                                                                                  
                                 


                                                                  

                                        
                                                  



                                           
                                                    

                                      


                                                                  
                                                                                                     
                                                            
                        
                                    





                                                                          
                                        

                                                        


                                                 

                                                                        
                                     


                                                                                  
                                          

                                                 
                           
                                      
                         
                 
                 
                 




                        
                                        
                                                                                            




                                                                                              

                     
                                                                                                                                  





                        

                              



                                                                        
                                 
                                                              


                                            


                                                                        











                                                                                     






                        





                                                           
                                   
                            

                                                                        
                                                         
                                               
                                    

                                                            
                                                







                         








                                                                    

                                                                                         
                                            

                                    










                                               

                                                                         
                       
                   
              
                  
        



















                                                                                                                    


       
                                                                                                                                        







                        
               



                              

                                                                                     
                                                 
                                      




                                       
                               
                                      


                                             
                                                     
                                                         



                                                          
                                                           
                                     

                                              
                                
                                  
                                     



                                                

                                                          


                                             

                                                           

                                        




                                                  
                 








                        

                                                                              
                                                                                                                







                        
               

                                              

                              

                              

                                                                                     
                                                 
                               

                               
     
                                    
                             
                               
                                      


                                             




                                           
                                                     
                                                         
                                  
                             
                                                            
       
                                    

                                                        
                                                               
                                          
                                  
                                                       

                                                      

                                                                              

                                           
                                                             
       
                                   

                                 
                                            
                                


                                    
                                                    
                                                
                                                        
                                                
                                            
       
                                        

                                        
                         
     

                                   
                 










                                                                              
                                                                                                                               











                              

                                                                                     
                                                 
                               




                                      


                                               
                                               

                                                        
                                      

                                   
                                                            
       
                                    

                                                         
                                                               
                                          
                                  
                                                        

                                                      

                                                                              

                                           
                                                              











                                                        
                                                

                                            
                                         

                                        


                                    
                         
                 
                 
                 
                 




                        






































































                                                                                     


                                                                           
                                                                                                 





                        
               





                              

                                                                                     

                                                 

                                         

                                                     
                            

                                                                        
     
                                  


                                      


                                                
                                            
                                                         
                                  


                                                                          

                                      
                                       
                                       
                                    



                                             


                                                      
       
                                      

                                        

                         



                                         


                         
                 






                        
                                                                                
                                                                                                                    


























                                                                        
                                         
                                       
                                                                                       




                        
                                                         
                            

                                                                                









































































































































































































                                                                                                                          












                                                                                   
                                                                                            





















                                                             




                        

               
               







                                 
     








                                                                  
       




                                                         
       
















































                                                             
     
                        

                         
                 
                 

                 




                        
 


































                                                                                       
                                                                  



                        

               
               

                              


                                                              

                                        
                                                  


                                         
                                   
                                                       
                                          
                                            
                                             
                                                             
     

                                                              

                                      
                                                  
                                      














                                                              
                                              
                                                   
                                              

                                                   

                                          

                 
                                     
                               
                                              
                                                   
              
                                      




                         
                 






                        


















                                                                    
                                                                                                                                                    


                        


                      
                                                                                            
                                                             
                              

                                                                        
                

                                                            
                                             

                                  
                                                                            
                                        
     
                      
     

                                                           

                                  
                                                                           
                                        
     

                                         

                                                                    

                                  
                                                                                   

                                        
                           
     

                                                         

                                  
                                                 

                                        








                                                                              








                                                                                 








                                                                              








                                                                                     

















                                                                                      
                                            
     
                                    

                                                                                 
                                
                              
                          
                                                                       
                                        
     

                             
                     
                                   
                    
                         






                        
                                                                                                                                





                        

               




                                                                       
                                                                  
                        
                                                      
                                                               









                                                                           
                                 




                                                  
                                                          



                                        
                                          




                                                     

                            
                                  

























                                                       
                                            

































                                                                 











                              
                                                                                                                


                        
     
                                                                     






                                                     

































































































                                                                                                                     






                                                                  



                                   
                                                         
     


                                      




                        










                                                                                            
                                                  
     
                                                             
                              
                                           
                                                                          
                                    
                                                  


                                                      
                                                           
                              
                                        
                                       
                                                                   

                                   
                               
                                 
                                                               
                                            
                                      
                       
                         
                 





                        
                                                                                           










                                                     
                                            


                                       





                        
                                                                                                                               



                        
               
                
                              
                                                

                                                                       
                        

                                     
                                                            

                                           
                                                                                                  



                                                
                                                          

                                           
                                                                                               










                                                


                                                                                                                                                


                                           


                                                                                                                                              

                     
                                                                                                                                                      



                        







                                                                  
                                                          

                              



                                                                       
                                

                                                                        
                                   
                                           



                                                                       
                        
                                                          

                                  

                                                                    
                                                              
                                               


                                      
                                                                        
                                                                            
                                

                                                                            
                                      
                                                
                                           
                                                                   
                                         
                                                
                                                                                               
       
                                               
                                                              
                                                                
                                                                        
                                      
                                                                        
                                           


                                      
                               
                                                                           

                                                                            
       
                                                                         
                                        
                                                                                
     
                                     

                                                            


                                    

                                                                   

                                                        
                          
                                                           
                                                                 
                                                           



                                    
                                              
                                    
                                                                                

                     

                                                             
                       
                              


                                                                          
                                                                    
                                            
                                      
                                                    
                         

                 






                        
                                                                                                                                                   










                                                        
                                                          
                              









                                                                       
                        
                                                          



                                                                 

                                                              



                                                                     
                                                                                        
                                    

                                                                            
                                      
                                          
                                           
                                                                   
                                         
                                                


                                       

                                                 
                                                


                                                                                            
                                                              
                                                                
                                                                        
                                      
                                                                        
                                           




                                                                        

                                                                            





                                                                             

                                                            




                                                                


                                                        
                                                     
                                                                 
                                                           
                              
                                                



                                    
                                              







                                                                             


                                                                          
                                                                    
                                            










                                                 
 
                                                                                                                                       









                                            
                                           

                              


                                                                       
                                            

                                                                      

                                                


                                                                  
                                    
                                                               
                                            
                                       

                                             


                                                                          
                                                                    
                                            











                                      
                                                                      






                        

                                            
                                                

                              


                                              


                                                                       
                              
                                                          


                                           
                                                  
                                    

                                                                          
                                     
                                              





                                                       
                                                             
                                        
                                                
                                              



                                                      




                                                                          
                                                                    
                                            


                                      







                        



























                                                                                                                                     

































































                                                                                                                                  





























                                                                                                                  



































                                                                                                                                  



















                                                                                                                                         
                                                                            














                                            












































































                                                                                                                                          










































                                                                                                                               










































                                                                                                                                
                                                                                                    























                                             


                                                                

                     


























                                                   
                                                      


                        
                                                                
                            



                                                                       
                                                
                                             






                                         

                                             
                                    
                                             

                                      
                     




                        
                                                                                                                                                                           








                              
                                                 
                                                                 
                                     


                                                                 

     
                             
                                
                                  
                                              
                                     


                                                                   
       

                                                        
                                          
                                            

                                                 
                                   

                                                                  
                                                                                         
                                 
                                 
                                 

                                              
                                     

                                                        
                                           
     
                     








                         
                      

                                                                       
                                                                                  
 















                                                                             
                                                   
                                                    







                                              

                                                               






                                                      
                                         







                                                                              
       
                               
                       
                                             
                                              


                                
                     
                            
                                       
                            
                                            


                    
                   
                     
                                
                            
                                       
                                                
                                    
                                              
                            
                                
                     

                            
                                       
                            
                                            


                    
                   
                     
                                
                            
                                       
                                                
                                    
                                              
                            
                                
                     

                            
                                       
                            
                                            


                    
                   
                     
                                
                            
                                       
                                                
                                    
                                              
                            
                                
                     

                            
                                       
                            
                                            


                    
                   
                     
                                
                            
                                       
                                                
                                    
                                              
                            
                                
                     

                            
                                       
                            
                                            


                    
                   
                     
                                
                            
                                       
                                                
                                    
                                              
                            
                                
                     

                            
                                       
                            
                                            


                    
                   
                     
                                
                            
                                       
                                                
                                    
                                              
                            
                                
                     

                            
                                       
                            
                                            


                    
                   
                     
                                
                            
                                       
                                                
                                    
                                              
                            
                                
                     

                            
                                       
                            
                                            


                    
                   
                     
                                
                            
                                       
                                                
                                    
                                              
                            
                                
                     

                            
                                       
                            
                                            


                    
                   
                     
                                
                            
                                       
                                                
                                    
                                              
                            
                                
                     

                            
                                       
                            
                                            


                    
                   
                     
                                
                            
                                       
                                                
                                    
                                              
                            
                                
                     

                            
                                       
                            
                                            


                    
                   
                     
                                
                            
                                       
                                                
                                    
                                              
                            
                                
                     

                            
                                       
                            
                                            


                    
                   
                     
                                
                            
                                       
                                                
                                    
                                                     
                            
                                
                            
                                      
                      

                            
                                              


                               
                   
                     
                                
                            
                                       
                                                
                                    
                                                      
                            
                                
                     

                            
                                                 
                            
                                              


                                
                   
                     
                                
                            
                                       
                                                
                                    
                                                     
                            
                                
                            
                                      
                      

                            
                                              


                               
                   
                     
                                
                            
                                       
                                                
                                    
                                                      
                            
                                
                     

                            
                                                 
                            
                                              


                                
                   
                     
                                
                            

                                    
                                             
                                    
                                                   
                            
                          
                            
                               
                            
                                       
                            
                                         


                                
                   
                     
                                
                            
                                        
                                                 
                                    
                                                              
                            
                          
                            
                                                
                            
                                                 
                            
                                     


                                
                   
                     
                                
                            
                                        
                                                 
                                    
                                                     
                            
                             
                            
                                           
                      

                            
                                     


                               
                   
                     
                                
                            
                                        
                                                 
                                    
                                                       
                            
                          
                            
                                      
                            
                                                 
                            
                                  


                               
                   
                     
                                
                            
                                        
                                                 
                                    
                                                               
                            
                          
                            
                               
                            
                                                 
                            
                                        


                                
                   
                     
                                
                            
                                        
                                                 
                                    
                                                            
                            
                             
                            
                                    
                      

                            
                                        

                               
                                 
                   
                     
                                
                            

                                           
                                                    
                                    
                                                               
                            
                               
                            
                               
                            
                                       
                            
                                                


                                
                   
                     
                                
                            
                                               
                                                        
                                    
                                                                          
                            
                               
                            
                                                
                            
                                                 
                            
                                            


                                
                   
                     
                                
                            
                                               
                                                        
                                    
                                                                   
                            
                                    
                            
                                           
                      

                            
                                            


                               
                   
                     
                                
                            
                                               
                                                        
                                    
                                                                 
                            
                               
                            
                                      
                            
                                                 
                            
                                       


                               
                   
                     
                                
                            
                                               
                                                        
                                    
                                                                         
                            
                               
                            
                               
                            
                                                 
                            
                                             


                                
                   
                     
                                
                            
                                               
                                                        
                                    
                                                                        
                            
                                    
                            
                                    
                      

                            
                                             

                               
                                 
                   
                     
                                
                            

                                      
                                               
                                    
                                                     
                            
                          
                            
                               
                            
                                       
                            
                                           


                                
                   
                     
                                
                            
                                          
                                                   
                                    
                                                                
                            
                          
                            
                                                
                            
                                                 
                            
                                       


                                
                   
                     
                                
                            
                                          
                                                   
                                    
                                                         
                            
                               
                            
                                           
                      

                            
                                       


                               
                   
                     
                                
                            
                                          
                                                   
                                    
                                                       
                            
                          
                            
                                      
                            
                                                 
                            
                                  


                               
                   
                     
                                
                            
                                          
                                                   
                                    
                                                               
                            
                          
                            
                               
                            
                                                 
                            
                                        


                                
                   
                     
                                
                            
                                          
                                                   
                                    
                                                              
                            
                               
                            
                                    
                      

                            
                                        

                               
                                 
                   
                     
                                
                            

                                     
                                              
                                    
                                                   
                            
                         
                            
                               
                            
                                       
                            
                                          


                                
                   
                     
                                
                            
                                         
                                                  
                                    
                                                              
                            
                         
                            
                                                
                            
                                                 
                            
                                      


                                
                   
                     
                                
                            
                                         
                                                  
                                    
                                                       
                            
                              
                            
                                           
                      

                            
                                      


                               
                   
                     
                                
                            
                                         
                                                  
                                    
                                                     
                            
                         
                            
                                      
                            
                                                 
                            
                                 


                               
                   
                     
                                
                            
                                         
                                                  
                                    
                                                             
                            
                         
                            
                               
                            
                                                 
                            
                                       


                                
                   
                     
                                
                            
                                         
                                                  
                                    
                                                            
                            
                              
                            
                                    
                      

                            
                                       

                               
                                 
                   
                     
                                
                            

                                      
                                               
                                    
                                                     
                            
                          
                            
                               
                            
                                       
                            
                                           


                                
                   
                     
                                
                            
                                          
                                                   
                                    
                                                                
                            
                          
                            
                                                
                            
                                                 
                            
                                       


                                
                   
                     
                                
                            
                                          
                                                   
                                    
                                                         
                            
                               
                            
                                           
                      

                            
                                       


                               
                   
                     
                                
                            
                                          
                                                   
                                    
                                                       
                            
                          
                            
                                      
                            
                                                 
                            
                                  


                               
                   
                     
                                
                            
                                          
                                                   
                                    
                                                               
                            
                          
                            
                               
                            
                                                 
                            
                                        


                                
                   
                     
                                
                            
                                          
                                                   
                                    
                                                              
                            
                               
                            
                                    
                      

                            
                                        

                               
                                 
                   
                     
                                
                            













                                                                             

                               
















                                                                               

                               
















                                                                                                      

                               
















                                                                       

                                
















                                                                         

                                
















                                                                                                

                                


                                

                                     
                                              
                                    
                                                     
                            
                           
                            
                               
                            
                                       
                            
                                          


                                
                   
                     
                                
                            
                                     
                                              
                                    
                                                     
                            
                           
                            
                               
                            
                                       
                            
                                          


                                
                   
                     
                                
                            
                                     
                                              
                                    
                                                     
                            
                           
                            
                               
                            
                                       
                            
                                          


                                
                   
                     
                                
                            
                                     
                                              
                                    
                                                     
                            
                           
                            
                               
                            
                                       
                            
                                          


                                
                   
                     
                                
                            
                                     
                                              
                                    
                                                     
                            
                           
                            
                               
                            
                                       
                            
                                          


                                
                   
                     
                                
                            
                                     
                                              
                                    
                                                     
                            
                           
                            
                               
                            
                                       
                            
                                          


                                
                   
                     
                                
                            
                                         
                                                  
                                    
                                                           
                            
                           
                            
                                                
                            
                                                 
                            
                                 


                                
                   
                     
                                
                            
                                         
                                                  
                                    
                                                  
                            
                              
                            
                                           
                      

                            
                                 


                               
                   
                     
                                
                            
                                         
                                                  
                                    
                                                       
                            
                           
                            
                                      
                            
                                                 
                            
                                 


                               
                   
                     
                                
                            
                                         
                                                  
                                    
                                                                 
                            
                           
                            
                               
                            
                                                 
                            
                                         


                                
                   
                     
                                
                            
                                         
                                                  
                                    
                                                              
                            
                              
                            
                                    
                      

                            
                                         

                               
                                 
                   
                     
                                
                            















                                                               
                   

















                                                                
                   

















                                                                    
                   


                                

                                 
                                          
                                    
                                                                    
                            
                              
                            
                                      
                            
                                                  
                            
                                           


                               
                   

                                
                            
                                              
           













                                                                  
                   



                                              
                                                       
                                    
                                                            
                            
                              
                            
                                           
                      

                            
                                        


                               
                   

                                
                            
                                              
                                                       
                                    
                                                              
                            
                              
                            
                                           
                      

                            
                                        


                                
                   

                                
                            
                                                  
                                                           
                                    
                                                       
                            
                              
                            
                                             
                      

                            
                                               


                                 
                   

                                
                            
                                                  
                                                           
                                    
                                                           
                            
                              
                            
                                                
                      

                            
                                            


                                 
                   

                                
                            
                                                  
                                                           
                                    
                                                             
                            
                              
                            
                                    
                      

                            
                                            


                                 
                   

                                
                            
                                             
            













                                                                    
                   



                                             
                                                      
                                    
                                                                    
                            
                               
                            
                                      
                            
                                                 
                            
                                          


                               
                   

                                
                            
                                        
            
                                                 
                                    
                            
                                     
                     
                     
                      

                            
                                            


                    
                   
                     
                     
                            
                                         
                                                  
                                    
                            
                                      
                     

                      
                      
                            
                                            


                    
                   
                     
                     
                            
                                    
                                             
                                    
                            
                                 
                     
                     
                      

                            
                                            


                    
                   
                     
                     
                            
                                     
                                              
                                    
                            
                                  
                     
                     
                      

                            
                                            


                    
                   
                     
                     
                            
                                         
                                                  
                                    
                            
                                      
                     

                      
                      
                            
                                            


                    
                   
                     
                     
                            
                                        
                                                 
                                    
                            
                                     
                     

                      
                      
                            
                                            


                    
                   
                     
                     
                            
                                    
                                             
                                    
                            
                                 
                     

                      
                      
                            
                                            


                    
                   
                     
                     
                            
                                     
                                              
                                    
                            
                                  
                     
                     
                      

                            
                                            


                    
                   
                     
                     
                            
                                     
                                              
                                    
                            
                                  
                     

                      
                      
                            
                                            


                    
                   
                     
                     
                            
                                    
                                             
                                    
                            
                                 
                     
                     
                      

                            
                                            


                    
                   
                     
                     
                            
                               
                                        
                                    
                            
                            
                     
                     
                      

                            
                                         


                    
                   

                     
                            
                                       
                                                
                                    
                            
                                    
                     

                      
                      
                            
                                           


                    
                   
                     
                     
                            
                                        
                                                 
                                    
                            
                                     
                     
                     
                      

                            
                                           


                    
                   
                     
                     
                            
                                   
                                            
                                    
                            
                                
                     
                     
                      

                            
                                           


                    
                   
                     
                     
                            
                                    
                                             
                                    
                            
                                 
                     

                      
                      
                            
                                           


                    
                   
                     
                     
                            
                                        
                                                 
                                    
                            
                                     
                     
                     
                      

                            
                                           


                    
                   
                     
                     
                            
                                       
                                                
                                    
                            
                                    
                     

                      
                      
                            
                                           


                    
                   
                     
                     
                            
                                   
                                            
                                    
                            
                                
                     

                      
                      
                            
                                           


                    
                   
                     
                     
                            
                                    
                                             
                                    
                            
                                 
                     

                      
                      
                            
                                           


                    
                   
                     
                     
                            
                                    
                                             
                                    
                            
                                 
                     
                     
                      

                            
                                           


                    
                   
                     
                     
                            
                                   
                                            
                                    
                            
                                
                     
                     
                      

                            
                                           


                    
                   
                     
                     
                            
                                                                               
                                       
                                    
                            
                           
                     

                      
                      
                            
                                        


                    
                   
                     
                     
                            

                                              
                                                       
                                    
                            
                                     
                            
                               
                      

                            
                                            


                    
                   

                                 
                            
                                               
                                                        
                                    
                            
                                      
                            
                               
                      

                            
                                            


                    
                   

                                 
                            
                                          
                                                   
                                    
                            
                                 
                            
                               
                      

                            
                                            


                    
                   

                                 
                            
                                           
                                                    
                                    
                            
                                  
                            
                               
                      

                            
                                            


                    
                   

                                 
                            
                                               
                                                        
                                    
                            
                                      
                            
                               
                      

                            
                                            


                    
                   

                                 
                            
                                              
                                                       
                                    
                            
                                     
                            
                               
                      

                            
                                            


                    
                   

                                 
                            
                                          
                                                   
                                    
                            
                                 
                            
                               
                      

                            
                                            


                    
                   

                                 
                            
                                           
                                                    
                                    
                            
                                  
                            
                               
                      

                            
                                            


                    
                   

                                 
                            
                                           
                                                    
                                    
                            
                                  
                            
                               
                      

                            
                                            


                    
                   

                                 
                            
                                          
                                                   
                                    
                            
                                 
                            
                               
                      

                            
                                            


                    
                   

                                 
                            
                                     
                                              
                                    
                            
                            
                            
                               
                      

                            
                                         


                    
                   

                                 
                            
                                             
                                                      
                                    
                            
                                    
                            
                               
                      

                            
                                            


                    
                   

                                 
                            
                                              
                                                       
                                    
                            
                                     
                            
                               
                      

                            
                                            


                    
                   

                                 
                            
                                         
                                                  
                                    
                            
                                
                            
                               
                      

                            
                                            


                    
                   

                                 
                            
                                          
                                                   
                                    
                            
                                 
                            
                               
                      

                            
                                            


                    
                   

                                 
                            
                                              
                                                       
                                    
                            
                                     
                            
                               
                      

                            
                                            


                    
                   

                                 
                            
                                             
                                                      
                                    
                            
                                    
                            
                               
                      

                            
                                            


                    
                   

                                 
                            
                                         
                                                  
                                    
                            
                                
                            
                               
                      

                            
                                            


                    
                   

                                 
                            
                                          
                                                   
                                    
                            
                                 
                            
                               
                      

                            
                                            


                    
                   

                                 
                            
                                          
                                                   
                                    
                            
                                 
                            
                               
                      

                            
                                            


                    
                   

                                 
                            
                                         
                                                  
                                    
                            
                                
                            
                               
                      

                            
                                            


                    
                   

                                 
                            
                                                                                     
                                             
                                    
                            
                           
                            
                               
                      

                            
                                         


                    
                   

                                 
                
                
 
                                     
                                    



                                    
                                        



                                                    
                                       



                                                
                                    



                                    
                                         



                                                              
                                      



                                      
                                           



                                                                               
                                            



                                                                                      
                                           



                                                                               
                                           



                                                                               
                                            



                                                                                      
                                            



                                                                                      
                                               



                                                                                                           
                                                



                                                                                                                  
                                               



                                                                                                           
                                                



                                                                                                                  
                                        



                                                    
                                     



                                    
                                        



                                                       









                                                                                       
                                          



                                                                  
                                          



                                                                  
                                     



                                    
                                          



                                                                        
                                           



                                                                               
                                          



                                                                        
                                          



                                                                        
                                           



                                                                               
                                           



                                                                               
                                              



                                                                                                    
                                               



                                                                                                           
                                              



                                                                                                    
                                               



                                                                                                           
                                         



                                                           
                                   



                                    
                                        



                                                       
                                         



                                                           
                                              



                                                                                                 
                                    



                                    
                                         



                                                              














                                                                                                                                       

                                       
                                          



                                                                         
                                       



                                                 
                                              



                                                                                                        
                                           



                                                                                
                                      



                                          
                                               



                                                                                                               
                                                 



                                                                                                                                                      
                                                 



                                                                                                                                                                                                                                                         
                                                



                                                                                                                                                                                                                                                  
                                                 



                                                                                                                                                             
                                                 



                                                                                                                                                                                                                                                                
                                                



                                                                                                                                                                                                                                                         
                                                 



                                                                                                                          
                                                 



                                                                                                                                                                                                                             
                                                



                                                                                                                                                                                                           
                                                 



                                                                                                                                 
                                                 



                                                                                                                                                                                                                                    
                                                



                                                                                                                                                                                                                             
                                                 



                                                                                                                                                             
                                                 



                                                                                                                                                                                                                                                                
                                                



                                                                                                                                                                                                                                                         
                                                 



                                                                                                                                                      
                                                 



                                                                                                                                                                                                                                                         
                                                



                                                                                                                                                                                                                                                  
                                                 



                                                                                                                          
                                                 



                                                                                                                                                                                                                             
                                                



                                                                                                                                                                                                                      
                                                 



                                                                                                                                 
                                                 



                                                                                                                                                                                                                                    
                                                



                                                                                                                                                                                                                             
                                                 



                                                                                                                                 
                                                 



                                                                                                                                                                                                                                    
                                                



                                                                                                                                                                                                                             
                                                 



                                                                                                                          
                                                 



                                                                                                                                                                                                                             
                                                



                                                                                                                                                                                                                      
                                               



                                                                                                             
                                            



                                                                                       
                                       



                                                 
                                                



                                                                                                                      
                                                 



                                                                                                                          
                                            



                                                                                    
                                                     



                                                                                                                                                         
                                            



                                                                                       
                                       



                                                 
                                                



                                                                                                                      
                                             



                                                                                              
                                             



                                                                                              
                                                    



                                                                                                                                                  
                                                 



                                                                                                                          
                                                 



                                                                                                                          
                                                 



                                                                                                                          
                                                 



                                                                                                                          
                                                 



                                                                                                                          
                                                 



                                                                                                                          
                                                 



                                                                                                                          
                                                 



                                                                                                                          
                                                 



                                                                                                                          
                                                 



                                                                                                                          
                                                 



                                                                                                                          
                                                 



                                                                                                                          
                                             



                                                                                                                 
                                            



                                                                                                          
                                             



                                                                                                                 
                                                  



                                                                                                                                                    
                                             



                                                                                                                 
                                                 



                                                                                                                                             
                                      



                                             
                                      



                                             









                                                                  
                                                



                                                                                                                   
                                               



                                                                                                               
                                               



                                                                                                               
                                               



                                                                                                               
                                               



                                                                                                               
                                               



                                                                                                               
                                               



                                                                                                               
                                              



                                                                                                                        
                                              



                                                        
                                              



                                                                                                                                                           
                                             



                                                                                                                                                    
                                                   


                                    
                                                                                                                                                           
                                                   


                                    
                                                                                                                                                           














                                                                                                                                                                                                                                                                                                   
 
                                            

                                    
                        
                
                
 
                                



                                    
                  


                             
                       
 



















                                                                                          
                                                 

                                    
                        
                            
                                              
 






                                              







                                                                                          
                                                 

                                    
                                  
                            
                                    
 
                                                   

                                    
                        
                            

                             
                                          

                                    
                        
                            

                             
                                                      

                                    
                                  
                            

                             
                                                      

                                    
                                  
                

                
                                                       

                                    
                                   
                

                






                                                       
                                          



                                    
                  
                            
                           
                            
                      
 
                                     



                                    

                                           



                                    


                            
                            

                      










                                           
                                            

                                    

                        
                

               



                                    
                  

                            

                            
 
                                            

                                    
                        
                


                



                                    
                  

                            

                                
 
                                            

                                    
                        
                

                
                                     



                                    
                  

                            

                                
 
                                            

                                    
                        
                

                
                                     



                                    
                  

                            

                                
 
                                            

                                    
                        
                

                
                                     



                                    
                  

                            

                                
 
                                            

                                    
                        
                

                
                                     



                                    
                  

                            

                                
 
                                     

                                    
                 
                

                
                         



                                    
                      


                            
                       
 
                                
                                    
                   



                       
 
                                    
                                    




                         
 
                                 
                                    




                       
 
                                 






                                    
       
                                                                                                                                                        





                        
                     
                               
                         
                                            

                                                                                      
                            
                                                                                                   
                           
                                                                         
                             
                                                                             
                            
                                                                           
                              
                                                                                                       
                                     








                         
                                                                                                                                       






                                         
                                          
                                
                                                                                                 
                                         







                         
                                                                                                                                                            








                              
                                     
     
                                
                               
                                      
                                                                         
                                                           
     
                                           

                                
                               
                                      

                                                                         




                                                           
                               
                                      
                                                                            













                                                            
                                                        
                                               


                                        

                     
                                                                               





                        
                        
                                         
                                             
                                
                                                                         

                                                                        
                                                                      
                                   
                                            
                                    








                         
                                                                                 





                        
                        
                                         
                                               

                                                                         

                                                                  
                                   
                                  
                                      
                     







                         

























                                                                                
                                                                                                                                         








                                                
                                
                                                                                                 

                                                                  
                                   
                                  
                                                                       
                                                               
                               

                                                                        

                                                  
                                      





                                                                     
                                      












                                       
                                                          



                        
               






                                            

                                                                        
                      
                                                          
                                                                       

                               
                                

                              


                                                                        



                                   
               

                         
                 




                        
                                                                        
                                            




                        
               
               

                              


                                                                  
                                                        
     
                                                  
                                                            
                              
                                                                       


                                        

                                                                          

                                                
                                                            
     
                                                    
                                                            
                              
                                                                       

                                          
                                                              



                                                      
                                                          
                              
                              
                                                  

                                                

                                                  
                                                              
                                                           
                               

                                     

                                                        


                            
                 
                 





                        
                                                                                     








                              


                                          


                                                                        









                                               
                                    
                                   
                                              















                                              
                                                                         









                                   
                                             


                                               
                            






                                         
                                              















                                   
                                                                       




                        
               
               

                              


                                                                  

                                                       
                                                   
                                                            
                              
                                                                       


                                         


                                                                          

                                                        
     
                                                 
                                                            
                              
                                                                       

                                       
                                    


                                                                          


                                                      
                                                          
                              
                             

                                        
                                                                   

                                   
                           
                         
                 
                 





                        
                                                                                                           




                        
                                                 

                            
                              

                                     
                              


                                                              
                                        
                                
                            
                                                  
       
                                        
                         
                                                                              

                          
                         










                             
                                                                                                    




                                                                            




                        




                
                            




                                                            






                                                                          
                                      
                               


                                                    





                                                                            
     
                                        
                                                             
       
                                                   
                                       
                                 
                                            

                                                                        
                                                                    
                      
                                    



                                                      
                                                  
                                       
                                 
                                            
                                    



                                                      
                                               

                                                              
                                        
                                 
                                         
                                    

                                                      








                                                                        
     
                                          





                                                                                  
     
                                         

                                          
                                                    
                                       
                                 
         
                                             
                                         
                                   
                                              



                                                        
                                                                      





                                                      
                                                   
                                       
                                 
                                                




                                                      
                                                

                                                              
                                        
                                 
                                          


                                                      








                                                                        


                                        

                                



                 





                        
                                                                                              



                        
               

               

               

                            


                                                                  
                    
                              
                                       
                                                                 
                                                           

                                                            
                                                                
                                                            
                                                   
                                    
                                                                   
     


                                                                              
                                                              
                                     
                                                              
                                
                                                                         
                                
                                            

                                                              

                                                                                   
                                                              
                                    
                                                              
                                    
                                                                         
                                
                                               

                                                               


                                                                      







                                                                            
                                
                                                  
                                              


                                                                    
                                                                    
                                                         
                                                       

                                        
                                              
                                                       
                                           

                                                                   
       
     
                                        
                               


                                                 
                                


                         

                 
                 




                        





























































                                                                                                       

                                                                       
                                                                                             




                        
                                                 
                                             

                                                 
                                               

                             
                           
                                  
                               
                         





                        
                                                                             


                        




                              
                            
                                                    
                           
                                  


                         




                        
                                                               





                                   
                                                              

                               
                                                                        

                               
                                                               







                                  





















                                                                        





















                                                                        
                              
                                                     



                                     
                                                     

                   
                        
     
                                         
                         
                       

                                     




                                      
                                                      
                                                                               
                                               
                                             



                               
                                 
                                            
                        
                                              
                                                








                                            
                        




                                                      
                                                             





                                            
                        
                                               
                                    

                              





                                    

                                                         
                                                         

                                                    
                                          
                        
                        
                                        
                             
                           


                                       

                             

                              

                                                                                                   

                        
                        





                                                                
                                                 
             
                                             
                                                                  







                                           
                                                                                                                                   




                        
                                       











                                                                    
                    

                                     




                                      
                                                      
                                                        
                                             



                               
                                 
                                            
                        
                                                       
                                    
















                                                                

                                                            
                                         






                                            
                                                        


                                    

                             



                             

                                                                  
                                                         

                                                              
                                       



                                   
                                                                                












                                                                   
                                                            
                                                




                                            
                        
                                                             
                                          
                        
                        
                                        
                             
                           

                            


                                        

                                    

                             

                        
                        





                                                                       
                                                 
             
                                             
                                                                  







                                           
                                                                                                                               




                        
                                     

















                                                                    




                                      
                                                      
                                                      
                                             



                               
                                 
                                            
                        
                                                     
                                    

                            

                                   
               



                                            
                        








                                                              
                                         
                                  
                        
                        







                                                      

                             

                             
                   
                        




                                                                
                                       

                            

                                   
                                                                                



                                            
                        








                                                                 
                                                
                        

                          

                                            
                        
                                                            
                                             
                        
                        
                                        
                             
                           

                            




                                        

                             















                                                                      
                                        
                             
                           


                                       

                             

                              



                                                                                                   
                        






                                                                     
             
                                             
                                                                  







                                           
                                                                                                                             




                        
                                       
                                                   
                     















                                                                    




                                      
                                                      
                                                        
                                             



                               
                                 
                                            
                        
                                                       
                                    

                            

                                   
               



                                            
                        








                                                                
                                         
                                  
                        
                        





                                                        

                              



                                    
                   
                        




                                                                  
                                       

                            

                                   




                                                                                
                        








                                                                   
                                                     
                        

                          

                                            
                        
                                                              
                                             
                        
                        
                                        
                             
                           

                            




                                        

                             















                                                                        
                                        
                             
                           


                                       

                             

                              



                                                                                                   
                        






                                                                       
             
                                             
                                                                  







                                           
                                                                                                                               




                        
                        
                                                  

                        
                        







                                                     




                                      
                                                      
                                         
                                             



                               
                                 
                                            
                        
                                        
                                    

                            

                                   
               



                                            
                        








                                                             
                                         
                                  
                        
                        







                                            

                             


                             
                        



                                                         
             
                                             
                                                                        







                                           
                                                                                                       




                        


                                
                            





                                      
                                                      
                                     
                                             





                                            
                        
                                     
                                 

                            

                                   
               



                                            
                        








                                                             
                                 

                            

                                   




                                            
                        
                                          
                         
                                                      
                                 
                                              
                            


                                                             
                                                 
                                  
                        



                                            
                        
                                        
                                                  
                                  
                        



                                            
                        


                                     

                        
                                    
                      



                                    
                        



                                                         
             
                                             
                                                                        







                                           
                                                                                                                




                        


                            
                                





                                      
                                                      
                                     
                                             





                                            
                        
                                     
                                 

                            

                                
               



                                            
                        




                                                      
                                 

                            

                                   




                                            
                        








                                                             
                                                 
                                  
                        



                                            
                        

                                  
                    



                                            
                        

                                     
                        


                           
                      



                                    
                        
                                               
                                

                                                         
             
                                             
                                                                        







                                           
                                                                                                                             







                            
                             





                                      
                                                      
                                     
                                             





                                            
                        



                                    

                                   
               



                                            
                        











                                                             

                                




                                            
                        





                                                      
                                  
                        



                                            
                        

                                                  
                                  
                        



                                            
                        


                                     

                        
                                    
                      



                                    
                        



                                                         
             
                                             
                                                                        







                                           
                                                                                                                          




                        
                        

                            
                                





                                      
                                                      
                                             
                                             





                                            
                        



                                        

                                   
               



                                            
                        








                                                             
                                                 





                                            
                        



                                            

                                   
               



                                            
                        





                                                      
                                  
                        



                                            
                        

                                               
                                  
                        



                                            
                        


                                         

                        
                                    
                      



                                    
                        



                                                         
             
                                             
                                                                        







                                           
















                                                                                                               
                                             
                                             





                                            
                        



                                        

                                   
               



                                            
                        








                                                             
                                                 





                                            
                        



                                            

                                   
               



                                            
                        





                                                      
                                  
                        



                                            
                        

                                               
                                  
                        



                                            
                        


                                         

                        
                                    
                      



                                    
                        



                                                         
             
                                             
                                                                        








                                                                                                                     




                        









                                      
                                                      
                                         
                                             





                                            
                        



                                         

                                
               



                                            
                        




                                                      
                                                 





                                            
                        



                                            

                                   
               



                                            
                        





                                                      
                                  
                        



                                            
                        

                                                   
                    



                                            
                        

                                         
                        


                           
                      



                                    
                        



                                                         
             
                                             
                                                                        













                                                                                                                                  


































































































































































































































                                                                                                                                       











                                                      
                                             
































































































                                                                                                                         










                                                      
                                           
                                             





                                            
                        




                                           

                               



                                            
                        








                                                      
                               




                                            
                        









                                                             
                                  
                        



                                            
                        

                                  




                                            
                        

                                           
                        


                           
                      



                                    
                        



                                                         
             
                                             
                                                                        







                                           
                                                                                                                                      







                              
                                         






                                                      
                                           
                                             





                                            
                        



                                           


                                   



                                            
                        











                                                             

                                




                                            
                        





                                                      
                                  
                        



                                            
                        

                                  




                                            
                        

                                           
                        


                           
                      



                                    
                        



                                                         
             
                                             
                                                                        







                                           
                                                                                                                                      















                                                      
                                               
                                             





                                            
                        



                                               


                                



                                            
                        




                                                       
                                                 





                                            
                        



                                                  


                                   



                                            
                        





                                                        
                                  
                        



                                            
                        
                                                   
                                  
                    



                                            
                        

                                               
                        


                           
                      



                                    
                        



                                                         
             
                                             
                                                                        
























                                                                                                                                            
                                               
                                             





                                            
                        



                                               


                                   



                                            
                        








                                                             
                                                 





                                            
                        



                                                  


                                   



                                            
                        





                                                        
                                  
                        



                                            
                        
                                                   
                                  
                    



                                            
                        

                                               
                        


                           
                      



                                    
                        



                                                         
             
                                             
                                                                        
























                                                                                                                           
                                               
                                             





                                            
                        



                                               


                                   



                                            
                        








                                                             
                                                 





                                            
                        



                                                  


                                   



                                            
                        





                                                        
                                  
                        



                                            
                        
                                                   
                                  
                    



                                            
                        

                                               
                        


                           
                      



                                    
                        



                                                         
             
                                             
                                                                        













                                                                                                                               
                                  
                                                 
             
        
                    

                                                                              

                                                     
                   
                 
                        
     

                                    
                                                            





                                      
                                                      
                                              
                                             





                                            
                        


                                                

                                 





                                            
                        





                                                             
                                  
                        
                        





                                              
                              





                                    
                        



                                                         
             
                                             
                                                               
                                      





                                           
                  
                                                                                                                      




                        
                                                   
                                   
              
        
                 





                                      
                                                      
                                                               
                                             





                                            
                        


                                                              

                                   





                                            
                        





                                                                   
                                  
                        
                        





                                                               
                              





                                    
                        



                                                                         
             
                                             
                                                                    







                                           
                                                                                                                          




                        























                                                 
                                                



                        


                                                        
                        




                        
                                                



                        



                                                        
                        



                        
# The Mu computer's level-2 language, also called Mu.
# http://akkartik.name/post/mu-2019-2
#
# To run:
#   $ ./translate_subx init.linux [0-9]*.subx apps/mu.subx
#   $ ./a.elf < prog.mu > prog.elf

# == Goals
# 1. Be memory safe. It should be impossible to corrupt the heap, or to create
# a bad pointer. (Requires strong type safety.)
# 2. Do as little as possible to achieve goal 1. The translator should be
# implementable in machine code.
#   - minimize impedance mismatch between source language and SubX target
#     (e.g. programmer manages registers manually)
#   - checks over syntax
#     (e.g. programmer's register allocation is checked)
#   - runtime checks to avoid complex static analysis
#     (e.g. array indexing always checks bounds)

# == Language description
# A program is a sequence of function and type definitions.
#
# Function example:
#   fn foo n: int -> result/eax: int {
#     ...
#   }
#
# Functions consist of a name, optional inputs, optional outputs and a block.
#
# Function inputs and outputs are variables. All variables have a type and
# storage specifier. They can be placed either in memory (on the stack) or in
# one of 6 named registers.
#   eax ecx edx ebx esi edi
# Variables in registers must be primitive 32-bit types.
# Variables not explicitly placed in a register are on the stack.
#
# Function inputs are always passed in memory (on the stack), while outputs
# are always returned in registers.
#
# Blocks mostly consist of statements.
#
# Statements mostly consist of a name, optional inputs and optional outputs.
#
# Statement inputs are variables or literals. Variables need to specify type
# (and storage) the first time they're mentioned but not later.
#
# Statement outputs, like function outputs, must be variables in registers.
#
# Statement names must be either primitives or user-defined functions.
#
# Primitives can write to any register.
# User-defined functions only write to hard-coded registers. Outputs of each
# call must have the same registers as in the function definition.
#
# There are some other statement types:
#   - blocks. Multiple statements surrounded by '{...}' and optionally
#     prefixed with a label name and ':'
#       - {
#           ...
#         }
#       - foo: {
#           ...
#         }
#
#   - variable definitions on the stack. E.g.:
#       - var foo: int
#       - var bar: (array int 3)
#     There's no initializer; variables are automatically initialized.
#     The type of a local variable is either word-length (4 bytes) or starts with 'ref'.
#
#   - variables definitions in a register. E.g.:
#       - var foo/eax: int <- add bar 1
#     The initializer is mandatory and must be a valid instruction that writes
#     a single output to the right register. In practice registers will
#     usually be either initialized by primitives or copied from eax.
#       - var eax: int <- foo bar quux
#         var floo/ecx: int <- copy eax
#
# Still todo:
#   global variables
#   union types
#
# Formal types:
#   A program is a linked list of functions
#   A function contains:
#     name: (handle array byte)
#     inouts: linked list of vars  <-- 'inouts' is more precise than 'inputs'
#       data: (handle var)
#       next: (handle list)
#     outputs: linked list of vars
#       data: (handle var)
#       next: (handle list)
#     body: (handle block)
#   A var-type contains:
#     name: (handle array byte)
#     type: (handle type-tree)
#
#   A statement can be:
#     tag 0: a block
#     tag 1: a simple statement (stmt1)
#     tag 2: a variable defined on the stack
#     tag 3: a variable defined in a register
#
#   A block contains:
#     tag: 0
#     statements: (handle list stmt)
#     name: (handle array byte) -- starting with '$'
#
#   A regular statement contains:
#     tag: 1
#     operation: (handle array byte)
#     inouts: (handle list operand)
#     outputs: (handle list var)
#
#   A variable defined on the stack contains:
#     tag: 2
#     name: (handle array byte)
#     type: (handle type-tree)
#
#   A variable defined in a register contains:
#     tag: 3
#     name: (handle array byte)
#     type: (handle type-tree)
#     reg: (handle array byte)

# == Translation: managing the stack
# Now that we know what the language looks like in the large, let's think
# about how translation happens from the bottom up. One crucial piece of the
# puzzle is how Mu will clean up variables defined on the stack for you.
#
# Assume that we maintain a 'functions' list while parsing source code. And a
# 'primitives' list is a global constant. Both these contain enough information
# to perform type-checking on function calls or primitive statements, respectively.
#
# Defining variables pushes them on a stack with the current block depth and
# enough information about their location (stack offset or register).
# Starting a block increments the current block id.
# Each statement now has enough information to emit code for it.
# Ending a block is where the magic happens:
#   pop all variables at the current block depth
#   emit code to restore all register variables introduced at the current depth
#   emit code to clean up all stack variables at the current depth (just increment esp)
#   decrement the current block depth
#
# Formal types:
#   live-vars: stack of vars
#   var:
#     name: (handle array byte)
#     type: (handle type-tree)
#     block: int
#     stack-offset: int  (added to ebp)
#     register: (handle array byte)
#       either usual register names
#       or '*' to indicate any register
#   At most one of stack-offset or register-index must be non-zero.
#   A register of '*' designates a variable _template_. Only legal in formal
#   parameters for primitives.

# == Translating a single function call
# This one's easy. Assuming we've already checked things, we just drop the
# outputs (which use hard-coded registers) and emit inputs in a standard format.
#
# out1, out2, out3, ... <- name inout1, inout2, inout3, ...
# =>
# (name inout1 inout2 inout3)
#
# Formal types:
#   functions: linked list of info
#     name: (handle array byte)
#     inouts: linked list of vars
#     outputs: linked list of vars
#     body: block (linked list of statements)

# == Translating a single primitive instruction
# A second crucial piece of the puzzle is how Mu converts fairly regular
# primitives with their uniform syntax to SubX instructions with their gnarly
# x86 details.
#
# Mu instructions have inputs and outputs. Primitives can have up to 2 of
# them.
# SubX instructions have rm32 and r32 operands.
# The translation between them covers almost all the possibilities.
#   Instructions with 1 inout may turn into ones with 1 rm32
#     (e.g. incrementing a var on the stack)
#   Instructions with 1 output may turn into ones with 1 rm32
#     (e.g. incrementing a var in a register)
#   1 inout and 1 output may turn into 1 rm32 and 1 r32
#     (e.g. adding a var to a reg)
#   2 inouts may turn into 1 rm32 and 1 r32
#     (e.g. adding a reg to a var)
#   1 inout and 1 literal may turn into 1 rm32 and 1 imm32
#     (e.g. adding a constant to a var)
#   1 output and 1 literal may turn into 1 rm32 and 1 imm32
#     (e.g. adding a constant to a reg)
#   2 outputs to hardcoded registers and 1 inout may turn into 1 rm32
#     (special-case: divide edx:eax by a var or reg)
# Observations:
#   We always emit rm32. It may be the first inout or the first output.
#   We may emit r32 or imm32 or neither.
#   When we emit r32 it may come from first inout or second inout or first output.
#
# Accordingly, the formal data structure for a primitive looks like this:
#   primitives: linked list of info
#     name: (handle array byte)
#     mu-inouts: linked list of vars to check
#     mu-outputs: linked list of vars to check; at most a singleton
#     subx-name: (handle array byte)
#     subx-rm32: enum arg-location
#     subx-r32: enum arg-location
#     subx-imm32: enum arg-location
#     subx-imm8: enum arg-location
#     subx-disp32: enum arg-location
#     output-is-write-only: boolean
#   arg-location: enum
#     0 means none
#     1 means first inout
#     2 means second inout
#     3 means first output

# == Translating a block
# Emit block name if necessary
# Emit '{'
# When you encounter a statement, emit it as above
# When you encounter a variable declaration
#   emit any code needed for it (bzeros)
#   push it on the var stack
#   update register dict if necessary
# When you encounter '}'
#   While popping variables off the var stack until block id changes
#     Emit code needed to clean up the stack
#       either increment esp
#       or pop into appropriate register

# The rest is straightforward.

== data

Program:
_Program-functions:  # (handle function)
  0/imm32
_Program-functions->payload:
  0/imm32
_Program-types:  # (handle typeinfo)
  0/imm32
_Program-types->payload:
  0/imm32
_Program-signatures:  # (handle function)
  0/imm32
_Program-signatures->payload:
  0/imm32

# Some constants for simulating the data structures described above.
# Many constants here come with a type in a comment.
#
# Sometimes the type is of the value at that offset for the given type. For
# example, if you start at a function record and move forward Function-inouts
# bytes, you'll find a (handle list var).
#
# At other times, the type is of the constant itself. For example, the type of
# the constant Function-size is (addr int). To get the size of a function,
# look in *Function-size.

Function-name:  # (handle array byte)
  0/imm32
Function-inouts:  # (handle list var)
  8/imm32
Function-outputs:  # (handle list var)
  0x10/imm32
Function-body:  # (handle block)
  0x18/imm32
Function-next:  # (handle function)
  0x20/imm32
Function-size:  # (addr int)
  0x28/imm32/40

Primitive-name:  # (handle array byte)
  0/imm32
Primitive-inouts:  # (handle list var)
  8/imm32
Primitive-outputs:  # (handle list var)
  0x10/imm32
Primitive-subx-name:  # (handle array byte)
  0x18/imm32
Primitive-subx-rm32:  # enum arg-location
  0x20/imm32
Primitive-subx-r32:  # enum arg-location
  0x24/imm32
Primitive-subx-imm32:  # enum arg-location
  0x28/imm32
Primitive-subx-imm8:  # enum arg-location  -- only for bit shifts
  0x2c/imm32
Primitive-subx-disp32:  # enum arg-location  -- only for branches
  0x30/imm32
Primitive-output-is-write-only:  # boolean
  0x34/imm32
Primitive-next:  # (handle function)
  0x38/imm32
Primitive-size:  # (addr int)
  0x40/imm32/60

Stmt-tag:  # int
  0/imm32

Block-stmts:  # (handle list stmt)
  4/imm32
Block-var:  # (handle var)
  0xc/imm32

Stmt1-operation:  # (handle array byte)
  4/imm32
Stmt1-inouts:  # (handle stmt-var)
  0xc/imm32
Stmt1-outputs:  # (handle stmt-var)
  0x14/imm32

Vardef-var:  # (handle var)
  4/imm32

Regvardef-operation:  # (handle array byte)
  4/imm32
Regvardef-inouts:  # (handle stmt-var)
  0xc/imm32
Regvardef-outputs:  # (handle stmt-var)  # will have exactly one element
  0x14/imm32

Stmt-size:  # (addr int)
  0x1c/imm32

Var-name:  # (handle array byte)
  0/imm32
Var-type:  # (handle type-tree)
  8/imm32
Var-block-depth:  # int -- not available until code-generation time
  0x10/imm32
Var-offset:  # int -- not available until code-generation time
  0x14/imm32
Var-register:  # (handle array byte) -- name of a register
  0x18/imm32
Var-size:  # (addr int)
  0x20/imm32

List-value:  # (handle _)
  0/imm32
List-next:  # (handle list _)
  8/imm32
List-size:  # (addr int)
  0x10/imm32

# A stmt-var is like a list of vars with call-site specific metadata
Stmt-var-value:  # (handle var)
  0/imm32
Stmt-var-next:  # (handle stmt-var)
  8/imm32
Stmt-var-is-deref:  # boolean
  0x10/imm32
Stmt-var-size:  # (addr int)
  0x14/imm32

# A live-var is a var augmented with information needed for tracking live
# variables.
Live-var-value:  # (handle var)
  0/imm32
Live-var-register-spilled:  # boolean; only used if value is in a register, and only during code-gen
  8/imm32
Live-var-size:  # (addr int)
  0xc/imm32

# Types are expressed as trees (s-expressions) of type-ids (ints).

Type-tree-is-atom:  # boolean
  0/imm32
# if is-atom?
Type-tree-value:  # type-id
  4/imm32
Type-tree-value-size:  # int (for static data structure sizes)
  8/imm32
Type-tree-parameter-name:  # (handle array byte) for type parameters
  8/imm32
# unless is-atom?
Type-tree-left:  # (addr type-tree)
  4/imm32
Type-tree-right:  # (addr type-tree)
  0xc/imm32
#
Type-tree-size:  # (addr int)
  0x14/imm32

# Types

# TODO: Turn this data structure into valid Mu, with (fake) handles rather than addrs.
Type-id:  # (stream (addr array byte))
  0/imm32/write  # initialized later from Primitive-type-ids
  0/imm32/read
  0x100/imm32/size
  # data
  0/imm32  # 0 reserved for literals; value is just the name
           # Not to be used directly, so we don't include a name here.
  "int"/imm32  # 1
  "addr"/imm32  # 2
  "array"/imm32  # 3
  "handle"/imm32  # 4
  "boolean"/imm32  # 5
  0/imm32  # 6 reserved for constants; they're like literals, but value is an int in Var-offset
           # Not to be used directly, so we don't include a name here.
  "offset"/imm32  # 7: (offset T) is guaranteed to be a 32-bit multiple of size-of(T)
  # 0x20
  "byte"/imm32  # 8
  0/imm32  # 9 reserved for array-capacity; value is in Type-tree-size.
           # Not to be used directly, so we don't include a name here.
  0/imm32  # 10 reserved for type parameters; value is (address array byte) in Type-tree-value2.
           # Not to be used directly, so we don't include a name here.
  # some SubX types deliberately left undefined in Mu; they can only be operated on using SubX primitives
  "stream"/imm32  # 11
  "slice"/imm32  # 12
  "code-point"/imm32  # 13; smallest scannable unit from a text stream
  "grapheme"/imm32  # 14; smallest printable unit; will eventually be composed of multiple code-points, but currently corresponds 1:1
                    # only 4-byte graphemes in utf-8 are currently supported;
                    # unclear how we should deal with larger clusters.
  # Keep Primitive-type-ids in sync if you add types here.
                                                          0/imm32
  0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32
  0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32 0/imm32

Primitive-type-ids:  # (addr int)
  0x34

# == Type definitions
# Program->types contains some typeinfo for each type definition.
# Types contain vars with types, but can't specify registers.
Typeinfo-id:  # type-id
  0/imm32
Typeinfo-fields:  # (handle table (handle array byte) (handle typeinfo-entry))
  4/imm32
# Total size must be >= 0
# During parsing it may take on two additional values:
#   -2: not yet initialized
#   -1: in process of being computed
# See populate-mu-type-sizes for details.
Typeinfo-total-size-in-bytes:  # int
  0xc/imm32
Typeinfo-next:  # (handle typeinfo)
  0x10/imm32
Typeinfo-size:  # (addr int)
  0x18/imm32

# Each entry in the typeinfo->fields table has a pointer to a string and a
# pointer to a typeinfo-entry.
Typeinfo-fields-row-size:  # (addr int)
  0x10/imm32

# typeinfo-entry objects have information about a field in a single record type
#
# each field of a type is represented using two var's:
#   1. the input var: expected type of the field; convenient for creating using parse-var-with-type
#   2. the output var: a constant containing the byte offset; convenient for code-generation
# computing the output happens after parsing; in the meantime we preserve the
# order of fields in the 'index' field.
Typeinfo-entry-input-var:  # (handle var)
  0/imm32
Typeinfo-entry-index:  # int
  8/imm32
Typeinfo-entry-output-var:  # (handle var)
  0xc/imm32
Typeinfo-entry-size:  # (addr int)
  0x14/imm32

== code

Entry:
    # . prologue
    89/<- %ebp 4/r32/esp
    (new-segment *Heap-size Heap)
    # if (argv[1] == "test') run-tests()
    {
      # if (argc <= 1) break
      81 7/subop/compare *ebp 1/imm32
      7e/jump-if-<= break/disp8
      # if (argv[1] != "test") break
      (kernel-string-equal? *(ebp+8) "test")  # => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
      #
      (run-tests)
      # syscall(exit, *Num-test-failures)
      8b/-> *Num-test-failures 3/r32/ebx
      eb/jump $mu-main:end/disp8
    }
    # otherwise convert Stdin
    (convert-mu Stdin Stdout Stderr 0)
    (flush Stdout)
    # syscall(exit, 0)
    bb/copy-to-ebx 0/imm32
$mu-main:end:
    e8/call syscall_exit/disp32

convert-mu:  # in: (addr buffered-file), out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    # initialize global data structures
    c7 0/subop/copy *Next-block-index 1/imm32
    8b/-> *Primitive-type-ids 0/r32/eax
    89/<- *Type-id 0/r32/eax  # stream-write
    c7 0/subop/copy *_Program-functions 0/imm32
    c7 0/subop/copy *_Program-functions->payload 0/imm32
    c7 0/subop/copy *_Program-types 0/imm32
    c7 0/subop/copy *_Program-types->payload 0/imm32
    c7 0/subop/copy *_Program-signatures 0/imm32
    c7 0/subop/copy *_Program-signatures->payload 0/imm32
    #
    (parse-mu *(ebp+8) *(ebp+0x10) *(ebp+0x14))
    (populate-mu-type-sizes *(ebp+0x10) *(ebp+0x14))
#?     (dump-typeinfos "=== typeinfos\n")
    (check-mu-types *(ebp+0x10) *(ebp+0x14))
    (emit-subx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
$convert-mu:end:
    # . restore registers
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-empty-input:
    # empty input => empty output
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
    (check-stream-equal _test-output-stream "" "F - test-convert-empty-input")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-skeleton:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-skeleton/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-skeleton/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-skeleton/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-skeleton/3")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-skeleton/4")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-skeleton/5")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-skeleton/6")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-skeleton/7")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-multiple-function-skeletons:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "fn bar {\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check first function
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-multiple-function-skeletons/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/3")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/4")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/5")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/6")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/7")
    # check second function
    (check-next-stream-line-equal _test-output-stream "bar:"                    "F - test-convert-multiple-function-skeletons/10")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-multiple-function-skeletons/11")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-multiple-function-skeletons/12")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-multiple-function-skeletons/13")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-multiple-function-skeletons/14")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-multiple-function-skeletons/15")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-multiple-function-skeletons/16")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-multiple-function-skeletons/17")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-with-arg:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo n: int {\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg/3")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg/4")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg/5")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg/6")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg/7")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-with-arg-and-body:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo n: int {\n")
    (write _test-input-stream "  increment n\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-arg-and-body/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-arg-and-body/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-arg-and-body/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-arg-and-body/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-arg-and-body/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-arg-and-body/5")
    (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-arg-and-body/6")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-arg-and-body/7")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-arg-and-body/8")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-arg-and-body/9")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-arg-and-body/10")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-arg-and-body/11")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-arg-and-body/12")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-distinguishes-args:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo a: int, b: int {\n")
    (write _test-input-stream "  increment b\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-distinguishes-args/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-distinguishes-args/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-distinguishes-args/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-distinguishes-args/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-distinguishes-args/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-distinguishes-args/5")
    (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0x0000000c)"  "F - test-convert-function-distinguishes-args/6")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-distinguishes-args/7")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-distinguishes-args/8")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-distinguishes-args/9")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-distinguishes-args/10")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-distinguishes-args/11")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-distinguishes-args/12")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-returns-result:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
    (write _test-input-stream "  result <- copy a\n")
    (write _test-input-stream "  result <- increment\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-returns-result/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-returns-result/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-returns-result/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-returns-result/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-returns-result/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-returns-result/5")
    (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-returns-result/6")
    (check-next-stream-line-equal _test-output-stream "    40/increment-eax"    "F - test-convert-function-returns-result/7")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-returns-result/8")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-returns-result/9")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-returns-result/10")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-returns-result/11")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-returns-result/12")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-returns-result/13")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-with-literal-arg:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo a: int, b: int -> result/eax: int {\n")
    (write _test-input-stream "  result <- copy a\n")
    (write _test-input-stream "  result <- add 1\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg/5")
    (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-with-literal-arg/6")
    (check-next-stream-line-equal _test-output-stream "    05/add-to-eax 1/imm32"  "F - test-convert-function-with-literal-arg/7")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg/8")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg/9")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg/10")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg/11")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg/12")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg/13")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-with-literal-arg-2:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo a: int, b: int -> result/ebx: int {\n")
    (write _test-input-stream "  result <- copy a\n")
    (write _test-input-stream "  result <- add 1\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-literal-arg-2/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-literal-arg-2/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-literal-arg-2/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-literal-arg-2/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-literal-arg-2/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-literal-arg-2/5")
    (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-with-literal-arg-2/6")
    (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %ebx 1/imm32"  "F - test-convert-function-with-literal-arg-2/7")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-literal-arg-2/8")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-literal-arg-2/9")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-literal-arg-2/10")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-literal-arg-2/11")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-literal-arg-2/12")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-literal-arg-2/13")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-call-with-literal-arg:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn main -> result/ebx: int {\n")
    (write _test-input-stream "  result <- do-add 3 4\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "fn do-add a: int, b: int -> result/ebx: int {\n")
    (write _test-input-stream "  result <- copy a\n")
    (write _test-input-stream "  result <- add b\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call-with-literal-arg/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/4")
    (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call-with-literal-arg/5")
    (check-next-stream-line-equal _test-output-stream "    (do-add 3 4)"        "F - test-convert-function-call-with-literal-arg/6")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/7")
    (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-literal-arg/8")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/9")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/10")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/11")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/12")
    (check-next-stream-line-equal _test-output-stream "do-add:"                 "F - test-convert-function-call-with-literal-arg/13")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-literal-arg/14")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-literal-arg/15")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-literal-arg/16")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-literal-arg/17")
    (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:loop:"  "F - test-convert-function-call-with-literal-arg/18")
    (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/19")
    (check-next-stream-line-equal _test-output-stream "    03/add *(ebp+0x0000000c) 0x00000003/r32"  "F - test-convert-function-call-with-literal-arg/20")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-literal-arg/21")
    (check-next-stream-line-equal _test-output-stream "$do-add:0x00000002:break:"  "F - test-convert-function-call-with-literal-arg/22")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-literal-arg/23")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-literal-arg/24")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-literal-arg/25")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-literal-arg/26")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-call-with-signature:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn main -> result/ebx: int {\n")
    (write _test-input-stream "  result <- do-add 3 4\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "sig do-add a: int, b: int -> result/ebx: int\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call-with-signature/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-signature/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-signature/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-signature/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-signature/4")
    (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call-with-signature/5")
    (check-next-stream-line-equal _test-output-stream "    (do-add 3 4)"        "F - test-convert-function-call-with-signature/6")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-signature/7")
    (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call-with-signature/8")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-signature/9")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-signature/10")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-signature/11")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-signature/12")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-with-local-var-in-mem:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var x: int\n")
    (write _test-input-stream "  increment x\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-mem/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-mem/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-mem/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-mem/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-mem/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-mem/5")
    (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-in-mem/6")
    (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-mem/7")
    (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-local-var-in-mem/8")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-mem/9")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-mem/10")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-mem/11")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-mem/12")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-mem/13")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-mem/14")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-invalid-literal:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  increment 1n\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-convert-invalid-literal: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: variable '1n' cannot begin with a digit (or do you have a typo in a number?)"  "F - test-convert-invalid-literal: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-convert-invalid-literal: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-local-var-in-mem-has-no-initializer:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var x: int <- copy 0\n")
    (write _test-input-stream "  increment x\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-var-in-mem-has-no-initializer: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: var x: variables on the stack can't take an initializer"  "F - test-var-in-mem-has-no-initializer: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-var-in-mem-has-no-initializer: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-convert-function-with-local-var-with-compound-type-in-mem:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var x: (addr int)\n")
    (write _test-input-stream "  copy-to x, 0\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-compound-type-in-mem/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-compound-type-in-mem/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-compound-type-in-mem/5")
    (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-compound-type-in-mem/6")
    (check-next-stream-line-equal _test-output-stream "    c7 0/subop/copy *(ebp+0xfffffffc) 0/imm32"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/7")
    (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/8")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-compound-type-in-mem/9")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/10")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-compound-type-in-mem/11")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-with-compound-type-in-mem/12")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-with-compound-type-in-mem/13")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-compound-type-in-mem/14")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-with-local-var-in-reg:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var x/ecx: int <- copy 3\n")
    (write _test-input-stream "  x <- increment\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-reg/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-reg/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-reg/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-reg/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-reg/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-reg/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-in-reg/6")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-convert-function-with-local-var-in-reg/7")
    (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-local-var-in-reg/8")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-in-reg/9")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-reg/10")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-reg/11")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-reg/12")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-reg/13")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-reg/14")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-reg/15")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-with-allocate:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var x/ecx: (addr handle int) <- copy 0\n")
    (write _test-input-stream "  allocate x\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-allocate/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-allocate/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-allocate/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-allocate/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-allocate/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-allocate/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-allocate/6")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-allocate/7")
    (check-next-stream-line-equal _test-output-stream "    (allocate Heap 0x00000004 %ecx)"  "F - test-convert-function-with-allocate/8")  # 4 = size-of(int)
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-allocate/9")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-allocate/10")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-allocate/11")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-allocate/12")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-allocate/13")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-allocate/14")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-allocate/15")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-initializer-in-hex:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var x/ecx: int <- copy 10\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-initializer-in-hex: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "literal integers are always hex in Mu; either start '10' with a '0x' to be unambiguous, or convert it to decimal."  "F - test-initializer-in-hex: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-initializer-in-hex: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-convert-function-with-second-local-var-in-same-reg:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var x/ecx: int <- copy 3\n")
    (write _test-input-stream "  var y/ecx: int <- copy 4\n")
    (write _test-input-stream "  y <- increment\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-second-local-var-in-same-reg/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-second-local-var-in-same-reg/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-second-local-var-in-same-reg/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-second-local-var-in-same-reg/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-second-local-var-in-same-reg/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-second-local-var-in-same-reg/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-second-local-var-in-same-reg/6")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-convert-function-with-second-local-var-in-same-reg/7")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-convert-function-with-second-local-var-in-same-reg/8")
    (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-convert-function-with-second-local-var-in-same-reg/9")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-second-local-var-in-same-reg/10")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-second-local-var-in-same-reg/11")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-second-local-var-in-same-reg/12")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-second-local-var-in-same-reg/13")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-second-local-var-in-same-reg/14")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-second-local-var-in-same-reg/15")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-second-local-var-in-same-reg/16")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-read-clobbered-reg-var:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)  # bytes of args in call to convert-mu
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var x/ecx: int <- copy 3\n")
    (write _test-input-stream "  var y/ecx: int <- copy 4\n")
    (write _test-input-stream "  x <- increment\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-read-clobbered-reg-var: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: register ecx reads var 'x' after writing var 'y'"  "F - test-read-clobbered-reg-var: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-read-clobbered-reg-var: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-convert-function-call:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn main -> result/ebx: int {\n")
    (write _test-input-stream "  result <- foo\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "fn foo -> result/ebx: int {\n")
    (write _test-input-stream "  result <- copy 3\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "main:"                   "F - test-convert-function-call/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call/4")
    (check-next-stream-line-equal _test-output-stream "$main:0x00000001:loop:"  "F - test-convert-function-call/5")
    (check-next-stream-line-equal _test-output-stream "    (foo)"               "F - test-convert-function-call/6")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call/7")
    (check-next-stream-line-equal _test-output-stream "$main:0x00000001:break:" "F - test-convert-function-call/8")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call/9")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call/10")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call/11")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call/12")
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call/13")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call/14")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call/15")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call/16")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call/17")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"  "F - test-convert-function-call/18")
    (check-next-stream-line-equal _test-output-stream "    bb/copy-to-ebx 3/imm32"  "F - test-convert-function-call/19")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call/20")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-call/21")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call/22")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call/23")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call/24")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call/25")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-call-with-inout-with-compound-type:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn f {\n")
    (write _test-input-stream "  var x: (addr int)\n")
    (write _test-input-stream "  g x\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "fn g a: (addr int) {\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-inout-with-compound-type/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-inout-with-compound-type/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-inout-with-compound-type/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-inout-with-compound-type/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-inout-with-compound-type/4")
    (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-inout-with-compound-type/5")
    (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-inout-with-compound-type/6")
    (check-next-stream-line-equal _test-output-stream "    (g *(ebp+0xfffffffc))"  "F - test-convert-function-call-with-inout-with-compound-type/7")
    (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-call-with-inout-with-compound-type/8")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-inout-with-compound-type/9")
    (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-inout-with-compound-type/10")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-inout-with-compound-type/11")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-inout-with-compound-type/12")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-inout-with-compound-type/13")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-inout-with-compound-type/14")
    (check-next-stream-line-equal _test-output-stream "g:"                      "F - test-convert-function-call-with-inout-with-compound-type/15")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-inout-with-compound-type/16")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-inout-with-compound-type/17")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-inout-with-compound-type/18")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-inout-with-compound-type/19")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-inout-with-compound-type/20")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-inout-with-compound-type/21")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-inout-with-compound-type/22")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-call-with-inout-with-type-parameter:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn f {\n")
    (write _test-input-stream "  var x: (addr int)\n")
    (write _test-input-stream "  g x\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "fn g a: (addr _) {\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # no error; types matched
    (check-stream-equal _test-error-stream  ""  "F - test-convert-function-call-with-inout-with-type-parameter: error stream should be empty")
    # don't bother checking the generated code; that's in the test 'test-local-clobbered-by-fn-output' below
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-convert-function-call-with-incorrect-inout-type:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn f {\n")
    (write _test-input-stream "  var x: int\n")
    (write _test-input-stream "  g x\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "fn g a: foo {\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-inout-type: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn f: call g: type for inout 'x' is not right"  "F - test-convert-function-call-with-incorrect-inout-type: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-inout-type: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    5d/pop-to-ebp
    c3/return

test-convert-function-call-with-inout-with-incorrect-compound-type:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn f {\n")
    (write _test-input-stream "  var x: (addr int)\n")
    (write _test-input-stream "  g x\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "fn g a: (addr bool) {\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-inout-with-incorrect-compound-type: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn f: call g: type for inout 'x' is not right"  "F - test-convert-function-call-with-inout-with-incorrect-compound-type: error message")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-convert-function-call-with-inout-with-multiple-type-parameters:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn f {\n")
    (write _test-input-stream "  var x: (addr int)\n")
    (write _test-input-stream "  var y: (addr int)\n")
    (write _test-input-stream "  g x, y\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "fn g a: (addr _), b: (addr _) {\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # no errors
    (check-stream-equal _test-error-stream  ""  "F - test-convert-function-call-with-inout-with-multiple-type-parameters: error stream should be empty")
    # don't bother checking the generated code
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-type-parameter-matches-rest-of-type:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn f {\n")
    (write _test-input-stream "  var x: (addr array int)\n")
    (write _test-input-stream "  g x\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "fn g a: (addr _) {\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # no errors
    (check-stream-equal _test-error-stream  ""  "F - test-type-parameter-matches-rest-of-type: error stream should be empty")
    # don't bother checking the generated code
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-convert-function-call-with-inout-with-incompatible-type-parameters:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn f {\n")
    (write _test-input-stream "  var x: (addr int)\n")
    (write _test-input-stream "  var y: (addr boolean)\n")
    (write _test-input-stream "  g x, y\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "fn g a: (addr _T), b: (addr _T) {\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-inout-with-incompatible-type-parameters: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn f: call g: type for inout 'y' is not right"  "F - test-convert-function-call-with-inout-with-incompatible-type-parameters: error message")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-convert-function-call-with-too-few-inouts:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn f {\n")
    (write _test-input-stream "  g\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "fn g a: int {\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-few-inouts: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn f: call g: too few inouts"  "F - test-convert-function-call-with-too-few-inouts: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-few-inouts: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    5d/pop-to-ebp
    c3/return

test-convert-function-call-with-too-many-inouts:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn f {\n")
    (write _test-input-stream "  var x: int\n")
    (write _test-input-stream "  g x\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "fn g {\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-many-inouts: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn f: call g: too many inouts"  "F - test-convert-function-call-with-too-many-inouts: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-many-inouts: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    5d/pop-to-ebp
    c3/return

test-convert-function-call-with-incorrect-output-type:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn f {\n")
    (write _test-input-stream "  var x/eax: int <- g\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "fn g -> a/eax: foo {\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-output-type: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn f: call g: type for output 'x' is not right"  "F - test-convert-function-call-with-incorrect-output-type: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-output-type: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    5d/pop-to-ebp
    c3/return

test-convert-function-call-with-too-few-outputs:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn f {\n")
    (write _test-input-stream "  g\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "fn g -> a/eax: int {\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-few-outputs: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn f: call g: too few outputs"  "F - test-convert-function-call-with-too-few-outputs: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-few-outputs: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    5d/pop-to-ebp
    c3/return

test-convert-function-call-with-too-many-outputs:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn f {\n")
    (write _test-input-stream "  var x/eax: int <- g\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "fn g {\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-too-many-outputs: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn f: call g: too many outputs"  "F - test-convert-function-call-with-too-many-outputs: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-too-many-outputs: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    5d/pop-to-ebp
    c3/return

test-convert-function-call-with-incorrect-output-register:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn f {\n")
    (write _test-input-stream "  var x/ecx: int <- g\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "fn g -> a/eax: int {\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-convert-function-call-with-incorrect-output-register: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn f: call g: register for output 'x' is not right"  "F - test-convert-function-call-with-incorrect-output-register: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-convert-function-call-with-incorrect-output-register: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    5d/pop-to-ebp
    c3/return

test-convert-function-with-local-var-dereferenced:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var x/ecx: (addr int) <- copy 0\n")
    (write _test-input-stream "  increment *x\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-dereferenced/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-dereferenced/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-dereferenced/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-dereferenced/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-dereferenced/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-dereferenced/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-local-var-dereferenced/6")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-local-var-dereferenced/7")
    (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *ecx"  "F - test-convert-function-with-local-var-dereferenced/8")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-local-var-dereferenced/9")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-dereferenced/10")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-dereferenced/11")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-dereferenced/12")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-dereferenced/13")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-dereferenced/14")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-dereferenced/15")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# variables of type 'byte' are not allowed on the stack
test-convert-function-with-byte-operations:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var x/eax: byte <- copy 0\n")
    (write _test-input-stream "  var y/ecx: byte <- copy 0\n")
    (write _test-input-stream "  y <- copy-byte x\n")
    (write _test-input-stream "  var z/edx: (addr byte) <- copy 0\n")
    (write _test-input-stream "  y <- copy-byte *z\n")
    (write _test-input-stream "  copy-byte-to *z, x\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-function-with-byte-operations/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-function-with-byte-operations/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-function-with-byte-operations/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-function-with-byte-operations/3")
    (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-function-with-byte-operations/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-function-with-byte-operations/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-function-with-byte-operations/6")
    (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-function-with-byte-operations/7")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-function-with-byte-operations/8")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"                  "F - test-convert-function-with-byte-operations/9")
    (check-next-stream-line-equal _test-output-stream "    8a/byte-> %eax 0x00000001/r32"           "F - test-convert-function-with-byte-operations/10")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %edx"                    "F - test-convert-function-with-byte-operations/11")
    (check-next-stream-line-equal _test-output-stream "    ba/copy-to-edx 0/imm32"                  "F - test-convert-function-with-byte-operations/12")
    (check-next-stream-line-equal _test-output-stream "    8a/byte-> *edx 0x00000001/r32"           "F - test-convert-function-with-byte-operations/13")
    (check-next-stream-line-equal _test-output-stream "    88/byte<- *edx 0x00000000/r32"           "F - test-convert-function-with-byte-operations/14")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %edx"                     "F - test-convert-function-with-byte-operations/15")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-function-with-byte-operations/16")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-function-with-byte-operations/17")
    (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-function-with-byte-operations/18")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-function-with-byte-operations/19")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-function-with-byte-operations/20")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-function-with-byte-operations/21")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-function-with-byte-operations/22")
    (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-function-with-byte-operations/23")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# variables of type 'byte' _can_ be function args. They then occupy 4 bytes.
test-copy-byte-var-from-fn-arg:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo x: byte, y: int {\n")
    (write _test-input-stream "  var a/eax: byte <- copy x\n")
    (write _test-input-stream "  var b/eax: int <- copy y\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-copy-byte-from-fn-arg/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-copy-byte-from-fn-arg/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-copy-byte-from-fn-arg/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-copy-byte-from-fn-arg/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-copy-byte-from-fn-arg/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-copy-byte-from-fn-arg/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-copy-byte-from-fn-arg/6")
    (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-copy-byte-from-fn-arg/7")
    (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x0000000c) 0x00000000/r32"  "F - test-copy-byte-from-fn-arg/8")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"   "F - test-copy-byte-from-fn-arg/9")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-copy-byte-from-fn-arg/10")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-copy-byte-from-fn-arg/11")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-copy-byte-from-fn-arg/12")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-copy-byte-from-fn-arg/13")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-copy-byte-from-fn-arg/14")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-copy-byte-from-fn-arg/15")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-compare-register-with-literal:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var x/ecx: int <- copy 0\n")
    (write _test-input-stream "  compare x, 0\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-compare-register-with-literal/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-compare-register-with-literal/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-compare-register-with-literal/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-compare-register-with-literal/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-compare-register-with-literal/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-compare-register-with-literal/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-compare-register-with-literal/7")
    (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0/imm32"  "F - test-convert-compare-register-with-literal/8")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-compare-register-with-literal/10")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-compare-register-with-literal/11")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-compare-register-with-literal/12")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-compare-register-with-literal/13")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-compare-register-with-literal/14")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-compare-register-with-literal/15")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-unknown-variable:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  compare x, 0\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-unknown-variable: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: unknown variable 'x'"  "F - test-unknown-variable: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-unknown-variable: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-convert-function-with-local-var-in-block:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  {\n")
    (write _test-input-stream "    var x: int\n")
    (write _test-input-stream "    increment x\n")
    (write _test-input-stream "  }\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-block/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-block/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-block/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-block/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-block/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-block/5")
    (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-block/6")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-local-var-in-block/7")
    (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-block/8")
    (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-block/9")
    (check-next-stream-line-equal _test-output-stream "      81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-local-var-in-block/10")
    (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-block/11")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-local-var-in-block/12")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-block/13")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-block/14")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-block/15")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-block/16")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-block/17")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-block/18")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-with-local-var-in-mem-after-block:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  {\n")
    (write _test-input-stream "    var y: int\n")
    (write _test-input-stream "  }\n")
    (write _test-input-stream "  var x: int\n")
    (write _test-input-stream "  increment x\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-mem-after-block/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-mem-after-block/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-mem-after-block/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-mem-after-block/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-mem-after-block/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-mem-after-block/5")
    (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-mem-after-block/6")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-local-var-in-mem-after-block/7")
    (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-mem-after-block/8")
    (check-next-stream-line-equal _test-output-stream "      81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-local-var-in-mem-after-block/9")
    (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-mem-after-block/10")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-local-var-in-mem-after-block/11")
    (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-in-mem-after-block/12")
    (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-mem-after-block/13")
    (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-local-var-in-mem-after-block/14")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-mem-after-block/15")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-mem-after-block/16")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-mem-after-block/17")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-mem-after-block/18")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-mem-after-block/19")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-mem-after-block/20")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-with-local-var-in-named-block:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  $bar: {\n")
    (write _test-input-stream "    var x: int\n")
    (write _test-input-stream "    increment x\n")
    (write _test-input-stream "  }\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-in-named-block/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-in-named-block/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-in-named-block/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-in-named-block/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-in-named-block/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-in-named-block/5")
    (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-local-var-in-named-block/6")
    (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-local-var-in-named-block/7")
    (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-local-var-in-named-block/8")
    (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-local-var-in-named-block/9")
    (check-next-stream-line-equal _test-output-stream "      81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-local-var-in-named-block/10")
    (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-local-var-in-named-block/11")
    (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-local-var-in-named-block/12")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-in-named-block/13")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-in-named-block/14")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-in-named-block/15")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-in-named-block/16")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-in-named-block/17")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-in-named-block/18")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-unknown-variable-in-named-block:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  $a: {\n")
    (write _test-input-stream "    compare x, 0\n")
    (write _test-input-stream "  }\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-unknown-variable-in-named-block: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: unknown variable 'x'"  "F - test-unknown-variable-in-named-block: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-unknown-variable-in-named-block: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-always-shadow-outermost-reg-vars-in-function:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var x/ecx: int <- copy 3\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-always-shadow-outermost-reg-vars-in-function/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-always-shadow-outermost-reg-vars-in-function/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-always-shadow-outermost-reg-vars-in-function/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-always-shadow-outermost-reg-vars-in-function/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-always-shadow-outermost-reg-vars-in-function/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-always-shadow-outermost-reg-vars-in-function/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-compare-register-with-literal/6")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-always-shadow-outermost-reg-vars-in-function/8")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-compare-register-with-literal/9")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-always-shadow-outermost-reg-vars-in-function/12")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-always-shadow-outermost-reg-vars-in-function/13")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-always-shadow-outermost-reg-vars-in-function/14")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-always-shadow-outermost-reg-vars-in-function/15")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-always-shadow-outermost-reg-vars-in-function/16")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-always-shadow-outermost-reg-vars-in-function/17")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

_pending-test-clobber-dead-local:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var x/ecx: int <- copy 3\n")
    (write _test-input-stream "  {\n")
    (write _test-input-stream "    var y/ecx: int <- copy 4\n")
    (write _test-input-stream "  }\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-clobber-dead-local/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-clobber-dead-local/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-clobber-dead-local/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-clobber-dead-local/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-clobber-dead-local/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-clobber-dead-local/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-clobber-dead-local/6")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-clobber-dead-local/7")
    (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-clobber-dead-local/8")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-clobber-dead-local/9")
    (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-clobber-dead-local/10")  # no push/pop here
    (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-clobber-dead-local/11")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-clobber-dead-local/12")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-clobber-dead-local/13")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-clobber-dead-local/14")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-clobber-dead-local/15")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-clobber-dead-local/16")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-clobber-dead-local/17")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-clobber-dead-local/18")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-clobber-dead-local/19")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-shadow-live-local:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var x/ecx: int <- copy 3\n")
    (write _test-input-stream "  {\n")
    (write _test-input-stream "    var y/ecx: int <- copy 4\n")
    (write _test-input-stream "  }\n")
    (write _test-input-stream "  x <- increment\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-local/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-local/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-local/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-local/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-local/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-local/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-live-local/6")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-live-local/7")
    (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-local/8")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-local/9")
    (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-local/10")
    (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-local/11")
    (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-local/12")
    (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-local/13")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-local/14")
    (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-local/15")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-live-local/16")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-local/17")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-local/18")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-local/19")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-local/20")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-local/21")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-local/22")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-shadow-name:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var x/ecx: int <- copy 3\n")
    (write _test-input-stream "  {\n")
    (write _test-input-stream "    var x/edx: int <- copy 4\n")
    (write _test-input-stream "  }\n")
    (write _test-input-stream "  x <- increment\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-name/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-name/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-name/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-name/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-name/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-name/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-name/6")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-name/7")
    (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-name/8")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-name/9")
    (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %edx"  "F - test-shadow-name/10")
    (check-next-stream-line-equal _test-output-stream "      ba/copy-to-edx 4/imm32"  "F - test-shadow-name/11")
    (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %edx" "F - test-shadow-name/12")
    (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-name/13")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-name/14")
    (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-name/15")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-name/16")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-name/17")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-name/18")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-name/19")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-name/20")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-name/21")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-name/22")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-shadow-name-2:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var x/ecx: int <- copy 3\n")
    (write _test-input-stream "  {\n")
    (write _test-input-stream "    var x/edx: int <- copy 4\n")
    (write _test-input-stream "    var y/ecx: int <- copy 5\n")
    (write _test-input-stream "  }\n")
    (write _test-input-stream "  x <- increment\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-name-2/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-name-2/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-name-2/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-name-2/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-name-2/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-name-2/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-shadow-name-2/6")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-name-2/7")
    (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-name-2/8")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-name-2/9")
    (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %edx"  "F - test-shadow-name-2/10")
    (check-next-stream-line-equal _test-output-stream "      ba/copy-to-edx 4/imm32"  "F - test-shadow-name-2/11")
    (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-name-2/12")
    (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 5/imm32"  "F - test-shadow-name-2/13")
    (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-name-2/14")
    (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %edx" "F - test-shadow-name-2/15")
    (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-name-2/16")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-name-2/17")
    (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-name-2/18")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-shadow-name-2/19")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-name-2/20")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-name-2/21")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-name-2/22")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-name-2/23")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-name-2/24")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-name-2/25")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-do-not-spill-same-register-in-block:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var x/ecx: int <- copy 3\n")
    (write _test-input-stream "  var y/ecx: int <- copy 4\n")
    (write _test-input-stream "  y <- increment\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-do-not-spill-same-register-in-block/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-do-not-spill-same-register-in-block/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-do-not-spill-same-register-in-block/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-do-not-spill-same-register-in-block/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-do-not-spill-same-register-in-block/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-do-not-spill-same-register-in-block/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-do-not-spill-same-register-in-block/6")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-do-not-spill-same-register-in-block/7")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-do-not-spill-same-register-in-block/8")
    (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-do-not-spill-same-register-in-block/9")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-do-not-spill-same-register-in-block/10")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-do-not-spill-same-register-in-block/11")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-do-not-spill-same-register-in-block/12")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-do-not-spill-same-register-in-block/13")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-do-not-spill-same-register-in-block/14")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-do-not-spill-same-register-in-block/15")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-do-not-spill-same-register-in-block/16")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-spill-different-register-in-block:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var x/eax: int <- copy 3\n")
    (write _test-input-stream "  var y/ecx: int <- copy 4\n")
    (write _test-input-stream "  y <- increment\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-spill-different-register-in-block/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-spill-different-register-in-block/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-spill-different-register-in-block/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-spill-different-register-in-block/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-spill-different-register-in-block/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-spill-different-register-in-block/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-spill-different-register-in-block/6")
    (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-spill-different-register-in-block/7")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-spill-different-register-in-block/8")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-spill-different-register-in-block/9")
    (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-spill-different-register-in-block/10")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-spill-different-register-in-block/11")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-spill-different-register-in-block/12")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-spill-different-register-in-block/13")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-spill-different-register-in-block/14")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-spill-different-register-in-block/15")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-spill-different-register-in-block/16")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-spill-different-register-in-block/17")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-spill-different-register-in-block/18")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-shadow-live-output:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo -> x/ecx: int {\n")
    (write _test-input-stream "  x <- copy 3\n")
    (write _test-input-stream "  {\n")
    (write _test-input-stream "    var y/ecx: int <- copy 4\n")
    (write _test-input-stream "  }\n")
    (write _test-input-stream "  x <- increment\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-shadow-live-output/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-shadow-live-output/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-shadow-live-output/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-shadow-live-output/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-shadow-live-output/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-shadow-live-output/5")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"  "F - test-shadow-live-output/7")  # no push because it's an output reg
    (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-shadow-live-output/8")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-shadow-live-output/9")
    (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-shadow-live-output/10")
    (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-shadow-live-output/11")
    (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx" "F - test-shadow-live-output/12")
    (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-shadow-live-output/13")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-shadow-live-output/14")
    (check-next-stream-line-equal _test-output-stream "    41/increment-ecx"    "F - test-shadow-live-output/15")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-shadow-live-output/17")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-shadow-live-output/18")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-shadow-live-output/19")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-shadow-live-output/20")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-shadow-live-output/21")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-shadow-live-output/21")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-stmt-defines-output-in-same-register-as-inout:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo -> x/ecx: int {\n")
    (write _test-input-stream "  var y/ecx: int <- copy 4\n")
    (write _test-input-stream "  x <- copy y\n")  # writing to a fn output is currently the only way for a statement to define a new var
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # no error; we looked up 'y' correctly before pushing the binding for 'x'
    (check-stream-equal _test-error-stream  ""  "F - test-stmt-defines-output-in-same-register-as-inout: error stream should be empty")
    # don't bother checking the generated code; that's in the test 'test-local-clobbered-by-fn-output' below
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-local-clobbered-by-fn-output:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo -> x/ecx: int {\n")
    (write _test-input-stream "  var y/ecx: int <- copy 4\n")
    (write _test-input-stream "  x <- copy y\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-local-clobbered-by-fn-output/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-local-clobbered-by-fn-output/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-local-clobbered-by-fn-output/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-local-clobbered-by-fn-output/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-local-clobbered-by-fn-output/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-local-clobbered-by-fn-output/5")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 4/imm32"  "F - test-local-clobbered-by-fn-output/6")  # no push because it's an output reg
    (check-next-stream-line-equal _test-output-stream "    89/<- %ecx 0x00000001/r32"  "F - test-local-clobbered-by-fn-output/7")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-local-clobbered-by-fn-output/8")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-local-clobbered-by-fn-output/9")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-local-clobbered-by-fn-output/10")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-local-clobbered-by-fn-output/11")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-local-clobbered-by-fn-output/12")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-local-clobbered-by-fn-output/13")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-read-output:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo -> x/ecx: int {\n")
    (write _test-input-stream "  x <- copy 0x34\n")
    (write _test-input-stream "  compare x, 0x35\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-read-output/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-read-output/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-read-output/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-read-output/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-read-output/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-read-output/5")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0x34/imm32"  "F - test-read-output/6")
    (check-next-stream-line-equal _test-output-stream "    81 7/subop/compare %ecx 0x35/imm32"  "F - test-read-output/7")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-read-output/8")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-read-output/9")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-read-output/10")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-read-output/11")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-read-output/12")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-read-output/13")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-fn-output-written-in-inner-block:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo -> out/edi: int {\n")
    (write _test-input-stream "  var a/eax: int <- copy 3\n")  # define outer local
    (write _test-input-stream "  {\n")
    (write _test-input-stream "    var a/ecx: int <- copy 4\n")  # shadow outer local
    (write _test-input-stream "    out <- copy a\n")  # write to fn output
    (write _test-input-stream "  }\n")
    (write _test-input-stream "  compare a, 0\n")  # use outer local
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # no error; defining 'out' didn't interfere with the reclamation of 'b'
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-fn-output-written-in-inner-block/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-fn-output-written-in-inner-block/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-fn-output-written-in-inner-block/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-fn-output-written-in-inner-block/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-fn-output-written-in-inner-block/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-fn-output-written-in-inner-block/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-fn-output-written-in-inner-block/6")
    (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 3/imm32"  "F - test-fn-output-written-in-inner-block/7")
    (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-fn-output-written-in-inner-block/8")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-fn-output-written-in-inner-block/9")
    (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %ecx"  "F - test-fn-output-written-in-inner-block/10")
    (check-next-stream-line-equal _test-output-stream "      b9/copy-to-ecx 4/imm32"  "F - test-fn-output-written-in-inner-block/10")
    (check-next-stream-line-equal _test-output-stream "      89/<- %edi 0x00000001/r32"  "F - test-fn-output-written-in-inner-block/11")
    (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %ecx"  "F - test-fn-output-written-in-inner-block/12")
    (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-fn-output-written-in-inner-block/13")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-fn-output-written-in-inner-block/14")
    (check-next-stream-line-equal _test-output-stream "    3d/compare-eax-with 0/imm32"  "F - test-fn-output-written-in-inner-block/15")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-fn-output-written-in-inner-block/16")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-fn-output-written-in-inner-block/17")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-fn-output-written-in-inner-block/18")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-fn-output-written-in-inner-block/19")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-fn-output-written-in-inner-block/20")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-fn-output-written-in-inner-block/21")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-fn-output-written-in-inner-block/22")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-with-branches-in-block:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo x: int {\n")
    (write _test-input-stream "  {\n")
    (write _test-input-stream "    break-if->=\n")
    (write _test-input-stream "    loop-if-addr<\n")
    (write _test-input-stream "    increment x\n")
    (write _test-input-stream "    loop\n")
    (write _test-input-stream "  }\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-block/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-block/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-block/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-block/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-block/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-block/5")
    (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-block/6")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-in-block/7")
    (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/8")
    (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-block/9")
    (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-in-block/10")
    (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/11")
    (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-block/12")
    (check-next-stream-line-equal _test-output-stream "        0f 83/jump-if-addr>= break/disp32"  "F - test-convert-function-with-branches-in-block/13")
    (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:loop/disp32"  "F - test-convert-function-with-branches-in-block/14")
    (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-block/15")
    (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-block/16")
    (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-in-block/17")
    (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-block/18")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-in-block/19")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-block/20")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-block/21")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-block/22")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-block/23")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-block/24")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-block/25")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-with-branches-in-named-block:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo x: int {\n")
    (write _test-input-stream "  $bar: {\n")
    (write _test-input-stream "    break-if->= $bar\n")
    (write _test-input-stream "    loop-if-addr< $bar\n")
    (write _test-input-stream "    increment x\n")
    (write _test-input-stream "    loop\n")
    (write _test-input-stream "  }\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-in-named-block/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-in-named-block/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-in-named-block/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-in-named-block/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-in-named-block/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-in-named-block/5")
    (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-in-named-block/6")
    (check-next-stream-line-equal _test-output-stream "$bar:loop:"              "F - test-convert-function-with-branches-in-named-block/7")
    (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/8")
    (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-in-named-block/9")
    (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:break/disp32"  "F - test-convert-function-with-branches-in-named-block/10")
    (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/11")
    (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-in-named-block/12")
    (check-next-stream-line-equal _test-output-stream "        0f 83/jump-if-addr>= break/disp32"  "F - test-convert-function-with-branches-in-named-block/13")
    (check-next-stream-line-equal _test-output-stream "        e9/jump $bar:loop/disp32"  "F - test-convert-function-with-branches-in-named-block/14")
    (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-in-named-block/15")
    (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0x00000008)"  "F - test-convert-function-with-branches-in-named-block/16")
    (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"   "F - test-convert-function-with-branches-in-named-block/17")
    (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-in-named-block/18")
    (check-next-stream-line-equal _test-output-stream "$bar:break:"             "F - test-convert-function-with-branches-in-named-block/19")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-in-named-block/20")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-in-named-block/21")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-in-named-block/22")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-in-named-block/23")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-in-named-block/24")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-in-named-block/25")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-with-var-in-nested-block:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo x: int {\n")
    (write _test-input-stream "  {\n")
    (write _test-input-stream "    {\n")
    (write _test-input-stream "      var x: int\n")
    (write _test-input-stream "      increment x\n")
    (write _test-input-stream "    }\n")
    (write _test-input-stream "  }\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-var-in-nested-block/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-var-in-nested-block/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-var-in-nested-block/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-var-in-nested-block/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-var-in-nested-block/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-var-in-nested-block/5")
    (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-var-in-nested-block/6")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-var-in-nested-block/7")
    (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-var-in-nested-block/8")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-var-in-nested-block/9")
    (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-var-in-nested-block/10")
    (check-next-stream-line-equal _test-output-stream "        ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-var-in-nested-block/11")
    (check-next-stream-line-equal _test-output-stream "        81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-var-in-nested-block/12")
    (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-var-in-nested-block/13")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-var-in-nested-block/14")
    (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-var-in-nested-block/15")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-var-in-nested-block/16")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-var-in-nested-block/17")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-var-in-nested-block/18")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-var-in-nested-block/19")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-var-in-nested-block/20")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-var-in-nested-block/21")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-var-in-nested-block/22")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-with-multiple-vars-in-nested-blocks:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo x: int {\n")
    (write _test-input-stream "  {\n")
    (write _test-input-stream "    var x/eax: int <- copy 0\n")
    (write _test-input-stream "    {\n")
    (write _test-input-stream "      var y: int\n")
    (write _test-input-stream "      x <- add y\n")
    (write _test-input-stream "    }\n")
    (write _test-input-stream "  }\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-multiple-vars-in-nested-blocks/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-multiple-vars-in-nested-blocks/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/5")
    (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/6")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/7")
    (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %eax"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/8")
    (check-next-stream-line-equal _test-output-stream "      b8/copy-to-eax 0/imm32"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/9")
    (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/10")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/11")
    (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-multiple-vars-in-nested-blocks/12")
    (check-next-stream-line-equal _test-output-stream "        03/add *(ebp+0xfffffff8) 0x00000000/r32"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/13")
    (check-next-stream-line-equal _test-output-stream "        81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/14")
    (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-multiple-vars-in-nested-blocks/15")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/16")
    (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %eax"   "F - test-convert-function-with-multiple-vars-in-nested-blocks/17")
    (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-multiple-vars-in-nested-blocks/18")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/19")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-multiple-vars-in-nested-blocks/20")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/21")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-multiple-vars-in-nested-blocks/22")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-multiple-vars-in-nested-blocks/23")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-multiple-vars-in-nested-blocks/24")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-multiple-vars-in-nested-blocks/25")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-with-branches-and-local-vars:
    # A conditional 'break' after a 'var' in a block is converted into a
    # nested block that performs all necessary cleanup before jumping. This
    # results in some ugly code duplication.
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  {\n")
    (write _test-input-stream "    var x: int\n")
    (write _test-input-stream "    break-if->=\n")
    (write _test-input-stream "    increment x\n")
    (write _test-input-stream "  }\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-local-vars/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-local-vars/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-local-vars/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-and-local-vars/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-local-vars/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-local-vars/5")
    (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-local-vars/6")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-local-vars/7")
    (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-local-vars/8")
    (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-local-vars/9")
    (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-and-local-vars/10")
    (check-next-stream-line-equal _test-output-stream "        81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-branches-and-local-vars/11")
    (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-and-local-vars/12")
    (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-local-vars/13")
    (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-branches-and-local-vars/14")
    (check-next-stream-line-equal _test-output-stream "      81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-branches-and-local-vars/15")
    (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-local-vars/16")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-local-vars/17")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-local-vars/18")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-local-vars/19")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-local-vars/20")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-and-local-vars/21")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-local-vars/22")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-local-vars/23")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-with-conditional-loops-and-local-vars:
    # A conditional 'loop' after a 'var' in a block is converted into a nested
    # block that performs all necessary cleanup before jumping. This results
    # in some ugly code duplication.
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  {\n")
    (write _test-input-stream "    var x: int\n")
    (write _test-input-stream "    loop-if->=\n")
    (write _test-input-stream "    increment x\n")
    (write _test-input-stream "  }\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-conditional-loops-and-local-vars/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-conditional-loops-and-local-vars/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-conditional-loops-and-local-vars/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-conditional-loops-and-local-vars/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-conditional-loops-and-local-vars/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/5")
    (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-conditional-loops-and-local-vars/6")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-conditional-loops-and-local-vars/7")
    (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-conditional-loops-and-local-vars/8")
    (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-conditional-loops-and-local-vars/9")
    (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-conditional-loops-and-local-vars/10")
    (check-next-stream-line-equal _test-output-stream "        81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-conditional-loops-and-local-vars/11")
    (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:loop/disp32"  "F - test-convert-function-with-conditional-loops-and-local-vars/12")
    (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-conditional-loops-and-local-vars/13")
    (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-conditional-loops-and-local-vars/14")
    (check-next-stream-line-equal _test-output-stream "      81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-conditional-loops-and-local-vars/15")
    (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-conditional-loops-and-local-vars/16")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/17")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-conditional-loops-and-local-vars/18")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-conditional-loops-and-local-vars/19")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-conditional-loops-and-local-vars/20")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-conditional-loops-and-local-vars/21")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-conditional-loops-and-local-vars/22")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-conditional-loops-and-local-vars/23")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-with-unconditional-loops-and-local-vars:
    # An unconditional 'loop' after a 'var' in a block is emitted _after_ the
    # regular block cleanup. Any instructions after 'loop' are dead and
    # therefore skipped.
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  {\n")
    (write _test-input-stream "    var x: int\n")
    (write _test-input-stream "    loop\n")
    (write _test-input-stream "    increment x\n")
    (write _test-input-stream "  }\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-loops-and-local-vars/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-loops-and-local-vars/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/5")
    (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/6")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-loops-and-local-vars/7")
    (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-loops-and-local-vars/8")
    (check-next-stream-line-equal _test-output-stream "      81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-unconditional-loops-and-local-vars/9")
    (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-unconditional-loops-and-local-vars/10")
    # not emitted:                                           ff 0/subop/increment *(ebp+0xfffffffc)
    (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-loops-and-local-vars/11")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/12")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-loops-and-local-vars/13")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-loops-and-local-vars/14")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-loops-and-local-vars/15")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-loops-and-local-vars/16")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-loops-and-local-vars/17")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-loops-and-local-vars/18")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-with-branches-and-loops-and-local-vars:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  {\n")
    (write _test-input-stream "    var x: int\n")
    (write _test-input-stream "    break-if->=\n")
    (write _test-input-stream "    increment x\n")
    (write _test-input-stream "    loop\n")
    (write _test-input-stream "  }\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-branches-and-loops-and-local-vars/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-branches-and-loops-and-local-vars/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-branches-and-loops-and-local-vars/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/5")
    (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/6")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-branches-and-loops-and-local-vars/7")
    (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-branches-and-loops-and-local-vars/8")
    (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/9")
    (check-next-stream-line-equal _test-output-stream "        0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-branches-and-loops-and-local-vars/10")
    (check-next-stream-line-equal _test-output-stream "        81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-branches-and-loops-and-local-vars/11")
    (check-next-stream-line-equal _test-output-stream "        e9/jump $foo:0x00000002:break/disp32"  "F - test-convert-function-with-branches-and-loops-and-local-vars/12")
    (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-branches-and-loops-and-local-vars/13")
    (check-next-stream-line-equal _test-output-stream "      ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-branches-and-loops-and-local-vars/14")
    (check-next-stream-line-equal _test-output-stream "      81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-branches-and-loops-and-local-vars/15")
    (check-next-stream-line-equal _test-output-stream "      e9/jump loop/disp32"  "F - test-convert-function-with-branches-and-loops-and-local-vars/16")
    (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-branches-and-loops-and-local-vars/17")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/18")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-branches-and-loops-and-local-vars/19")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-branches-and-loops-and-local-vars/20")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-branches-and-loops-and-local-vars/21")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-branches-and-loops-and-local-vars/22")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-branches-and-loops-and-local-vars/23")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-branches-and-loops-and-local-vars/24")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-with-nonlocal-branches-and-loops-and-local-vars:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  a: {\n")
    (write _test-input-stream "    var x: int\n")
    (write _test-input-stream "    {\n")
    (write _test-input-stream "      var y: int\n")
    (write _test-input-stream "      break-if->= a\n")
    (write _test-input-stream "      increment x\n")
    (write _test-input-stream "      loop\n")
    (write _test-input-stream "    }\n")
    (write _test-input-stream "  }\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/5")
    (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/6")
    (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/7")
    (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/8")
    (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/9")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/10")
    (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/11")
    (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/12")
    (check-next-stream-line-equal _test-output-stream "          0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/13")
    (check-next-stream-line-equal _test-output-stream "          81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/14")
    (check-next-stream-line-equal _test-output-stream "          81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/15")
    (check-next-stream-line-equal _test-output-stream "          e9/jump a:break/disp32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/16")
    (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/17")
    (check-next-stream-line-equal _test-output-stream "        ff 0/subop/increment *(ebp+0xfffffffc)"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/18")
    (check-next-stream-line-equal _test-output-stream "        81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/19")
    (check-next-stream-line-equal _test-output-stream "        e9/jump loop/disp32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/20")
    (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/21")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/22")
    (check-next-stream-line-equal _test-output-stream "      81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/23")
    (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/24")
    (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/25")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/26")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/27")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/28")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/29")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/30")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars/31")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    # non-local conditional branch from a block without a local variable,
    # unwinding a local on the stack
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  a: {\n")
    (write _test-input-stream "    var x: int\n")
    (write _test-input-stream "    {\n")
    (write _test-input-stream "      break-if->= a\n")
    (write _test-input-stream "    }\n")
    (write _test-input-stream "  }\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/5")
    (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/6")
    (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/7")
    (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/8")
    (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/9")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/10")
    (check-next-stream-line-equal _test-output-stream "        {"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/11")
    (check-next-stream-line-equal _test-output-stream "          0f 8c/jump-if-< break/disp32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/12")
    (check-next-stream-line-equal _test-output-stream "          81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/13")
    (check-next-stream-line-equal _test-output-stream "          e9/jump a:break/disp32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/14")
    (check-next-stream-line-equal _test-output-stream "        }"               "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/15")
    (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/16")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/17")
    (check-next-stream-line-equal _test-output-stream "      81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/18")
    (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/19")
    (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/20")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/21")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/22")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/23")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/24")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/25")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-2/26")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    # non-local unconditional branch from a block without a local variable,
    # unwinding a local on the stack
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  a: {\n")
    (write _test-input-stream "    var x: int\n")
    (write _test-input-stream "    {\n")
    (write _test-input-stream "      break a\n")
    (write _test-input-stream "    }\n")
    (write _test-input-stream "  }\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/5")
    (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/6")
    (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/7")
    (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/8")
    (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/9")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/10")
    (check-next-stream-line-equal _test-output-stream "        81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/11")
    (check-next-stream-line-equal _test-output-stream "        e9/jump a:break/disp32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/12")
    (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/14")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/15")
    (check-next-stream-line-equal _test-output-stream "      81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/16")
    (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/17")
    (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/18")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/19")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/20")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/21")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/22")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/23")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-3/24")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  a: {\n")
    (write _test-input-stream "    var x/esi: int <- copy 0\n")
    (write _test-input-stream "    {\n")
    (write _test-input-stream "      break a\n")
    (write _test-input-stream "    }\n")
    (write _test-input-stream "  }\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/5")
    (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/6")
    (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/7")
    (check-next-stream-line-equal _test-output-stream "      ff 6/subop/push %esi"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/8")
    (check-next-stream-line-equal _test-output-stream "      be/copy-to-esi 0/imm32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/9")
    (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/10")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/11")
    (check-next-stream-line-equal _test-output-stream "        8f 0/subop/pop %esi"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/12")
    (check-next-stream-line-equal _test-output-stream "        e9/jump a:break/disp32"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/13")
    (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/14")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/15")
    (check-next-stream-line-equal _test-output-stream "      8f 0/subop/pop %esi"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/16")
    (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/17")
    (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/18")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/19")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/20")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/21")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/22")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/23")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-branches-and-loops-and-local-vars-4/24")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-with-nonlocal-unconditional-break-and-local-vars:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  a: {\n")
    (write _test-input-stream "    var x: int\n")
    (write _test-input-stream "    {\n")
    (write _test-input-stream "      var y: int\n")
    (write _test-input-stream "      break a\n")
    (write _test-input-stream "      increment x\n")
    (write _test-input-stream "    }\n")
    (write _test-input-stream "  }\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/5")
    (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/6")
    (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/7")
    (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/8")
    (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/9")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/10")
    (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/11")
    (check-next-stream-line-equal _test-output-stream "        81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/12")
    (check-next-stream-line-equal _test-output-stream "        81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/13")
    (check-next-stream-line-equal _test-output-stream "        e9/jump a:break/disp32"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/14")
    (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/15")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/16")
    (check-next-stream-line-equal _test-output-stream "      81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/17")
    (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/18")
    (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/19")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/20")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/21")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/22")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/23")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/24")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-break-and-local-vars/25")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-with-unconditional-break-and-local-vars:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  {\n")
    (write _test-input-stream "    var x: int\n")
    (write _test-input-stream "    {\n")
    (write _test-input-stream "      var y: int\n")
    (write _test-input-stream "      break\n")
    (write _test-input-stream "      increment x\n")
    (write _test-input-stream "    }\n")
    (write _test-input-stream "  }\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-unconditional-break-and-local-vars/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-unconditional-break-and-local-vars/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-unconditional-break-and-local-vars/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-unconditional-break-and-local-vars/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-unconditional-break-and-local-vars/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/5")
    (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-unconditional-break-and-local-vars/6")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/7")
    (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-unconditional-break-and-local-vars/8")
    (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-unconditional-break-and-local-vars/9")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-unconditional-break-and-local-vars/10")
    (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-unconditional-break-and-local-vars/11")
    (check-next-stream-line-equal _test-output-stream "        81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-unconditional-break-and-local-vars/12")
    (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-unconditional-break-and-local-vars/13")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/14")
    (check-next-stream-line-equal _test-output-stream "      81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-unconditional-break-and-local-vars/15")
    (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-unconditional-break-and-local-vars/16")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/17")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-unconditional-break-and-local-vars/18")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-unconditional-break-and-local-vars/19")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-unconditional-break-and-local-vars/20")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-unconditional-break-and-local-vars/21")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-unconditional-break-and-local-vars/22")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-unconditional-break-and-local-vars/23")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-with-nonlocal-unconditional-loop-and-local-vars:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  a: {\n")
    (write _test-input-stream "    var x: int\n")
    (write _test-input-stream "    {\n")
    (write _test-input-stream "      var y: int\n")
    (write _test-input-stream "      loop a\n")
    (write _test-input-stream "      increment x\n")
    (write _test-input-stream "    }\n")
    (write _test-input-stream "  }\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/5")
    (check-next-stream-line-equal _test-output-stream "    {"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/6")
    (check-next-stream-line-equal _test-output-stream "a:loop:"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/7")
    (check-next-stream-line-equal _test-output-stream "      68/push 0/imm32"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/8")
    (check-next-stream-line-equal _test-output-stream "      {"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/9")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:loop:"   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/10")
    (check-next-stream-line-equal _test-output-stream "        68/push 0/imm32" "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/11")
    (check-next-stream-line-equal _test-output-stream "        81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/12")
    (check-next-stream-line-equal _test-output-stream "        81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/13")
    (check-next-stream-line-equal _test-output-stream "        e9/jump a:loop/disp32"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/14")
    (check-next-stream-line-equal _test-output-stream "      }"                 "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/15")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000003:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/16")
    (check-next-stream-line-equal _test-output-stream "      81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/17")
    (check-next-stream-line-equal _test-output-stream "    }"                   "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/18")
    (check-next-stream-line-equal _test-output-stream "a:break:"                "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/19")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/20")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/21")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/22")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/23")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/24")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-nonlocal-unconditional-loop-and-local-vars/25")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-with-local-array-var-in-mem:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var x: (array int 3)\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-var-in-mem/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-var-in-mem/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-var-in-mem/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-array-var-in-mem/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-var-in-mem/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-var-in-mem/5")
    # define x
    (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-function-with-local-array-var-in-mem/7")
    (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-function-with-local-array-var-in-mem/8")
    # reclaim x
    (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"  "F - test-convert-function-with-local-array-var-in-mem/9")
    #
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-var-in-mem/10")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-var-in-mem/11")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-var-in-mem/12")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-array-var-in-mem/13")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-var-in-mem/14")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-var-in-mem/15")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-array-size-in-hex:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var x: (array int 10)\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-array-size-in-hex: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "literal integers are always hex in Mu; either start '10' with a '0x' to be unambiguous, or convert it to decimal."  "F - test-array-size-in-hex: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-array-size-in-hex: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-convert-function-with-populate:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var x/ecx: (addr handle array int) <- copy 0\n")
    (write _test-input-stream "  populate x, 7\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-populate/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-populate/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-populate/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-populate/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-populate/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-populate/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-with-populate/6")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0/imm32"  "F - test-convert-function-with-populate/7")
    (check-next-stream-line-equal _test-output-stream "    (allocate-array2 Heap 0x00000004 7 %ecx)"  "F - test-convert-function-with-populate/8")  # 4 = size-of(int)
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-with-populate/9")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-populate/10")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-populate/11")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-populate/12")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-populate/13")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-populate/14")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-populate/15")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# special-case for size(byte) when allocating array
test-convert-function-with-local-array-of-bytes-in-mem:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var x: (array byte 3)\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-array-of-bytes-in-mem/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-array-of-bytes-in-mem/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-array-of-bytes-in-mem/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-array-of-bytes-in-mem/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-array-of-bytes-in-mem/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-array-of-bytes-in-mem/5")
    # define x
    (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x00000003)"  "F - test-convert-function-with-local-array-of-bytes-in-mem/7")
    (check-next-stream-line-equal _test-output-stream "    68/push 0x00000003/imm32"  "F - test-convert-function-with-local-array-of-bytes-in-mem/8")
    # reclaim x
    (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000007/imm32"  "F - test-convert-function-with-local-array-of-bytes-in-mem/9")
    #
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-array-of-bytes-in-mem/10")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-array-of-bytes-in-mem/11")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-array-of-bytes-in-mem/12")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-array-of-bytes-in-mem/13")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-array-of-bytes-in-mem/14")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-array-of-bytes-in-mem/15")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-address:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: int\n")
    (write _test-input-stream "  var b/eax: (addr int) <- address a\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-address/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-address/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-address/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-address/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-address/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-address/5")
    (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-address/6")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-address/7")
    (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000000/r32"  "F - test-convert-address/8")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-address/9")
    (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-address/10")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-address/11")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-address/12")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-address/13")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-address/14")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-address/15")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-address/16")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-length-of-array:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo a: (addr array int) {\n")
    (write _test-input-stream "  var b/eax: (addr array int) <- copy a\n")
    (write _test-input-stream "  var c/eax: int <- length b\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array/6")
    (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array/7")
    (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array/8")
    (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array/9")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array/10")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array/11")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array/12")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array/13")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array/14")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array/15")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array/16")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# special-case for size(byte) when computing array length
test-convert-length-of-array-of-bytes:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo a: (addr array byte) {\n")
    (write _test-input-stream "  var b/eax: (addr array byte) <- copy a\n")
    (write _test-input-stream "  var c/eax: int <- length b\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-bytes/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-bytes/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-bytes/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-bytes/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-bytes/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-bytes/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-bytes/6")
    (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-length-of-array-of-bytes/7")
    (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-bytes/8")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-bytes/9")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-bytes/10")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-bytes/11")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-bytes/12")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-bytes/13")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-bytes/14")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-bytes/15")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-length-of-array-on-stack:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: (array int 3)\n")
    (write _test-input-stream "  var b/eax: int <- length a\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-on-stack/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-on-stack/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-on-stack/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-on-stack/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-on-stack/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-on-stack/5")
    # define x
    (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"  "F - test-convert-length-of-array-on-stack/6")
    (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"  "F - test-convert-length-of-array-on-stack/7")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-on-stack/8")
    (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0xfffffff0) 0x00000000/r32"  "F - test-convert-length-of-array-on-stack/9")
    (check-next-stream-line-equal _test-output-stream "    c1/shift 5/subop/>> %eax 0x00000002/imm8"  "F - test-convert-length-of-array-on-stack/10")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-on-stack/11")
    (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"  "F - test-convert-length-of-array-on-stack/12")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-on-stack/13")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-on-stack/14")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-on-stack/15")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-on-stack/16")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-on-stack/17")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-on-stack/18")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-reg-var-def-with-read-of-same-register:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)  # bytes of args in call to convert-mu
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
    (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
    (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp could be clobbered at this point (though they shouldn't be)
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    (check-stream-equal _test-error-stream  ""  "F - test-reg-var-def-with-read-of-same-register: error stream should be empty")
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-reg-var-def-with-read-of-same-register/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-reg-var-def-with-read-of-same-register/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-reg-var-def-with-read-of-same-register/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-reg-var-def-with-read-of-same-register/3")
    (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-reg-var-def-with-read-of-same-register/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-reg-var-def-with-read-of-same-register/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-reg-var-def-with-read-of-same-register/6")
    (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-reg-var-def-with-read-of-same-register/7")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-reg-var-def-with-read-of-same-register/8")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-reg-var-def-with-read-of-same-register/9")
    (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32"  "F - test-reg-var-def-with-read-of-same-register/11")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-reg-var-def-with-read-of-same-register/13")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-reg-var-def-with-read-of-same-register/14")
    (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-reg-var-def-with-read-of-same-register/15")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-reg-var-def-with-read-of-same-register/16")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-reg-var-def-with-read-of-same-register/17")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-reg-var-def-with-read-of-same-register/18")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-reg-var-def-with-read-of-same-register/19")
    (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-reg-var-def-with-read-of-same-register/20")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-convert-index-into-array:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
    (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
    (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array/3")
    (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array/6")
    (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array/7")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array/8")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array/9")
    (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32"  "F - test-convert-index-into-array/10")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array/11")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array/12")
    (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array/13")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array/14")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array/15")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array/16")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array/17")
    (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array/18")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-index-into-array-of-bytes:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
    (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
    (write _test-input-stream "  var x/eax: (addr byte) <- index arr, idx\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes/3")
    (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes/6")
    (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-of-bytes/7")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes/8")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-of-bytes/9")
    (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx<<0x00000000 + 4) 0x00000000/r32"  "F - test-convert-index-into-array-of-bytes/11")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes/13")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes/14")
    (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes/15")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes/16")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes/17")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes/18")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes/19")
    (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes/20")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-index-into-array-with-literal:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
    (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-with-literal/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-with-literal/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-with-literal/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-with-literal/3")
    (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-with-literal/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-with-literal/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-with-literal/6")
    (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-with-literal/7")
                                                                                 # 2 * 4 bytes/elem + 4 bytes for size = offset 12
    (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x0000000c) 0x00000000/r32"  "F - test-convert-index-into-array-with-literal/8")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-with-literal/9")
    (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-with-literal/10")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-with-literal/11")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-with-literal/12")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-with-literal/13")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-with-literal/14")
    (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-with-literal/15")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-index-into-array-of-bytes-with-literal:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
    (write _test-input-stream "  var x/eax: (addr byte) <- index arr, 2\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-with-literal/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-with-literal/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-with-literal/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-with-literal/3")
    (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-with-literal/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-with-literal/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-with-literal/6")
    (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-of-bytes-with-literal/7")
                                                                                 # 2 * 1 byte/elem + 4 bytes for size = offset 6
    (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000006) 0x00000000/r32"  "F - test-convert-index-into-array-of-bytes-with-literal/8")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-with-literal/9")
    (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-with-literal/10")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-with-literal/11")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-with-literal/12")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-with-literal/13")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-with-literal/14")
    (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-with-literal/15")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-index-into-array-on-stack:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var arr: (array int 3)\n")
    (write _test-input-stream "  var idx/eax: int <- copy 2\n")
    (write _test-input-stream "  var x/eax: (addr int) <- index arr, idx\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack/3")
    (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack/5")
    # var arr
    (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack/6")
    (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack/7")
    # var idx
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack/8")
    (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 2/imm32"                  "F - test-convert-index-into-array-on-stack/9")
    # var x is at (ebp-0x10) + idx<<2 + 4 = ebp + idx<<2 - 0xc
    (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp + eax<<0x00000002 + 0xfffffff4) 0x00000000/r32"  "F - test-convert-index-into-array-on-stack/10")
    # reclaim idx
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack/11")
    # reclaim arr
    (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"    "F - test-convert-index-into-array-on-stack/12")
    #
    (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack/13")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack/14")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack/15")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack/16")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack/17")
    (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack/18")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-index-into-array-on-stack-with-literal:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var arr: (array int 3)\n")
    (write _test-input-stream "  var x/eax: (addr int) <- index arr, 2\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-on-stack-with-literal/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-on-stack-with-literal/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-on-stack-with-literal/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-on-stack-with-literal/3")
    (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-on-stack-with-literal/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-on-stack-with-literal/5")
    # var arr
    (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x0000000c)"          "F - test-convert-index-into-array-on-stack-with-literal/6")
    (check-next-stream-line-equal _test-output-stream "    68/push 0x0000000c/imm32"                "F - test-convert-index-into-array-on-stack-with-literal/7")
    # var x
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-on-stack-with-literal/8")
    # x is at (ebp-0x10) + 4 + 2*4 = ebp-4
    (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp + 0xfffffffc) 0x00000000/r32"  "F - test-convert-index-into-array-on-stack-with-literal/9")
    # reclaim x
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-on-stack-with-literal/10")
    # reclaim arr
    (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000010/imm32"    "F - test-convert-index-into-array-on-stack-with-literal/11")
    #
    (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-on-stack-with-literal/12")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-on-stack-with-literal/13")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-on-stack-with-literal/14")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-on-stack-with-literal/15")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-on-stack-with-literal/16")
    (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-on-stack-with-literal/17")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-index-into-array-of-bytes-on-stack-with-literal:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var arr: (array byte 3)\n")
    (write _test-input-stream "  var x/eax: (addr byte) <- index arr, 2\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/3")
    (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/5")
    # var arr
    (check-next-stream-line-equal _test-output-stream "    (push-n-zero-bytes 0x00000003)"          "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/6")
    (check-next-stream-line-equal _test-output-stream "    68/push 0x00000003/imm32"                "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/7")
    # var x
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/8")
    # x is at (ebp-7) + 4 + 2 = ebp-1
    (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp + 0xffffffff) 0x00000000/r32"  "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/9")
    # reclaim x
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/10")
    # reclaim arr
    (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000007/imm32"    "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/11")
    #
    (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/12")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/13")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/14")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/15")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/16")
    (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/17")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-index-into-array-using-offset:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
    (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
    (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
    (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset/3")
    (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset/6")
    (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-using-offset/7")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset/8")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-using-offset/9")
    (check-next-stream-line-equal _test-output-stream "    69/multiply %ecx 0x00000004/imm32 0x00000001/r32"  "F - test-convert-index-into-array-using-offset/10")
    (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx + 4) 0x00000000/r32"  "F - test-convert-index-into-array-using-offset/11")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset/12")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset/13")
    (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset/14")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset/15")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset/16")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset/17")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset/18")
    (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset/19")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-index-into-array-of-bytes-using-offset:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
    (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
    (write _test-input-stream "  var off/ecx: (offset byte) <- compute-offset arr, idx\n")
    (write _test-input-stream "  var x/eax: (addr byte) <- index arr, off\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-using-offset/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-using-offset/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-using-offset/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-using-offset/3")
    (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-using-offset/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-using-offset/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-using-offset/6")
    (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-of-bytes-using-offset/7")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes-using-offset/8")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-index-into-array-of-bytes-using-offset/9")
    (check-next-stream-line-equal _test-output-stream "    69/multiply %ecx 0x00000001/imm32 0x00000001/r32"  "F - test-convert-index-into-array-of-bytes-using-offset/10")
    (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx + 4) 0x00000000/r32"  "F - test-convert-index-into-array-of-bytes-using-offset/11")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes-using-offset/12")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-using-offset/13")
    (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-using-offset/14")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-using-offset/15")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-using-offset/16")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-using-offset/17")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-using-offset/18")
    (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-using-offset/19")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-index-into-array-using-offset-on-stack:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var arr/eax: (addr array int) <- copy 0\n")
    (write _test-input-stream "  var idx: int\n")
    (write _test-input-stream "  var off/ecx: (offset int) <- compute-offset arr, idx\n")
    (write _test-input-stream "  var x/eax: (addr int) <- index arr, off\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-using-offset-on-stack/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-using-offset-on-stack/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-using-offset-on-stack/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-using-offset-on-stack/3")
    (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-using-offset-on-stack/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-using-offset-on-stack/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-using-offset-on-stack/6")
    (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-using-offset-on-stack/7")
    (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"                         "F - test-convert-index-into-array-using-offset-on-stack/8")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-using-offset-on-stack/9")
    (check-next-stream-line-equal _test-output-stream "    69/multiply *(ebp+0xfffffff8) 0x00000004/imm32 0x00000001/r32"  "F - test-convert-index-into-array-using-offset-on-stack/10")
    (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx + 4) 0x00000000/r32"  "F - test-convert-index-into-array-using-offset-on-stack/11")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-using-offset-on-stack/12")
    (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"    "F - test-convert-index-into-array-using-offset-on-stack/13")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-using-offset-on-stack/14")
    (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-using-offset-on-stack/15")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-using-offset-on-stack/16")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-using-offset-on-stack/17")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-using-offset-on-stack/18")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-using-offset-on-stack/19")
    (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-using-offset-on-stack/20")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-index-into-array-of-bytes-using-offset-on-stack:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var arr/eax: (addr array byte) <- copy 0\n")
    (write _test-input-stream "  var idx: int\n")
    (write _test-input-stream "  var off/ecx: (offset byte) <- compute-offset arr, idx\n")
    (write _test-input-stream "  var x/eax: (addr byte) <- index arr, off\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/3")
    (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/6")
    (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/7")
    (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/8")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/9")
    (check-next-stream-line-equal _test-output-stream "    69/multiply *(ebp+0xfffffff8) 0x00000001/imm32 0x00000001/r32"  "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/10")
    (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx + 4) 0x00000000/r32"  "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/11")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/12")
    (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"    "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/13")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/14")
    (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/15")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/16")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/17")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/18")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/19")
    (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/20")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-and-type-definition:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo a: (addr t) {\n")
    (write _test-input-stream "  var _a/eax: (addr t) <- copy a\n")
    (write _test-input-stream "  var b/ecx: (addr int) <- get _a, x\n")
    (write _test-input-stream "  var c/ecx: (addr int) <- get _a, y\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "type t {\n")
    (write _test-input-stream "  x: int\n")
    (write _test-input-stream "  y: int\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-and-type-definition/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-and-type-definition/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-and-type-definition/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-and-type-definition/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-and-type-definition/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-and-type-definition/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-and-type-definition/6")
    (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000000/r32"  "F - test-convert-function-and-type-definition/7")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-and-type-definition/8")
    (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000000) 0x00000001/r32"  "F - test-convert-function-and-type-definition/9")
    (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + 0x00000004) 0x00000001/r32"  "F - test-convert-function-and-type-definition/11")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-and-type-definition/13")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-convert-function-and-type-definition/14")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-and-type-definition/15")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-and-type-definition/16")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-and-type-definition/17")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-and-type-definition/18")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-and-type-definition/19")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-and-type-definition/20")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-type-definition-with-array:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "type t {\n")
    (write _test-input-stream "  a: (array int 3)\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-type-definition-with-array: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "type t: 'array' elements not allowed for now"  "F - test-type-definition-with-array: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-type-definition-with-array: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-type-definition-with-addr:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "type t {\n")
    (write _test-input-stream "  a: (addr int)\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-type-definition-with-addr: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "type t: 'addr' elements not allowed"  "F - test-type-definition-with-addr: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-type-definition-with-addr: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-convert-function-with-local-var-with-user-defined-type:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: t\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "type t {\n")
    (write _test-input-stream "  x: int\n")
    (write _test-input-stream "  y: int\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-user-defined-type/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-user-defined-type/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-user-defined-type/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-with-user-defined-type/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-user-defined-type/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-user-defined-type/5")
    (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/6")
    (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type/7")
    (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000008/imm32"  "F - test-convert-function-with-local-var-with-user-defined-type/8")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-user-defined-type/9")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-user-defined-type/10")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-user-defined-type/11")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-with-user-defined-type/12")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-with-user-defined-type/13")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-user-defined-type/14")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: t\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "type t {\n")
    (write _test-input-stream "  x: s\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "type s {\n")
    (write _test-input-stream "  z: int\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/5")
    (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/7")
    (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000004/imm32"  "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/8")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/9")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/10")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/11")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/12")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/13")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-with-local-var-with-user-defined-type-containing-user-defined-type/14")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-call-with-arg-of-user-defined-type:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn f {\n")
    (write _test-input-stream "  var a: t\n")
    (write _test-input-stream "  foo a\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "fn foo x: t {\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "type t {\n")
    (write _test-input-stream "  x: int\n")
    (write _test-input-stream "  y: int\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-arg-of-user-defined-type/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
    (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
    # var a: t
    (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/6")
    (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type/7")
    # foo a
    (check-next-stream-line-equal _test-output-stream "    (foo *(ebp+0xfffffff8) *(ebp+0xfffffffc))"  "F - test-convert-function-call-with-arg-of-user-defined-type/8")
    #
    (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000008/imm32"  "F - test-convert-function-call-with-arg-of-user-defined-type/9")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
    (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-arg-of-user-defined-type/13")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-arg-of-user-defined-type/19")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-arg-of-user-defined-type/21")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-function-call-with-arg-of-user-defined-type-register-indirect:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn f {\n")
    (write _test-input-stream "  var a/eax: (addr t) <- copy 0\n")
    (write _test-input-stream "  foo *a\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "fn foo x: t {\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "type t {\n")
    (write _test-input-stream "  x: int\n")
    (write _test-input-stream "  y: int\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-arg-of-user-defined-type/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type/4")
    (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type/5")
    # var a
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-call-with-arg-of-user-defined-type/6")
    (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"  "F - test-convert-function-call-with-arg-of-user-defined-type/7")
    # foo a
    (check-next-stream-line-equal _test-output-stream "    (foo *(eax+0x00000000) *(eax+0x00000004))"  "F - test-convert-function-call-with-arg-of-user-defined-type/8")
    #
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-convert-function-call-with-arg-of-user-defined-type/9")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type/10")
    (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type/11")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/12")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-arg-of-user-defined-type/13")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/14")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/15")
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type/16")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type/17")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type/18")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-arg-of-user-defined-type/19")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type/20")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-arg-of-user-defined-type/21")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type/22")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type/23")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# we don't have special support for call-by-reference; just explicitly create
# a new variable with the address of the arg
test-convert-function-call-with-arg-of-user-defined-type-by-reference:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn f {\n")
    (write _test-input-stream "  var a: t\n")
    (write _test-input-stream "  var b/eax: (addr t) <- address a\n")
    (write _test-input-stream "  foo b\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "fn foo x: (addr t) {\n")
    (write _test-input-stream "  var x/ecx: (addr int) <- copy x\n")
    (write _test-input-stream "  increment *x\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "type t {\n")
    (write _test-input-stream "  x: int\n")
    (write _test-input-stream "  y: int\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "f:"                      "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/4")
    (check-next-stream-line-equal _test-output-stream "$f:0x00000001:loop:"     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/5")
    # var a: t
    (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/6")
    (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/7")
    # var b/eax: (addr t)
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/8")
    (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffff8) 0x00000000/r32"  "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/9")
    # foo a
    (check-next-stream-line-equal _test-output-stream "    (foo %eax)"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/10")
    #
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/11")
    (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000008/imm32"  "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/12")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/13")
    (check-next-stream-line-equal _test-output-stream "$f:0x00000001:break:"    "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/14")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/15")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/16")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/17")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/18")
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/19")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/20")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/21")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/22")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/23")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:loop:"   "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/24")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/25")
    (check-next-stream-line-equal _test-output-stream "    8b/-> *(ebp+0x00000008) 0x00000001/r32"  "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/26")
    (check-next-stream-line-equal _test-output-stream "    ff 0/subop/increment *ecx"  "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/27")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/28")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/29")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000002:break:"  "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/30")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/31")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/32")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/33")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-function-call-with-arg-of-user-defined-type-by-reference/34")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-get-on-local-variable:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: t\n")
    (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "type t {\n")
    (write _test-input-stream "  x: int\n")
    (write _test-input-stream "  y: int\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-local-variable/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-local-variable/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-local-variable/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-local-variable/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-local-variable/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-local-variable/5")
    # var a
    (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/6")
    (check-next-stream-line-equal _test-output-stream "    68/push 0/imm32"     "F - test-convert-get-on-local-variable/7")
    # var c
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-local-variable/8")
    # get
    (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0xfffffffc) 0x00000001/r32"  "F - test-convert-get-on-local-variable/9")
    # reclaim c
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-local-variable/10")
    # reclaim a
    (check-next-stream-line-equal _test-output-stream "    81 0/subop/add %esp 0x00000008/imm32"  "F - test-convert-get-on-local-variable/11")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-local-variable/12")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-local-variable/13")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-local-variable/14")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-local-variable/15")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-local-variable/16")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-local-variable/17")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-get-on-function-argument:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo a: t {\n")
    (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "type t {\n")
    (write _test-input-stream "  x: int\n")
    (write _test-input-stream "  y: int\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument/5")
    # var c
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument/6")
    # get
    (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0x0000000c) 0x00000001/r32"  "F - test-convert-get-on-function-argument/7")
    # reclaim c
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument/8")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument/9")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument/10")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument/11")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument/12")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument/13")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument/14")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-get-on-function-argument-with-known-type:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "type t {\n")
    (write _test-input-stream "  x: int\n")
    (write _test-input-stream "  y: int\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "fn foo a: t {\n")
    (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-get-on-function-argument-with-known-type/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-get-on-function-argument-with-known-type/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-get-on-function-argument-with-known-type/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-get-on-function-argument-with-known-type/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-get-on-function-argument-with-known-type/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-get-on-function-argument-with-known-type/5")
    # var c
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-get-on-function-argument-with-known-type/6")
    # get
    (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(ebp+0x0000000c) 0x00000001/r32"  "F - test-convert-get-on-function-argument-with-known-type/7")
    # reclaim c
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx" "F - test-convert-get-on-function-argument-with-known-type/8")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-get-on-function-argument-with-known-type/9")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-get-on-function-argument-with-known-type/10")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-get-on-function-argument-with-known-type/11")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-get-on-function-argument-with-known-type/12")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-get-on-function-argument-with-known-type/13")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-get-on-function-argument-with-known-type/14")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-add-with-too-many-inouts:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: int\n")
    (write _test-input-stream "  var b/ecx: int <- add a, 0\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-inouts: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt add: too many inouts; most primitives support at most two arguments, across inouts and outputs"  "F - test-add-with-too-many-inouts: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-inouts: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-add-with-too-many-inouts-2:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: int\n")
    (write _test-input-stream "  add-to a, 0, 1\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-inouts-2: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt add-to: too many inouts; most primitives support at most two arguments, across inouts and outputs"  "F - test-add-with-too-many-inouts-2: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-inouts-2: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-add-with-too-many-outputs:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a/eax: int <- copy 0\n")
    (write _test-input-stream "  var b/ebx: int <- copy 0\n")
    (write _test-input-stream "  var c/ecx: int <- copy 0\n")
    (write _test-input-stream "  c, b <- add a\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-add-with-too-many-outputs: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt add: too many outputs; most primitives support at most one output"  "F - test-add-with-too-many-outputs: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-add-with-too-many-outputs: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-add-with-non-number:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: int\n")
    (write _test-input-stream "  var b/ecx: (addr int) <- add a\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-add-with-non-number: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt add: only non-addr scalar args permitted"  "F - test-add-with-non-number: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-add-with-non-number: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-add-with-addr-dereferenced:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a/eax: (addr int) <- copy 0\n")
    (write _test-input-stream "  add-to *a, 1\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
    # no error
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-get-with-wrong-field:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: t\n")
    (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "type t {\n")
    (write _test-input-stream "  x: int\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-field: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: type 't' has no member called 'y'"  "F - test-get-with-wrong-field: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-field: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-get-with-wrong-base-type:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: int\n")
    (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-base-type: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: var 'a' must have a 'type' definition"  "F - test-get-with-wrong-base-type: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-base-type: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-get-with-wrong-base-type-2:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: (addr t)\n")
    (write _test-input-stream "  var c/ecx: (addr int) <- get a, y\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "type t {\n")
    (write _test-input-stream "  x: int\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-base-type-2: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: var 'a' is an 'addr' type, and so must live in a register"  "F - test-get-with-wrong-base-type-2: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-base-type-2: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-get-with-wrong-offset-type:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: t\n")
    (write _test-input-stream "  var b: int\n")
    (write _test-input-stream "  var c/ecx: (addr int) <- get a, b\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "type t {\n")
    (write _test-input-stream "  x: int\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-offset-type: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: type 't' has no member called 'b'"  "F - test-get-with-wrong-offset-type: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-offset-type: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-get-with-wrong-output-type:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: t\n")
    (write _test-input-stream "  var c: (addr int)\n")
    (write _test-input-stream "  c <- get a, x\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "type t {\n")
    (write _test-input-stream "  x: int\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: output 'c' is not in a register"  "F - test-get-with-wrong-output-type: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-get-with-wrong-output-type-2:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: t\n")
    (write _test-input-stream "  var c/ecx: int <- get a, x\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "type t {\n")
    (write _test-input-stream "  x: int\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-2: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: output must be an address"  "F - test-get-with-wrong-output-type-2: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-2: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-get-with-wrong-output-type-3:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: t\n")
    (write _test-input-stream "  var c/ecx: (array int) <- get a, x\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "type t {\n")
    (write _test-input-stream "  x: int\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-3: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: output must be an address"  "F - test-get-with-wrong-output-type-3: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-3: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-get-with-wrong-output-type-4:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: t\n")
    (write _test-input-stream "  var c/ecx: (addr boolean) <- get a, x\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "type t {\n")
    (write _test-input-stream "  x: int\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-get-with-wrong-output-type-4: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: wrong output type for member 'x' of type 't'"  "F - test-get-with-wrong-output-type-4: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-get-with-wrong-output-type-4: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-get-with-wrong-output-type-5:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: t\n")
    (write _test-input-stream "  var c/ecx: (addr handle int) <- get a, x\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "type t {\n")
    (write _test-input-stream "  x: (handle int)\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
    # no errors
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-get-with-too-few-inouts:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: t\n")
    (write _test-input-stream "  var c/ecx: (addr int) <- get a\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "type t {\n")
    (write _test-input-stream "  x: int\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-few-inouts: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: too few inouts (2 required)"  "F - test-get-with-too-few-inouts: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-get-with-too-few-inouts: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-get-with-too-many-inouts:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: t\n")
    (write _test-input-stream "  var c/ecx: (addr int) <- get a, x, 0\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "type t {\n")
    (write _test-input-stream "  x: int\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-many-inouts: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: too many inouts (2 required)"  "F - test-get-with-too-many-inouts: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-get-with-too-many-inouts: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-get-with-no-output:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: t\n")
    (write _test-input-stream "  get a, x\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "type t {\n")
    (write _test-input-stream "  x: int\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-get-with-no-output: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: must have an output"  "F - test-get-with-no-output: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-get-with-no-output: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-get-with-too-many-outputs:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: t\n")
    (write _test-input-stream "  var b: int\n")
    (write _test-input-stream "  var c/eax: (addr int) <- copy 0\n")
    (write _test-input-stream "  c, b <- get a, x\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "type t {\n")
    (write _test-input-stream "  x: int\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-get-with-too-many-outputs: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt get: too many outputs (1 required)"  "F - test-get-with-too-many-outputs: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-get-with-too-many-outputs: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-convert-array-of-user-defined-types:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
    (write _test-input-stream "  x: int\n")
    (write _test-input-stream "  y: int\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
    (write _test-input-stream "  var idx/ecx: int <- copy 3\n")
    (write _test-input-stream "  var x/eax: (addr t) <- index arr, idx\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                                        "F - test-convert-array-of-user-defined-types/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"                              "F - test-convert-array-of-user-defined-types/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"                               "F - test-convert-array-of-user-defined-types/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"                      "F - test-convert-array-of-user-defined-types/3")
    (check-next-stream-line-equal _test-output-stream "  {"                                         "F - test-convert-array-of-user-defined-types/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"                       "F - test-convert-array-of-user-defined-types/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"                    "F - test-convert-array-of-user-defined-types/6")
    (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"                  "F - test-convert-array-of-user-defined-types/7")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"                    "F - test-convert-array-of-user-defined-types/8")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 3/imm32"                  "F - test-convert-array-of-user-defined-types/9")
    (check-next-stream-line-equal _test-output-stream "    8d/copy-address *(eax + ecx<<0x00000003 + 4) 0x00000000/r32"  "F - test-convert-array-of-user-defined-types/11")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"                     "F - test-convert-array-of-user-defined-types/13")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"                     "F - test-convert-array-of-user-defined-types/14")
    (check-next-stream-line-equal _test-output-stream "  }"                                         "F - test-convert-array-of-user-defined-types/15")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"                      "F - test-convert-array-of-user-defined-types/16")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"                              "F - test-convert-array-of-user-defined-types/17")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"                      "F - test-convert-array-of-user-defined-types/18")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"                             "F - test-convert-array-of-user-defined-types/19")
    (check-next-stream-line-equal _test-output-stream "  c3/return"                                 "F - test-convert-array-of-user-defined-types/20")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-length-of-array-of-user-defined-types-to-eax:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
    (write _test-input-stream "  x: int\n")
    (write _test-input-stream "  y: int\n")
    (write _test-input-stream "  z: int\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
    (write _test-input-stream "  var x/eax: (addr t) <- length arr\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-eax/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-eax/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-eax/5")
    # var arr
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/6")
    (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/7")
    # length instruction
    (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/8")
    (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/9")
    (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/10")
    (check-next-stream-line-equal _test-output-stream "    31/xor %edx 2/r32/edx"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/11")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0x0000000c/imm32"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/12")
    (check-next-stream-line-equal _test-output-stream "    f7 7/subop/idiv-eax-edx-by %ecx"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/13")
    (check-next-stream-line-equal _test-output-stream "    5a/pop-to-edx"       "F - test-convert-length-of-array-of-user-defined-types-to-eax/14")
    (check-next-stream-line-equal _test-output-stream "    59/pop-to-ecx"       "F - test-convert-length-of-array-of-user-defined-types-to-eax/15")
    # reclaim arr
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/16")
    #
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-eax/17")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/18")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-eax/19")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-user-defined-types-to-eax/20")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-user-defined-types-to-eax/21")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-eax/22")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-length-of-array-of-user-defined-types-to-ecx:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
    (write _test-input-stream "  x: int\n")
    (write _test-input-stream "  y: int\n")
    (write _test-input-stream "  z: int\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
    (write _test-input-stream "  var x/ecx: (addr t) <- length arr\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-ecx/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-ecx/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-ecx/5")
    # var a
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/6")
    (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/7")
    # var x
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ecx"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/8")
    # length instruction
    (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/9")
    (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/10")
    (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/11")
    (check-next-stream-line-equal _test-output-stream "    31/xor %edx 2/r32/edx"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/12")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0x0000000c/imm32"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/13")
    (check-next-stream-line-equal _test-output-stream "    f7 7/subop/idiv-eax-edx-by %ecx"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/14")
    (check-next-stream-line-equal _test-output-stream "    89/<- %ecx 0/r32/eax"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/15")
    (check-next-stream-line-equal _test-output-stream "    5a/pop-to-edx"       "F - test-convert-length-of-array-of-user-defined-types-to-ecx/16")
    (check-next-stream-line-equal _test-output-stream "    58/pop-to-eax"       "F - test-convert-length-of-array-of-user-defined-types-to-ecx/17")
    # reclaim x
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ecx"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/18")
    # reclaim a
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/19")
    #
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-ecx/20")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/21")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-ecx/22")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-user-defined-types-to-ecx/23")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-user-defined-types-to-ecx/24")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-ecx/25")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-length-of-array-of-user-defined-types-to-edx:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "type t {\n")  # size = 12, which is not a power of 2
    (write _test-input-stream "  x: int\n")
    (write _test-input-stream "  y: int\n")
    (write _test-input-stream "  z: int\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
    (write _test-input-stream "  var x/edx: (addr t) <- length arr\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types-to-edx/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types-to-edx/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types-to-edx/5")
    # var a
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/6")
    (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/7")
    # var x
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %edx"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/8")
    # length instruction
    (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/9")
    (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/10")
    (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/11")
    (check-next-stream-line-equal _test-output-stream "    31/xor %edx 2/r32/edx"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/12")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0x0000000c/imm32"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/13")
    (check-next-stream-line-equal _test-output-stream "    f7 7/subop/idiv-eax-edx-by %ecx"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/14")
    (check-next-stream-line-equal _test-output-stream "    89/<- %edx 0/r32/eax"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/15")
    (check-next-stream-line-equal _test-output-stream "    59/pop-to-ecx"       "F - test-convert-length-of-array-of-user-defined-types-to-edx/16")
    (check-next-stream-line-equal _test-output-stream "    58/pop-to-eax"       "F - test-convert-length-of-array-of-user-defined-types-to-edx/17")
    # reclaim x
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %edx"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/18")
    # reclaim a
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/19")
    #
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types-to-edx/20")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/21")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types-to-edx/22")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-user-defined-types-to-edx/23")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-user-defined-types-to-edx/24")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types-to-edx/25")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-convert-length-of-array-of-user-defined-types:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    #
    (write _test-input-stream "type t {\n")  # each t is 8 bytes, which is a power of 2
    (write _test-input-stream "  x: int\n")
    (write _test-input-stream "  y: int\n")
    (write _test-input-stream "  z: int\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var arr/eax: (addr array t) <- copy 0\n")
    (write _test-input-stream "  var x/ebx: (addr t) <- length arr\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "foo:"                    "F - test-convert-length-of-array-of-user-defined-types/0")
    (check-next-stream-line-equal _test-output-stream "  # . prologue"          "F - test-convert-length-of-array-of-user-defined-types/1")
    (check-next-stream-line-equal _test-output-stream "  55/push-ebp"           "F - test-convert-length-of-array-of-user-defined-types/2")
    (check-next-stream-line-equal _test-output-stream "  89/<- %ebp 4/r32/esp"  "F - test-convert-length-of-array-of-user-defined-types/3")
    (check-next-stream-line-equal _test-output-stream "  {"                     "F - test-convert-length-of-array-of-user-defined-types/4")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:"   "F - test-convert-length-of-array-of-user-defined-types/5")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %eax"  "F - test-convert-length-of-array-of-user-defined-types/6")
    (check-next-stream-line-equal _test-output-stream "    b8/copy-to-eax 0/imm32"  "F - test-convert-length-of-array-of-user-defined-types/7")
    (check-next-stream-line-equal _test-output-stream "    ff 6/subop/push %ebx"  "F - test-convert-length-of-array-of-user-defined-types/8")
    (check-next-stream-line-equal _test-output-stream "    50/push-eax"         "F - test-convert-length-of-array-of-user-defined-types/9")
    (check-next-stream-line-equal _test-output-stream "    51/push-ecx"         "F - test-convert-length-of-array-of-user-defined-types/10")
    (check-next-stream-line-equal _test-output-stream "    52/push-edx"         "F - test-convert-length-of-array-of-user-defined-types/11")
    (check-next-stream-line-equal _test-output-stream "    8b/-> *eax 0x00000000/r32"  "F - test-convert-length-of-array-of-user-defined-types/12")
    (check-next-stream-line-equal _test-output-stream "    31/xor %edx 2/r32/edx"  "F - test-convert-length-of-array-of-user-defined-types/13")
    (check-next-stream-line-equal _test-output-stream "    b9/copy-to-ecx 0x0000000c/imm32"  "F - test-convert-length-of-array-of-user-defined-types/14")
    (check-next-stream-line-equal _test-output-stream "    f7 7/subop/idiv-eax-edx-by %ecx"  "F - test-convert-length-of-array-of-user-defined-types/15")
    (check-next-stream-line-equal _test-output-stream "    89/<- %ebx 0/r32/eax"  "F - test-convert-length-of-array-of-user-defined-types/16")
    (check-next-stream-line-equal _test-output-stream "    5a/pop-to-edx"       "F - test-convert-length-of-array-of-user-defined-types/17")
    (check-next-stream-line-equal _test-output-stream "    59/pop-to-ecx"       "F - test-convert-length-of-array-of-user-defined-types/18")
    (check-next-stream-line-equal _test-output-stream "    58/pop-to-eax"       "F - test-convert-length-of-array-of-user-defined-types/19")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %ebx"  "F - test-convert-length-of-array-of-user-defined-types/20")
    (check-next-stream-line-equal _test-output-stream "    8f 0/subop/pop %eax"  "F - test-convert-length-of-array-of-user-defined-types/21")
    (check-next-stream-line-equal _test-output-stream "  }"                     "F - test-convert-length-of-array-of-user-defined-types/22")
    (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:"  "F - test-convert-length-of-array-of-user-defined-types/23")
    (check-next-stream-line-equal _test-output-stream "  # . epilogue"          "F - test-convert-length-of-array-of-user-defined-types/24")
    (check-next-stream-line-equal _test-output-stream "  89/<- %esp 5/r32/ebp"  "F - test-convert-length-of-array-of-user-defined-types/25")
    (check-next-stream-line-equal _test-output-stream "  5d/pop-to-ebp"         "F - test-convert-length-of-array-of-user-defined-types/26")
    (check-next-stream-line-equal _test-output-stream "  c3/return"             "F - test-convert-length-of-array-of-user-defined-types/27")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-index-with-non-array-atom-base-type:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: int\n")
    (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-index-with-non-array-atom-base-type: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: var 'a' is not an array"  "F - test-index-with-non-array-atom-base-type: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-index-with-non-array-atom-base-type: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-index-with-non-array-compound-base-type:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: (handle int)\n")
    (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-index-with-non-array-compound-base-type: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: var 'a' is not an array"  "F - test-index-with-non-array-compound-base-type: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-index-with-non-array-compound-base-type: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-index-with-non-array-compound-base-type-2:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: (addr int)\n")
    (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-index-with-non-array-compound-base-type-2: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: var 'a' is not an array"  "F - test-index-with-non-array-compound-base-type-2: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-index-with-non-array-compound-base-type-2: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-index-with-array-atom-base-type:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: array\n")
    (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-index-with-array-atom-base-type: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: array 'a' must specify the type of its elements"  "F - test-index-with-array-atom-base-type: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-index-with-array-atom-base-type: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-index-with-addr-base-on-stack:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: (addr array int)\n")
    (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-index-with-addr-base-on-stack: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: var 'a' is an addr to an array, and so must live in a register"  "F - test-index-with-addr-base-on-stack: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-index-with-addr-base-on-stack: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-index-with-array-base-in-register:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a/eax: (array int 3) <- copy 0\n")
    (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-index-with-array-base-in-register: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: var 'a' is an array, and so must live on the stack"  "F - test-index-with-array-base-in-register: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-index-with-array-base-in-register: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-index-with-wrong-index-type:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a/eax: (addr array int) <- copy 0\n")
    (write _test-input-stream "  var b: boolean\n")
    (write _test-input-stream "  var c/ecx: (addr int) <- index a, b\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-index-with-wrong-index-type: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: second argument 'b' must be an int or offset"  "F - test-index-with-wrong-index-type: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-index-with-wrong-index-type: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-index-with-offset-atom-index-type:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a/eax: (addr array int) <- copy 0\n")
    (write _test-input-stream "  var b: offset\n")
    (write _test-input-stream "  var c/ecx: (addr int) <- index a, b\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-index-with-offset-atom-index-type: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: offset 'b' must specify the type of array elements"  "F - test-index-with-offset-atom-index-type: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-index-with-offset-atom-index-type: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-index-with-offset-on-stack:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a/eax: (addr array int) <- copy 0\n")
    (write _test-input-stream "  var b: int\n")
    (write _test-input-stream "  var c/ecx: (addr int) <- index a, b\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-index-with-offset-on-stack: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: second argument 'b' must be in a register"  "F - test-index-with-offset-on-stack: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-index-with-offset-on-stack: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-index-needs-offset-type:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a/eax: (addr array t) <- copy 0\n")
    (write _test-input-stream "  var b/ebx: int <- copy 0\n")
    (write _test-input-stream "  var c/ecx: (addr int) <- index a, b\n")
    (write _test-input-stream "}\n")
    (write _test-input-stream "type t {\n")  # size 12 is not a power of two
    (write _test-input-stream "  x: int\n")
    (write _test-input-stream "  y: int\n")
    (write _test-input-stream "  z: int\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-index-needs-offset-type: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: cannot take an int for array 'a'; create an offset instead. See mu.md for details."  "F - test-index-needs-offset-type: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-index-needs-offset-type: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-index-with-output-not-address:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a/ebx: (addr array boolean) <- copy 0\n")
    (write _test-input-stream "  var o/edi: int <- index a, 0\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-index-with-output-not-address: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: output 'o' must be an address"  "F - test-index-with-output-not-address: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-index-with-output-not-address: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-index-with-output-not-address-2:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a/ebx: (addr array boolean) <- copy 0\n")
    (write _test-input-stream "  var o/edi: (int) <- index a, 0\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-index-with-output-not-address-2: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: output 'o' must be an address"  "F - test-index-with-output-not-address-2: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-index-with-output-not-address-2: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-index-with-wrong-output-type:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a/ebx: (addr array boolean) <- copy 0\n")
    (write _test-input-stream "  var o/edi: (addr int) <- index a, 0\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-index-with-wrong-output-type: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: output 'o' does not have the right type"  "F - test-index-with-wrong-output-type: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-index-with-wrong-output-type: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-index-with-wrong-output-compound-type:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a/ebx: (addr array handle boolean) <- copy 0\n")
    (write _test-input-stream "  var o/edi: (addr handle int) <- index a, 0\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-index-with-wrong-output-compound-type: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: output 'o' does not have the right type"  "F - test-index-with-wrong-output-compound-type: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-index-with-wrong-output-compound-type: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-index-with-no-inouts:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var c/ecx: (addr int) <- index\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-index-with-no-inouts: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: too few inouts (2 required)"  "F - test-index-with-no-inouts: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-index-with-no-inouts: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-index-with-too-few-inouts:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: (array int 3)\n")
    (write _test-input-stream "  var c/ecx: (addr int) <- index a\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-index-with-too-few-inouts: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: too few inouts (2 required)"  "F - test-index-with-too-few-inouts: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-index-with-too-few-inouts: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-index-with-too-many-inouts:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: (array int 3)\n")
    (write _test-input-stream "  var c/ecx: (addr int) <- index a, 0, 0\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-index-with-too-many-inouts: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: too many inouts (2 required)"  "F - test-index-with-too-many-inouts: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-index-with-too-many-inouts: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-index-with-no-output:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: (array int 3)\n")
    (write _test-input-stream "  index a, 0\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-index-with-no-output: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: must have an output"  "F - test-index-with-no-output: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-index-with-no-output: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

test-index-with-too-many-outputs:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (clear-stream $_test-input-buffered-file->buffer)
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    (clear-stream _test-error-stream)
    (clear-stream $_test-error-buffered-file->buffer)
    # var ed/edx: exit-descriptor = tailor-exit-descriptor(16)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    (tailor-exit-descriptor %edx 0x10)
    #
    (write _test-input-stream "fn foo {\n")
    (write _test-input-stream "  var a: (array int 3)\n")
    (write _test-input-stream "  var b/eax: (addr int) <- copy 0\n")
    (write _test-input-stream "  var c/ecx: (addr int) <- copy 0\n")
    (write _test-input-stream "  b, c <- index a, 0\n")
    (write _test-input-stream "}\n")
    # convert
    (convert-mu _test-input-buffered-file _test-output-buffered-file _test-error-buffered-file %edx)
    # registers except esp clobbered at this point
    # restore ed
    89/<- %edx 4/r32/esp
    (flush _test-output-buffered-file)
    (flush _test-error-buffered-file)
#?     # dump _test-error-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-error-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-error-stream)
#?     # }}}
    # check output
    (check-stream-equal _test-output-stream  ""  "F - test-index-with-too-many-outputs: output should be empty")
    (check-next-stream-line-equal _test-error-stream  "fn foo: stmt index: too many outputs (1 required)"  "F - test-index-with-too-many-outputs: error message")
    # check that stop(1) was called
    (check-ints-equal *(edx+4) 2 "F - test-index-with-too-many-outputs: exit status")
    # don't restore from ebp
    81 0/subop/add %esp 8/imm32
    # . epilogue
    5d/pop-to-ebp
    c3/return

#######################################################
# Parsing
#######################################################

== data

# Global state added to each var record when parsing a function
Next-block-index:  # (addr int)
    1/imm32

Curr-block-depth:  # (addr int)
    1/imm32

== code

parse-mu:  # in: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
    # pseudocode
    #   var curr-function: (addr handle function) = Program->functions
    #   var curr-signature: (addr handle function) = Program->signatures
    #   var curr-type: (addr handle typeinfo) = Program->types
    #   var line: (stream byte 512)
    #   var word-slice: slice
    #   while true                                  # line loop
    #     clear-stream(line)
    #     read-line-buffered(in, line)
    #     if (line->write == 0) break               # end of file
    #     word-slice = next-mu-token(line)
    #     if slice-empty?(word-slice)               # end of line
    #       continue
    #     else if slice-starts-with?(word-slice, "#")  # comment
    #       continue                                # end of line
    #     else if slice-equal?(word-slice, "fn")
    #       var new-function: (handle function) = allocate(function)
    #       var vars: (stack live-var 256)
    #       populate-mu-function-header(line, new-function, vars)
    #       populate-mu-function-body(in, new-function, vars)
    #       assert(vars->top == 0)
    #       *curr-function = new-function
    #       curr-function = &new-function->next
    #     else if slice-equal?(word-slice, "sig")
    #       var new-function: (handle function) = allocate(function)
    #       populate-mu-function-signature(line, new-function)
    #       *curr-signature = new-function
    #       curr-signature = &new-function->next
    #     else if slice-equal?(word-slice, "type")
    #       word-slice = next-mu-token(line)
    #       type-id = pos-or-insert-slice(Type-id, word-slice)
    #       var new-type: (handle typeinfo) = find-or-create-typeinfo(type-id)
    #       assert(next-word(line) == "{")
    #       populate-mu-type(in, new-type)
    #     else
    #       abort()
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # var curr-signature: (addr handle function) at *(ebp-4)
    68/push _Program-signatures/imm32
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    56/push-esi
    57/push-edi
    # var line/ecx: (stream byte 512)
    81 5/subop/subtract %esp 0x200/imm32
    68/push 0x200/imm32/size
    68/push 0/imm32/read
    68/push 0/imm32/write
    89/<- %ecx 4/r32/esp
    # var word-slice/edx: slice
    68/push 0/imm32/end
    68/push 0/imm32/start
    89/<- %edx 4/r32/esp
    # var curr-function/edi: (addr handle function)
    bf/copy-to-edi _Program-functions/imm32
    # var vars/ebx: (stack live-var 256)
    81 5/subop/subtract %esp 0xc00/imm32
    68/push 0xc00/imm32/size
    68/push 0/imm32/top
    89/<- %ebx 4/r32/esp
    {
$parse-mu:line-loop:
      (clear-stream %ecx)
      (read-line-buffered *(ebp+8) %ecx)
      # if (line->write == 0) break
      81 7/subop/compare *ecx 0/imm32
      0f 84/jump-if-= break/disp32
#?       # dump line {{{
#?       (write 2 "parse-mu: ^")
#?       (write-stream 2 %ecx)
#?       (write 2 "$\n")
#?       (rewind-stream %ecx)
#?       # }}}
      (next-mu-token %ecx %edx)
      # if slice-empty?(word-slice) continue
      (slice-empty? %edx)  # => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= loop/disp32
      # if (*word-slice->start == "#") continue
      # . eax = *word-slice->start
      8b/-> *edx 0/r32/eax
      8a/copy-byte *eax 0/r32/AL
      81 4/subop/and %eax 0xff/imm32
      # . if (eax == '#') continue
      3d/compare-eax-and 0x23/imm32/hash
      0f 84/jump-if-= loop/disp32
      # if (slice-equal?(word-slice, "fn")) parse a function
      {
$parse-mu:fn:
        (slice-equal? %edx "fn")  # => eax
        3d/compare-eax-and 0/imm32/false
        0f 84/jump-if-= break/disp32
        # var new-function/esi: (handle function)
        68/push 0/imm32
        68/push 0/imm32
        89/<- %esi 4/r32/esp
        # populate-mu-function(line, in, vars, new-function)
        (allocate Heap *Function-size %esi)
        # var new-function-addr/eax: (addr function)
        (lookup *esi *(esi+4))  # => eax
        # initialize vars
        (clear-stack %ebx)
        #
        (populate-mu-function-header %ecx %eax %ebx *(ebp+0xc) *(ebp+0x10))
        (populate-mu-function-body *(ebp+8) %eax %ebx *(ebp+0xc) *(ebp+0x10))
        # *curr-function = new-function
        8b/-> *esi 0/r32/eax
        89/<- *edi 0/r32/eax
        8b/-> *(esi+4) 0/r32/eax
        89/<- *(edi+4) 0/r32/eax
        # curr-function = &new-function->next
        # . var tmp/eax: (addr function) = lookup(new-function)
        (lookup *esi *(esi+4))  # => eax
        # . curr-function = &tmp->next
        8d/copy-address *(eax+0x20) 7/r32/edi  # Function-next
        # reclaim new-function
        81 0/subop/add %esp 8/imm32
        #
        e9/jump $parse-mu:line-loop/disp32
      }
      # if (slice-equal?(word-slice, "sig")) parse a function signature
      # Function signatures are for providing types to SubX functions.
      {
$parse-mu:sig:
        (slice-equal? %edx "sig")  # => eax
        3d/compare-eax-and 0/imm32/false
        0f 84/jump-if-= break/disp32
        # edi = curr-function
        57/push-edi
        8b/-> *(ebp-4) 7/r32/edi
        # var new-function/esi: (handle function)
        68/push 0/imm32
        68/push 0/imm32
        89/<- %esi 4/r32/esp
        # populate-mu-function(line, in, vars, new-function)
        (allocate Heap *Function-size %esi)
        # var new-function-addr/eax: (addr function)
        (lookup *esi *(esi+4))  # => eax
        #
        (populate-mu-function-signature %ecx %eax *(ebp+0xc) *(ebp+0x10))
        # *curr-signature = new-function
        8b/-> *esi 0/r32/eax
        89/<- *edi 0/r32/eax
        8b/-> *(esi+4) 0/r32/eax
        89/<- *(edi+4) 0/r32/eax
        # curr-signature = &new-function->next
        # . var tmp/eax: (addr function) = lookup(new-function)
        (lookup *esi *(esi+4))  # => eax
        # . curr-function = &tmp->next
        8d/copy-address *(eax+0x20) 7/r32/edi  # Function-next
        # reclaim new-function
        81 0/subop/add %esp 8/imm32
        # save curr-function
        89/<- *(ebp-4) 7/r32/edi
        # restore edi
        5f/pop-to-edi
        #
        e9/jump $parse-mu:line-loop/disp32
      }
      # if (slice-equal?(word-slice, "type")) parse a type (struct/record) definition
      {
$parse-mu:type:
        (slice-equal? %edx "type")  # => eax
        3d/compare-eax-and 0/imm32
        0f 84/jump-if-= break/disp32
        (next-mu-token %ecx %edx)
        # var type-id/eax: int
        (pos-or-insert-slice Type-id %edx)  # => eax
        # spill
        51/push-ecx
        # var new-type/ecx: (handle typeinfo)
        68/push 0/imm32
        68/push 0/imm32
        89/<- %ecx 4/r32/esp
        (find-or-create-typeinfo %eax %ecx)
        #
        (lookup *ecx *(ecx+4))  # => eax
        # TODO: ensure that 'line' has nothing else but '{'
#? (dump-typeinfos "=== aaa\n")
        (populate-mu-type *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))  # => eax
#? (dump-typeinfos "=== zzz\n")
        # reclaim new-type
        81 0/subop/add %esp 8/imm32
        # restore
        59/pop-to-ecx
        e9/jump $parse-mu:line-loop/disp32
      }
      # otherwise abort
      e9/jump $parse-mu:error1/disp32
    } # end line loop
$parse-mu:end:
    # . reclaim locals
    81 0/subop/add %esp 0x20c/imm32  # line
    81 0/subop/add %esp 0xc08/imm32  # vars
    81 0/subop/add %esp 8/imm32
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . reclaim local
    81 0/subop/add %esp 4/imm32
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$parse-mu:error1:
    # error("unexpected top-level command: " word-slice "\n")
    (write-buffered *(ebp+0xc) "unexpected top-level command: ")
    (write-slice-buffered *(ebp+0xc) %edx)
    (write-buffered *(ebp+0xc) "\n")
    (flush *(ebp+0xc))
    (stop *(ebp+0x10) 1)
    # never gets here

$parse-mu:error2:
    # error(vars->top " vars not reclaimed after fn '" new-function->name "'\n")
    (write-int32-hex-buffered *(ebp+0xc) *ebx)
    (write-buffered *(ebp+0xc) " vars not reclaimed after fn '")
    (write-slice-buffered *(ebp+0xc) *eax)  # Function-name
    (write-buffered *(ebp+0xc) "'\n")
    (flush *(ebp+0xc))
    (stop *(ebp+0x10) 1)
    # never gets here

# scenarios considered:
# ✗ fn foo  # no block
# ✓ fn foo {
# ✗ fn foo { {
# ✗ fn foo { }
# ✗ fn foo { } {
# ✗ fn foo x {
# ✗ fn foo x: {
# ✓ fn foo x: int {
# ✓ fn foo x: int {
# ✓ fn foo x: int -> y/eax: int {
# TODO:
#   disallow outputs of type `(... addr ...)`
#   disallow inputs of type `(... addr ... addr ...)`
populate-mu-function-header:  # first-line: (addr stream byte), out: (addr function), vars: (addr stack live-var), err: (addr buffered-file), ed: (addr exit-descriptor)
    # pseudocode:
    #   var word-slice: slice
    #   next-mu-token(first-line, word-slice)
    #   if slice-empty?(word-slice) abort
    #   assert(word-slice not in '{' '}' '->')
    #   out->name = slice-to-string(word-slice)
    #   ## inouts
    #   while true
    #     word-slice = next-mu-token(first-line)
    #     if slice-empty?(word-slice) abort
    #     if (word-slice == '{') goto done
    #     if (word-slice == '->') break
    #     assert(word-slice != '}')
    #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
    #     assert(v->register == null)
    #     # v->block-depth is implicitly 0
    #     out->inouts = append(v, out->inouts)
    #     push(vars, {v, false})
    #   ## outputs
    #   while true
    #     word-slice = next-mu-token(first-line)
    #     if slice-empty?(word-slice) abort
    #     if (word-slice == '{') break
    #     assert(word-slice not in '}' '->')
    #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
    #     assert(v->register != null)
    #     out->outputs = append(v, out->outputs)
    #   done:
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    57/push-edi
    # edi = out
    8b/-> *(ebp+0xc) 7/r32/edi
    # var word-slice/ecx: slice
    68/push 0/imm32/end
    68/push 0/imm32/start
    89/<- %ecx 4/r32/esp
    # var v/ebx: (handle var)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %ebx 4/r32/esp
    # read function name
    (next-mu-token *(ebp+8) %ecx)
    # error checking
    # if slice-empty?(word-slice) abort
    (slice-empty? %ecx)  # => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
    # if (word-slice == '{') abort
    (slice-equal? %ecx "{")   # => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
    # if (word-slice == '->') abort
    (slice-equal? %ecx "->")   # => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
    # if (word-slice == '}') abort
    (slice-equal? %ecx "}")   # => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
    # save function name
    (slice-to-string Heap %ecx %edi)  # Function-name
    # save function inouts
    {
$populate-mu-function-header:check-for-inout:
      (next-mu-token *(ebp+8) %ecx)
      # if slice-empty?(word-slice) abort
      (slice-empty? %ecx)  # => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
      # if (word-slice == '{') goto done
      (slice-equal? %ecx "{")   # => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= $populate-mu-function-header:done/disp32
      # if (word-slice == '->') break
      (slice-equal? %ecx "->")   # => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= break/disp32
      # if (word-slice == '}') abort
      (slice-equal? %ecx "}")   # => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
      # v = parse-var-with-type(word-slice, first-line)
      (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
      # assert(v->register == null)
      # . eax: (addr var) = lookup(v)
      (lookup *ebx *(ebx+4))  # => eax
      81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
      0f 85/jump-if-!= $populate-mu-function-header:error2/disp32
      # v->block-depth is implicitly 0
      #
      # out->inouts = append(v, out->inouts)
      8d/copy-address *(edi+8) 0/r32/eax  # Function-inouts
      (append-list Heap  *ebx *(ebx+4)  *(edi+8) *(edi+0xc)  %eax)  # Function-inouts, Function-inouts
      # push(vars, {v, false})
      (push *(ebp+0x10) *ebx)
      (push *(ebp+0x10) *(ebx+4))
      (push *(ebp+0x10) 0)  # false
      #
      e9/jump loop/disp32
    }
    # save function outputs
    {
$populate-mu-function-header:check-for-out:
      (next-mu-token *(ebp+8) %ecx)
      # if slice-empty?(word-slice) abort
      (slice-empty? %ecx)  # => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
      # if (word-slice == '{') break
      (slice-equal? %ecx "{")   # => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= break/disp32
      # if (word-slice == '->') abort
      (slice-equal? %ecx "->")   # => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
      # if (word-slice == '}') abort
      (slice-equal? %ecx "}")   # => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= $populate-mu-function-header:error1/disp32
      # v = parse-var-with-type(word-slice, first-line)
      (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x14) *(ebp+0x18))
      # assert(var->register != null)
      # . eax: (addr var) = lookup(v)
      (lookup *ebx *(ebx+4))  # => eax
      81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
      0f 84/jump-if-= $populate-mu-function-header:error3/disp32
      # out->outputs = append(v, out->outputs)
      8d/copy-address *(edi+0x10) 0/r32/eax  # Function-outputs
      (append-list Heap  *ebx *(ebx+4)  *(edi+0x10) *(edi+0x14)  %eax)  # Function-outputs, Function-outputs
      #
      e9/jump loop/disp32
    }
$populate-mu-function-header:done:
    (check-no-tokens-left *(ebp+8))
$populate-mu-function-header:end:
    # . reclaim locals
    81 0/subop/add %esp 0x10/imm32
    # . restore registers
    5f/pop-to-edi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$populate-mu-function-header:error1:
    # error("function header not in form 'fn <name> {'")
    (write-buffered *(ebp+0x14) "function header not in form 'fn <name> [inouts] [-> outputs] {' -- '")
    (flush *(ebp+0x14))
    (rewind-stream *(ebp+8))
    (write-stream-data *(ebp+0x14) *(ebp+8))
    (write-buffered *(ebp+0x14) "'\n")
    (flush *(ebp+0x14))
    (stop *(ebp+0x18) 1)
    # never gets here

$populate-mu-function-header:error2:
    # error("fn " fn ": function inout '" var "' cannot be in a register")
    (write-buffered *(ebp+0x14) "fn ")
    50/push-eax
    (lookup *edi *(edi+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x14) %eax)
    58/pop-to-eax
    (write-buffered *(ebp+0x14) ": function inout '")
    (lookup *eax *(eax+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x14) "' cannot be in a register")
    (flush *(ebp+0x14))
    (stop *(ebp+0x18) 1)
    # never gets here

$populate-mu-function-header:error3:
    # error("fn " fn ": function output '" var "' must be in a register")
    (write-buffered *(ebp+0x14) "fn ")
    50/push-eax
    (lookup *edi *(edi+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x14) %eax)
    58/pop-to-eax
    (write-buffered *(ebp+0x14) ": function output '")
    (lookup *ebx *(ebx+4))  # => eax
    (lookup *eax *(eax+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+0x14) %eax)
    (write-buffered *(ebp+0x14) "' must be in a register, in instruction '")
    (rewind-stream *(ebp+8))
    (write-stream-data *(ebp+0x14) *(ebp+8))
    (write-buffered *(ebp+0x14) "'\n")
    (flush *(ebp+0x14))
    (stop *(ebp+0x18) 1)
    # never gets here

# scenarios considered:
# ✓ fn foo
# ✗ fn foo {
# ✓ fn foo x
# ✓ fn foo x: int
# ✓ fn foo x: int -> y/eax: int
# TODO:
#   disallow outputs of type `(... addr ...)`
#   disallow inputs of type `(... addr ... addr ...)`
populate-mu-function-signature:  # first-line: (addr stream byte), out: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # pseudocode:
    #   var word-slice: slice
    #   next-mu-token(first-line, word-slice)
    #   assert(word-slice not in '{' '}' '->')
    #   out->name = slice-to-string(word-slice)
    #   ## inouts
    #   while true
    #     word-slice = next-mu-token(first-line)
    #     if slice-empty?(word-slice) break
    #     if (word-slice == '->') break
    #     assert(word-slice not in '{' '}')
    #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
    #     assert(v->register == null)
    #     # v->block-depth is implicitly 0
    #     out->inouts = append(v, out->inouts)
    #   ## outputs
    #   while true
    #     word-slice = next-mu-token(first-line)
    #     if slice-empty?(word-slice) break
    #     assert(word-slice not in '{' '}' '->')
    #     var v: (handle var) = parse-var-with-type(word-slice, first-line)
    #     assert(v->register != null)
    #     out->outputs = append(v, out->outputs)
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    57/push-edi
    # edi = out
    8b/-> *(ebp+0xc) 7/r32/edi
    # var word-slice/ecx: slice
    68/push 0/imm32/end
    68/push 0/imm32/start
    89/<- %ecx 4/r32/esp
    # var v/ebx: (handle var)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %ebx 4/r32/esp
    # read function name
    (next-mu-token *(ebp+8) %ecx)
    # error checking
    # if (word-slice == '{') abort
    (slice-equal? %ecx "{")   # => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
    # if (word-slice == '->') abort
    (slice-equal? %ecx "->")   # => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
    # if (word-slice == '}') abort
    (slice-equal? %ecx "}")   # => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
    # save function name
    (slice-to-string Heap %ecx %edi)  # Function-name
    # save function inouts
    {
$populate-mu-function-signature:check-for-inout:
      (next-mu-token *(ebp+8) %ecx)
      (slice-empty? %ecx)  # => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= break/disp32
      # if (word-slice == '->') break
      (slice-equal? %ecx "->")   # => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= break/disp32
      # if (word-slice == '{') abort
      (slice-equal? %ecx "{")   # => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
      # if (word-slice == '}') abort
      (slice-equal? %ecx "}")   # => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
      # v = parse-var-with-type(word-slice, first-line)
      (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x10) *(ebp+0x14))
      # assert(v->register == null)
      # . eax: (addr var) = lookup(v)
      (lookup *ebx *(ebx+4))  # => eax
      81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
      0f 85/jump-if-!= $populate-mu-function-signature:error2/disp32
      # v->block-depth is implicitly 0
      #
      # out->inouts = append(v, out->inouts)
      8d/copy-address *(edi+8) 0/r32/eax  # Function-inouts
      (append-list Heap  *ebx *(ebx+4)  *(edi+8) *(edi+0xc)  %eax)  # Function-inouts, Function-inouts
      #
      e9/jump loop/disp32
    }
    # save function outputs
    {
$populate-mu-function-signature:check-for-out:
      (next-mu-token *(ebp+8) %ecx)
      (slice-empty? %ecx)  # => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= break/disp32
      # if (word-slice == '{') abort
      (slice-equal? %ecx "{")   # => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
      # if (word-slice == '->') abort
      (slice-equal? %ecx "->")   # => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
      # if (word-slice == '}') abort
      (slice-equal? %ecx "}")   # => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= $populate-mu-function-signature:error1/disp32
      # v = parse-var-with-type(word-slice, first-line)
      (parse-var-with-type %ecx *(ebp+8) %ebx *(ebp+0x10) *(ebp+0x14))
      # assert(var->register != null)
      # . eax: (addr var) = lookup(v)
      (lookup *ebx *(ebx+4))  # => eax
      81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
      0f 84/jump-if-= $populate-mu-function-signature:error3/disp32
      # out->outputs = append(v, out->outputs)
      8d/copy-address *(edi+0x10) 0/r32/eax  # Function-outputs
      (append-list Heap  *ebx *(ebx+4)  *(edi+0x10) *(edi+0x14)  %eax)  # Function-outputs, Function-outputs
      #
      e9/jump loop/disp32
    }
$populate-mu-function-signature:done:
    (check-no-tokens-left *(ebp+8))
$populate-mu-function-signature:end:
    # . reclaim locals
    81 0/subop/add %esp 0x10/imm32
    # . restore registers
    5f/pop-to-edi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$populate-mu-function-signature:error1:
    # error("function signature not in form 'fn <name> {'")
    (write-buffered *(ebp+0x10) "function signature not in form 'fn <name> [inouts] [-> outputs] {' -- '")
    (flush *(ebp+0x10))
    (rewind-stream *(ebp+8))
    (write-stream-data *(ebp+0x10) *(ebp+8))
    (write-buffered *(ebp+0x10) "'\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$populate-mu-function-signature:error2:
    # error("fn " fn ": function inout '" var "' cannot be in a register")
    (write-buffered *(ebp+0x10) "fn ")
    50/push-eax
    (lookup *edi *(edi+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    58/pop-to-eax
    (write-buffered *(ebp+0x10) ": function inout '")
    (lookup *eax *(eax+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) "' cannot be in a register")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$populate-mu-function-signature:error3:
    # error("fn " fn ": function output '" var "' must be in a register")
    (write-buffered *(ebp+0x10) "fn ")
    50/push-eax
    (lookup *edi *(edi+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    58/pop-to-eax
    (write-buffered *(ebp+0x10) ": function output '")
    (lookup *ebx *(ebx+4))  # => eax
    (lookup *eax *(eax+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) "' must be in a register, in instruction '")
    (rewind-stream *(ebp+8))
    (write-stream-data *(ebp+0x10) *(ebp+8))
    (write-buffered *(ebp+0x10) "'\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

test-function-header-with-arg:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (write _test-input-stream "foo n: int {\n")
    # var result/ecx: function
    2b/subtract *Function-size 4/r32/esp
    89/<- %ecx 4/r32/esp
    (zero-out %ecx *Function-size)
    # var vars/ebx: (stack live-var 16)
    81 5/subop/subtract %esp 0xc0/imm32
    68/push 0xc0/imm32/size
    68/push 0/imm32/top
    89/<- %ebx 4/r32/esp
    # convert
    (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
    # check result->name
    (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
    (check-strings-equal %eax "foo" "F - test-function-header-with-arg/name")
    # var v/edx: (addr var) = result->inouts->value
    (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
    (lookup *eax *(eax+4))  # List-value List-value => eax
    89/<- %edx 0/r32/eax
    # check v->name
    (lookup *edx *(edx+4))  # Var-name Var-name => eax
    (check-strings-equal %eax "n" "F - test-function-header-with-arg/inout:0")
    # check v->type
    (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
    (check-ints-equal *eax 1 "F - test-function-header-with-arg/inout:0/type:0")  # Type-tree-is-atom
    (check-ints-equal *(eax+4) 1 "F - test-function-header-with-arg/inout:0/type:1")  # Type-tree-value
    (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-arg/inout:0/type:2")  # Type-tree-right
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-function-header-with-multiple-args:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (write _test-input-stream "foo a: int, b: int c: int {\n")
    # result/ecx: function
    2b/subtract *Function-size 4/r32/esp
    89/<- %ecx 4/r32/esp
    (zero-out %ecx *Function-size)
    # var vars/ebx: (stack live-var 16)
    81 5/subop/subtract %esp 0xc0/imm32
    68/push 0xc0/imm32/size
    68/push 0/imm32/top
    89/<- %ebx 4/r32/esp
    # convert
    (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
    # check result->name
    (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
    (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args/name")
    # var inouts/edx: (addr list var) = lookup(result->inouts)
    (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
    89/<- %edx 0/r32/eax
$test-function-header-with-multiple-args:inout0:
    # var v/ebx: (addr var) = lookup(inouts->value)
    (lookup *edx *(edx+4))  # List-value List-value => eax
    89/<- %ebx 0/r32/eax
    # check v->name
    (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
    (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args/inout:0")  # Var-name
    # check v->type
    (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
    (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:0/type:0")  # Type-tree-is-atom
    (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:0/type:1")  # Type-tree-value
    (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:0/type:2")  # Type-tree-right
$test-function-header-with-multiple-args:inout1:
    # inouts = lookup(inouts->next)
    (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
    89/<- %edx 0/r32/eax
    # v = lookup(inouts->value)
    (lookup *edx *(edx+4))  # List-value List-value => eax
    89/<- %ebx 0/r32/eax
    # check v->name
    (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
    (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args/inout:1")  # Var-name
    # check v->type
    (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
    (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:1/type:0")  # Type-tree-is-atom
    (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:1/type:1")  # Type-tree-value
    (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:1/type:2")  # Type-tree-right
$test-function-header-with-multiple-args:inout2:
    # inouts = lookup(inouts->next)
    (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
    89/<- %edx 0/r32/eax
    # v = lookup(inouts->value)
    (lookup *edx *(edx+4))  # List-value List-value => eax
    89/<- %ebx 0/r32/eax
    # check v->name
    (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
    (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args/inout:2")  # Var-name
    # check v->type
    (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
    (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args/inout:2/type:0")  # Type-tree-is-atom
    (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args/inout:2/type:1")  # Type-tree-value
    (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args/inout:2/type:2")  # Type-tree-right
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-function-header-with-multiple-args-and-outputs:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (write _test-input-stream "foo a: int, b: int, c: int -> x/ecx: int y/edx: int {\n")
    # result/ecx: function
    2b/subtract *Function-size 4/r32/esp
    89/<- %ecx 4/r32/esp
    (zero-out %ecx *Function-size)
    # var vars/ebx: (stack live-var 16)
    81 5/subop/subtract %esp 0xc0/imm32
    68/push 0xc0/imm32/size
    68/push 0/imm32/top
    89/<- %ebx 4/r32/esp
    # convert
    (populate-mu-function-header _test-input-stream %ecx %ebx Stderr 0)
    # check result->name
    (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
    (check-strings-equal %eax "foo" "F - test-function-header-with-multiple-args-and-outputs/name")
    # var inouts/edx: (addr list var) = lookup(result->inouts)
    (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
    89/<- %edx 0/r32/eax
$test-function-header-with-multiple-args-and-outputs:inout0:
    # var v/ebx: (addr var) = lookup(inouts->value)
    (lookup *edx *(edx+4))  # List-value List-value => eax
    89/<- %ebx 0/r32/eax
    # check v->name
    (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
    (check-strings-equal %eax "a" "F - test-function-header-with-multiple-args-and-outputs/inout:0")
    # check v->type
    (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
    (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:0")  # Type-tree-is-atom
    (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:1")  # Type-tree-value
    (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:0/type:2")  # Type-tree-right
$test-function-header-with-multiple-args-and-outputs:inout1:
    # inouts = lookup(inouts->next)
    (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
    89/<- %edx 0/r32/eax
    # v = lookup(inouts->value)
    (lookup *edx *(edx+4))  # List-value List-value => eax
    89/<- %ebx 0/r32/eax
    # check v->name
    (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
    (check-strings-equal %eax "b" "F - test-function-header-with-multiple-args-and-outputs/inout:1")
    # check v->type
    (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
    (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:0")  # Type-tree-is-atom
    (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:1")  # Type-tree-value
    (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:1/type:2")  # Type-tree-right
$test-function-header-with-multiple-args-and-outputs:inout2:
    # inouts = lookup(inouts->next)
    (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
    89/<- %edx 0/r32/eax
    # v = lookup(inouts->value)
    (lookup *edx *(edx+4))  # List-value List-value => eax
    89/<- %ebx 0/r32/eax
    # check v->name
    (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
    (check-strings-equal %eax "c" "F - test-function-header-with-multiple-args-and-outputs/inout:2")
    # check v->type
    (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
    (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:0")  # Type-tree-is-atom
    (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:1")  # Type-tree-value
    (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/inout:2/type:2")  # Type-tree-right
$test-function-header-with-multiple-args-and-outputs:out0:
    # var outputs/edx: (addr list var) = lookup(result->outputs)
    (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
    89/<- %edx 0/r32/eax
    # v = lookup(outputs->value)
    (lookup *edx *(edx+4))  # List-value List-value => eax
    89/<- %ebx 0/r32/eax
    # check v->name
    (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
    (check-strings-equal %eax "x" "F - test-function-header-with-multiple-args-and-outputs/output:0")
    # check v->register
    (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
    (check-strings-equal %eax "ecx" "F - test-function-header-with-multiple-args-and-outputs/output:0/register")
    # check v->type
    (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
    (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:0")  # Type-tree-is-atom
    (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:1")  # Type-tree-value
    (check-ints-equal *(eax+0xc) 0 "F - test-function-header-with-multiple-args-and-outputs/output:0/type:2")  # Type-tree-right
$test-function-header-with-multiple-args-and-outputs:out1:
    # outputs = lookup(outputs->next)
    (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
    89/<- %edx 0/r32/eax
    # v = lookup(inouts->value)
    (lookup *edx *(edx+4))  # List-value List-value => eax
    89/<- %ebx 0/r32/eax
    # check v->name
    (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
    (check-strings-equal %eax "y" "F - test-function-header-with-multiple-args-and-outputs/output:1")
    # check v->register
    (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
    (check-strings-equal %eax "edx" "F - test-function-header-with-multiple-args-and-outputs/output:1/register")
    # check v->type
    (lookup *(ebx+8) *(ebx+0xc))  # Var-type Var-type => eax
    (check-ints-equal *eax 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:0")  # Type-tree-is-atom
    (check-ints-equal *(eax+4) 1 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:1")  # Type-tree-value
    (check-ints-equal *(eax+0c) 0 "F - test-function-header-with-multiple-args-and-outputs/output:1/type:2")  # Type-tree-right
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# format for variables with types
#   x: int
#   x: int,
#   x/eax: int
#   x/eax: int,
# ignores at most one trailing comma
# WARNING: modifies name
parse-var-with-type:  # name: (addr slice), first-line: (addr stream byte), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
    # pseudocode:
    #   var s: slice
    #   if (!slice-ends-with(name, ":"))
    #     abort
    #   --name->end to skip ':'
    #   next-token-from-slice(name->start, name->end, '/', s)
    #   new-var-from-slice(s, out)
    #   ## register
    #   next-token-from-slice(s->end, name->end, '/', s)
    #   if (!slice-empty?(s))
    #     out->register = slice-to-string(s)
    #   ## type
    #   var type: (handle type-tree) = parse-type(first-line)
    #   out->type = type
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    56/push-esi
    57/push-edi
    # esi = name
    8b/-> *(ebp+8) 6/r32/esi
    # if (!slice-ends-with?(name, ":")) abort
    8b/-> *(esi+4) 1/r32/ecx  # Slice-end
    49/decrement-ecx
    8a/copy-byte *ecx 1/r32/CL
    81 4/subop/and %ecx 0xff/imm32
    81 7/subop/compare %ecx 0x3a/imm32/colon
    0f 85/jump-if-!= $parse-var-with-type:abort/disp32
    # --name->end to skip ':'
    ff 1/subop/decrement *(esi+4)
    # var s/ecx: slice
    68/push 0/imm32/end
    68/push 0/imm32/start
    89/<- %ecx 4/r32/esp
$parse-var-with-type:parse-name:
    (next-token-from-slice *esi *(esi+4) 0x2f %ecx)  # Slice-start, Slice-end, '/'
$parse-var-with-type:create-var:
    # new-var-from-slice(s, out)
    (new-var-from-slice Heap %ecx *(ebp+0x10))
    # save out->register
$parse-var-with-type:save-register:
    # . var out-addr/edi: (addr var) = lookup(*out)
    8b/-> *(ebp+0x10) 7/r32/edi
    (lookup *edi *(edi+4))  # => eax
    89/<- %edi 0/r32/eax
    # . s = next-token(...)
    (next-token-from-slice *(ecx+4) *(esi+4) 0x2f %ecx)  # s->end, name->end, '/'
    # . if (!slice-empty?(s)) out->register = slice-to-string(s)
    {
$parse-var-with-type:write-register:
      (slice-empty? %ecx)  # => eax
      3d/compare-eax-and 0/imm32/false
      75/jump-if-!= break/disp8
      # out->register = slice-to-string(s)
      8d/copy-address *(edi+0x18) 0/r32/eax  # Var-register
      (slice-to-string Heap %ecx %eax)
    }
$parse-var-with-type:save-type:
    8d/copy-address *(edi+8) 0/r32/eax  # Var-type
    (parse-type Heap *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
$parse-var-with-type:end:
    # . reclaim locals
    81 0/subop/add %esp 8/imm32
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$parse-var-with-type:abort:
    # error("var should have form 'name: type' in '" line "'\n")
    (write-buffered *(ebp+0x14) "var should have form 'name: type' in '")
    (flush *(ebp+0x14))
    (rewind-stream *(ebp+0xc))
    (write-stream-data *(ebp+0x14) *(ebp+0xc))
    (write-buffered *(ebp+0x14) "'\n")
    (flush *(ebp+0x14))
    (stop *(ebp+0x18) 1)
    # never gets here

parse-type:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle type-tree), err: (addr buffered-file), ed: (addr exit-descriptor)
    # pseudocode:
    #   var s: slice = next-mu-token(in)
    #   assert s != ""
    #   assert s != "->"
    #   assert s != "{"
    #   assert s != "}"
    #   if s == ")"
    #     return
    #   out = allocate(Type-tree)
    #   if s != "("
    #     HACK: if s is an int, parse and return it
    #     out->is-atom? = true
    #     if (s[0] == "_")
    #       out->value = type-parameter
    #       out->parameter-name = slice-to-string(ad, s)
    #     else
    #       out->value = pos-or-insert-slice(Type-id, s)
    #     return
    #   out->left = parse-type(ad, in)
    #   out->right = parse-type-tree(ad, in)
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    # clear out
    (zero-out *(ebp+0x10) *Handle-size)
    # var s/ecx: slice
    68/push 0/imm32
    68/push 0/imm32
    89/<- %ecx 4/r32/esp
    # s = next-mu-token(in)
    (next-mu-token *(ebp+0xc) %ecx)
#?     (write-buffered Stderr "tok: ")
#?     (write-slice-buffered Stderr %ecx)
#?     (write-buffered Stderr "$\n")
#?     (flush Stderr)
    # assert s != ""
    (slice-equal? %ecx "")  # => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $parse-type:abort/disp32
    # assert s != "{"
    (slice-equal? %ecx "{")  # => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $parse-type:abort/disp32
    # assert s != "}"
    (slice-equal? %ecx "}")  # => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $parse-type:abort/disp32
    # assert s != "->"
    (slice-equal? %ecx "->")  # => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $parse-type:abort/disp32
    # if (s == ")") return
    (slice-equal? %ecx ")")  # => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $parse-type:end/disp32
    # out = new tree
    (allocate *(ebp+8) *Type-tree-size *(ebp+0x10))
    # var out-addr/edx: (addr type-tree) = lookup(*out)
    8b/-> *(ebp+0x10) 2/r32/edx
    (lookup *edx *(edx+4))  # => eax
    89/<- %edx 0/r32/eax
    {
      # if (s != "(") break
      (slice-equal? %ecx "(")  # => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= break/disp32
      # if s is a number, store it in the type's size field
      {
$parse-type:check-for-int:
        # var tmp/eax: byte = *s->slice
        8b/-> *ecx 0/r32/eax
        8a/copy-byte *eax 0/r32/AL
        81 4/subop/and %eax 0xff/imm32
        # TODO: raise an error on `var x: (array int a)`
        (is-decimal-digit? %eax)  # => eax
        3d/compare-eax-and 0/imm32/false
        74/jump-if-= break/disp8
        #
        (is-hex-int? %ecx)  # => eax
        3d/compare-eax-and 0/imm32/false
        74/jump-if-= break/disp8
$parse-type:int:
        (check-mu-hex-int %ecx *(ebp+0x14) *(ebp+0x18))
        (parse-hex-int-from-slice %ecx)  # => eax
        c7 0/subop/copy *(edx+4) 9/imm32/type-id-array-capacity  # Type-tree-value
        89/<- *(edx+8) 0/r32/eax  # Type-tree-value-size
        e9/jump $parse-type:end/disp32
      }
$parse-type:atom:
      # out->is-atom? = true
      c7 0/subop/copy *edx 1/imm32/true  # Type-tree-is-atom
      {
$parse-type:check-for-type-parameter:
        # var tmp/eax: byte = *s->slice
        8b/-> *ecx 0/r32/eax
        8a/copy-byte *eax 0/r32/AL
        81 4/subop/and %eax 0xff/imm32
        # if (tmp != '_') break
        3d/compare-eax-and 0x5f/imm32/_
        75/jump-if-!= break/disp8
$parse-type:type-parameter:
        # out->value = type-parameter
        c7 0/subop/copy *(edx+4) 0xa/imm32/type-parameter  # Type-tree-value
        # out->parameter-name = slice-to-string(ad, s)
        8d/copy-address *(edx+8) 0/r32/eax  # Type-tree-parameter-name
        (slice-to-string *(ebp+8) %ecx %eax)
        e9/jump $parse-type:end/disp32
      }
$parse-type:non-type-parameter:
      # out->value = pos-or-insert-slice(Type-id, s)
      (pos-or-insert-slice Type-id %ecx)  # => eax
      89/<- *(edx+4) 0/r32/eax  # Type-tree-value
      e9/jump $parse-type:end/disp32
    }
$parse-type:non-atom:
    # otherwise s == "("
    # out->left = parse-type(ad, in)
    8d/copy-address *(edx+4) 0/r32/eax  # Type-tree-left
    (parse-type *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
    # out->right = parse-type-tree(ad, in)
    8d/copy-address *(edx+0xc) 0/r32/eax  # Type-tree-right
    (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
$parse-type:end:
    # . reclaim locals
    81 0/subop/add %esp 8/imm32
    # . restore registers
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$parse-type:abort:
    # error("unexpected token when parsing type: '" s "'\n")
    (write-buffered *(ebp+0x14) "unexpected token when parsing type: '")
    (write-slice-buffered *(ebp+0x14) %ecx)
    (write-buffered *(ebp+0x14) "'\n")
    (flush *(ebp+0x14))
    (stop *(ebp+0x18) 1)
    # never gets here

parse-type-tree:  # ad: (addr allocation-descriptor), in: (addr stream byte), out: (addr handle type-tree), err: (addr buffered-file), ed: (addr exit-descriptor)
    # pseudocode:
    #   var tmp: (handle type-tree) = parse-type(ad, in)
    #   if tmp == 0
    #     return 0
    #   out = allocate(Type-tree)
    #   out->left = tmp
    #   out->right = parse-type-tree(ad, in)
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    #
    (zero-out *(ebp+0x10) *Handle-size)
    # var tmp/ecx: (handle type-tree)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %ecx 4/r32/esp
    # tmp = parse-type(ad, in)
    (parse-type *(ebp+8) *(ebp+0xc) %ecx *(ebp+0x14) *(ebp+0x18))
    # if (tmp == 0) return
    81 7/subop/compare *ecx 0/imm32
    74/jump-if-= $parse-type-tree:end/disp8
    # out = new tree
    (allocate *(ebp+8) *Type-tree-size *(ebp+0x10))
    # var out-addr/edx: (addr tree) = lookup(*out)
    8b/-> *(ebp+0x10) 2/r32/edx
    (lookup *edx *(edx+4))  # => eax
    89/<- %edx 0/r32/eax
    # out->left = tmp
    8b/-> *ecx 0/r32/eax
    89/<- *(edx+4) 0/r32/eax  # Type-tree-left
    8b/-> *(ecx+4) 0/r32/eax
    89/<- *(edx+8) 0/r32/eax  # Type-tree-left
    # out->right = parse-type-tree(ad, in)
    8d/copy-address *(edx+0xc) 0/r32/eax  # Type-tree-right
    (parse-type-tree *(ebp+8) *(ebp+0xc) %eax *(ebp+0x14) *(ebp+0x18))
$parse-type-tree:end:
    # . reclaim locals
    81 0/subop/add %esp 8/imm32
    # . restore registers
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

next-mu-token:  # in: (addr stream byte), out: (addr slice)
    # pseudocode:
    # start:
    #   skip-chars-matching-whitespace(in)
    #   if in->read >= in->write              # end of in
    #     out = {0, 0}
    #     return
    #   out->start = &in->data[in->read]
    #   var curr-byte/eax: byte = in->data[in->read]
    #   if curr->byte == ','                  # comment token
    #     ++in->read
    #     goto start
    #   if curr-byte == '#'                   # comment
    #     goto done                             # treat as eof
    #   if curr-byte == '"'                   # string literal
    #     skip-string(in)
    #     goto done                           # no metadata
    #   if curr-byte == '('
    #     ++in->read
    #     goto done
    #   if curr-byte == ')'
    #     ++in->read
    #     goto done
    #   # read a word
    #   while true
    #     if in->read >= in->write
    #       break
    #     curr-byte = in->data[in->read]
    #     if curr-byte == ' '
    #       break
    #     if curr-byte == '\r'
    #       break
    #     if curr-byte == '\n'
    #       break
    #     if curr-byte == '('
    #       break
    #     if curr-byte == ')'
    #       break
    #     if curr-byte == ','
    #       break
    #     ++in->read
    # done:
    #   out->end = &in->data[in->read]
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    56/push-esi
    57/push-edi
    # esi = in
    8b/-> *(ebp+8) 6/r32/esi
    # edi = out
    8b/-> *(ebp+0xc) 7/r32/edi
$next-mu-token:start:
    (skip-chars-matching-whitespace %esi)
$next-mu-token:check0:
    # if (in->read >= in->write) return out = {0, 0}
    # . ecx = in->read
    8b/-> *(esi+4) 1/r32/ecx
    # . if (ecx >= in->write) return out = {0, 0}
    3b/compare<- *esi 1/r32/ecx
    c7 0/subop/copy *edi 0/imm32
    c7 0/subop/copy *(edi+4) 0/imm32
    0f 8d/jump-if->= $next-mu-token:end/disp32
    # out->start = &in->data[in->read]
    8d/copy-address *(esi+ecx+0xc) 0/r32/eax
    89/<- *edi 0/r32/eax
    # var curr-byte/eax: byte = in->data[in->read]
    31/xor-with %eax 0/r32/eax
    8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
    {
$next-mu-token:check-for-comma:
      # if (curr-byte != ',') break
      3d/compare-eax-and 0x2c/imm32/comma
      75/jump-if-!= break/disp8
      # ++in->read
      ff 0/subop/increment *(esi+4)
      # restart
      e9/jump $next-mu-token:start/disp32
    }
    {
$next-mu-token:check-for-comment:
      # if (curr-byte != '#') break
      3d/compare-eax-and 0x23/imm32/pound
      75/jump-if-!= break/disp8
      # return eof
      e9/jump $next-mu-token:done/disp32
    }
    {
$next-mu-token:check-for-string-literal:
      # if (curr-byte != '"') break
      3d/compare-eax-and 0x22/imm32/dquote
      75/jump-if-!= break/disp8
      (skip-string %esi)
      # return
      e9/jump $next-mu-token:done/disp32
    }
    {
$next-mu-token:check-for-open-paren:
      # if (curr-byte != '(') break
      3d/compare-eax-and 0x28/imm32/open-paren
      75/jump-if-!= break/disp8
      # ++in->read
      ff 0/subop/increment *(esi+4)
      # return
      e9/jump $next-mu-token:done/disp32
    }
    {
$next-mu-token:check-for-close-paren:
      # if (curr-byte != ')') break
      3d/compare-eax-and 0x29/imm32/close-paren
      75/jump-if-!= break/disp8
      # ++in->read
      ff 0/subop/increment *(esi+4)
      # return
      e9/jump $next-mu-token:done/disp32
    }
    {
$next-mu-token:regular-word-without-metadata:
      # if (in->read >= in->write) break
      # . ecx = in->read
      8b/-> *(esi+4) 1/r32/ecx
      # . if (ecx >= in->write) break
      3b/compare<- *esi 1/r32/ecx
      7d/jump-if->= break/disp8
      # var c/eax: byte = in->data[in->read]
      31/xor-with %eax 0/r32/eax
      8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
      # if (c == ' ') break
      3d/compare-eax-and 0x20/imm32/space
      74/jump-if-= break/disp8
      # if (c == '\r') break
      3d/compare-eax-and 0xd/imm32/carriage-return
      74/jump-if-= break/disp8
      # if (c == '\n') break
      3d/compare-eax-and 0xa/imm32/newline
      74/jump-if-= break/disp8
      # if (c == '(') break
      3d/compare-eax-and 0x28/imm32/open-paren
      0f 84/jump-if-= break/disp32
      # if (c == ')') break
      3d/compare-eax-and 0x29/imm32/close-paren
      0f 84/jump-if-= break/disp32
      # if (c == ',') break
      3d/compare-eax-and 0x2c/imm32/comma
      0f 84/jump-if-= break/disp32
      # ++in->read
      ff 0/subop/increment *(esi+4)
      #
      e9/jump loop/disp32
    }
$next-mu-token:done:
    # out->end = &in->data[in->read]
    8b/-> *(esi+4) 1/r32/ecx
    8d/copy-address *(esi+ecx+0xc) 0/r32/eax
    89/<- *(edi+4) 0/r32/eax
$next-mu-token:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

pos-or-insert-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # if (pos-slice(arr, s) != -1) return it
    (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
    3d/compare-eax-and -1/imm32
    75/jump-if-!= $pos-or-insert-slice:end/disp8
$pos-or-insert-slice:insert:
    # var s2/eax: (handle array byte)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %eax 4/r32/esp
    (slice-to-string Heap *(ebp+0xc) %eax)
    # throw away alloc-id
    (lookup *eax *(eax+4))  # => eax
    (write-int *(ebp+8) %eax)
    (pos-slice *(ebp+8) *(ebp+0xc))  # => eax
$pos-or-insert-slice:end:
    # . reclaim locals
    81 0/subop/add %esp 8/imm32
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# return the index in an array of strings matching 's', -1 if not found
# index is denominated in elements, not bytes
pos-slice:  # arr: (addr stream (addr array byte)), s: (addr slice) -> index/eax: int
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    52/push-edx
    53/push-ebx
    56/push-esi
#?     (write-buffered Stderr "pos-slice: ")
#?     (write-slice-buffered Stderr *(ebp+0xc))
#?     (write-buffered Stderr "\n")
#?     (flush Stderr)
    # esi = arr
    8b/-> *(ebp+8) 6/r32/esi
    # var index/ecx: int = 0
    b9/copy-to-ecx 0/imm32
    # var curr/edx: (addr (addr array byte)) = arr->data
    8d/copy-address *(esi+0xc) 2/r32/edx
    # var max/ebx: (addr (addr array byte)) = &arr->data[arr->write]
    8b/-> *esi 3/r32/ebx
    8d/copy-address *(esi+ebx+0xc) 3/r32/ebx
    {
#?       (write-buffered Stderr "  ")
#?       (write-int32-hex-buffered Stderr %ecx)
#?       (write-buffered Stderr "\n")
#?       (flush Stderr)
      # if (curr >= max) return -1
      39/compare %edx 3/r32/ebx
      b8/copy-to-eax -1/imm32
      73/jump-if-addr>= $pos-slice:end/disp8
      # if (slice-equal?(s, *curr)) break
      (slice-equal? *(ebp+0xc) *edx)  # => eax
      3d/compare-eax-and 0/imm32/false
      75/jump-if-!= break/disp8
      # ++index
      41/increment-ecx
      # curr += 4
      81 0/subop/add %edx 4/imm32
      #
      eb/jump loop/disp8
    }
    # return index
    89/<- %eax 1/r32/ecx
$pos-slice:end:
#?     (write-buffered Stderr "=> ")
#?     (write-int32-hex-buffered Stderr %eax)
#?     (write-buffered Stderr "\n")
    # . restore registers
    5e/pop-to-esi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-parse-var-with-type:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # (eax..ecx) = "x:"
    b8/copy-to-eax "x:"/imm32
    8b/-> *eax 1/r32/ecx
    8d/copy-address *(eax+ecx+4) 1/r32/ecx
    05/add-to-eax 4/imm32
    # var slice/ecx: slice = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/<- %ecx 4/r32/esp
    # _test-input-stream contains "int"
    (clear-stream _test-input-stream)
    (write _test-input-stream "int")
    # var v/edx: (handle var)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    #
    (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
    # var v-addr/edx: (addr var) = lookup(v)
    (lookup *edx *(edx+4))  # => eax
    89/<- %edx 0/r32/eax
    # check v-addr->name
    (lookup *edx *(edx+4))  # Var-name Var-name => eax
    (check-strings-equal %eax "x" "F - test-parse-var-with-type/name")
    # check v-addr->type
    (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
    (check-ints-equal *eax 1 "F - test-parse-var-with-type/type:0")  # Type-tree-is-atom
    (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type/type:1")  # Type-tree-value
    (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type/type:2")  # Type-tree-right
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-parse-var-with-type-and-register:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # (eax..ecx) = "x/eax:"
    b8/copy-to-eax "x/eax:"/imm32
    8b/-> *eax 1/r32/ecx
    8d/copy-address *(eax+ecx+4) 1/r32/ecx
    05/add-to-eax 4/imm32
    # var slice/ecx: slice = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/<- %ecx 4/r32/esp
    # _test-input-stream contains "int"
    (clear-stream _test-input-stream)
    (write _test-input-stream "int")
    # var v/edx: (handle var)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    #
    (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
    # var v-addr/edx: (addr var) = lookup(v)
    (lookup *edx *(edx+4))  # => eax
    89/<- %edx 0/r32/eax
    # check v-addr->name
    (lookup *edx *(edx+4))  # Var-name Var-name => eax
    (check-strings-equal %eax "x" "F - test-parse-var-with-type-and-register/name")
    # check v-addr->register
    (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
    (check-strings-equal %eax "eax" "F - test-parse-var-with-type-and-register/register")
    # check v-addr->type
    (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
    (check-ints-equal *eax 1 "F - test-parse-var-with-type-and-register/type:0")  # Type-tree-is-atom
    (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-type-and-register/type:1")  # Type-tree-left
    (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-type-and-register/type:2")  # Type-tree-right
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-parse-var-with-trailing-characters:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # (eax..ecx) = "x:"
    b8/copy-to-eax "x:"/imm32
    8b/-> *eax 1/r32/ecx
    8d/copy-address *(eax+ecx+4) 1/r32/ecx
    05/add-to-eax 4/imm32
    # var slice/ecx: slice = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/<- %ecx 4/r32/esp
    # _test-input-stream contains "int,"
    (clear-stream _test-input-stream)
    (write _test-input-stream "int,")
    # var v/edx: (handle var)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    #
    (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
    # var v-addr/edx: (addr var) = lookup(v)
    (lookup *edx *(edx+4))  # => eax
    89/<- %edx 0/r32/eax
    # check v-addr->name
    (lookup *edx *(edx+4))  # Var-name Var-name => eax
    (check-strings-equal %eax "x" "F - test-parse-var-with-trailing-characters/name")
    # check v-addr->register
    (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-trailing-characters/register")  # Var-register
    # check v-addr->type
    (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
    (check-ints-equal *eax 1 "F - test-parse-var-with-trailing-characters/type:0")  # Type-tree-is-atom
    (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-trailing-characters/type:1")  # Type-tree-left
    (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-trailing-characters/type:1")  # Type-tree-right
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-parse-var-with-register-and-trailing-characters:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # (eax..ecx) = "x/eax:"
    b8/copy-to-eax "x/eax:"/imm32
    8b/-> *eax 1/r32/ecx
    8d/copy-address *(eax+ecx+4) 1/r32/ecx
    05/add-to-eax 4/imm32
    # var slice/ecx: slice = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/<- %ecx 4/r32/esp
    # _test-input-stream contains "int,"
    (clear-stream _test-input-stream)
    (write _test-input-stream "int,")
    # var v/edx: (handle var)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    #
    (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
    # var v-addr/edx: (addr var) = lookup(v)
    (lookup *edx *(edx+4))  # => eax
    89/<- %edx 0/r32/eax
    # check v-addr->name
    (lookup *edx *(edx+4))  # Var-name Var-name => eax
    (check-strings-equal %eax "x" "F - test-parse-var-with-register-and-trailing-characters/name")
    # check v-addr->register
    (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
    (check-strings-equal %eax "eax" "F - test-parse-var-with-register-and-trailing-characters/register")
    # check v-addr->type
    (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
    (check-ints-equal *eax 1 "F - test-parse-var-with-register-and-trailing-characters/type:0")  # Type-tree-is-atom
    (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-register-and-trailing-characters/type:1")  # Type-tree-left
    (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-register-and-trailing-characters/type:2")  # Type-tree-right
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-parse-var-with-compound-type:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # (eax..ecx) = "x:"
    b8/copy-to-eax "x:"/imm32
    8b/-> *eax 1/r32/ecx
    8d/copy-address *(eax+ecx+4) 1/r32/ecx
    05/add-to-eax 4/imm32
    # var slice/ecx: slice = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/<- %ecx 4/r32/esp
    # _test-input-stream contains "(addr int)"
    (clear-stream _test-input-stream)
    (write _test-input-stream "(addr int)")
    # var v/edx: (handle var)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    #
    (parse-var-with-type %ecx _test-input-stream %edx Stderr 0)
    # var v-addr/edx: (addr var) = lookup(v)
    (lookup *edx *(edx+4))  # => eax
    89/<- %edx 0/r32/eax
    # check v-addr->name
    (lookup *edx *(edx+4))  # Var-name Var-name => eax
    (check-strings-equal %eax "x" "F - test-parse-var-with-compound-type/name")
    # check v-addr->register
    (check-ints-equal *(edx+0x18) 0 "F - test-parse-var-with-compound-type/register")  # Var-register
    # - check v-addr->type
    # var type/edx: (addr type-tree) = var->type
    (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
    89/<- %edx 0/r32/eax
    # type is a non-atom
    (check-ints-equal *edx 0 "F - test-parse-var-with-compound-type/type:0")  # Type-tree-is-atom
    # type->left == atom(addr)
    (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
    (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:1")  # Type-tree-is-atom
    (check-ints-equal *(eax+4) 2 "F - test-parse-var-with-compound-type/type:2")  # Type-tree-value
    # type->right->left == atom(int)
    (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
    (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
    (check-ints-equal *eax 1 "F - test-parse-var-with-compound-type/type:3")  # Type-tree-is-atom
    (check-ints-equal *(eax+4) 1 "F - test-parse-var-with-compound-type/type:4")  # Type-tree-value
    # type->right->right == null
    (check-ints-equal *(eax+0xc) 0 "F - test-parse-var-with-compound-type/type:5")  # Type-tree-right
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# identifier starts with a letter or '$' or '_'
# no constraints at the moment on later letters
# all we really want to do so far is exclude '{', '}' and '->'
is-identifier?:  # in: (addr slice) -> result/eax: boolean
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # if (slice-empty?(in)) return false
    (slice-empty? *(ebp+8))  # => eax
    3d/compare-eax-and 0/imm32/false
    75/jump-if-!= $is-identifier?:false/disp8
    # var c/eax: byte = *in->start
    8b/-> *(ebp+8) 0/r32/eax
    8b/-> *eax 0/r32/eax
    8a/copy-byte *eax 0/r32/AL
    81 4/subop/and %eax 0xff/imm32
    # if (c == '$') return true
    3d/compare-eax-and 0x24/imm32/$
    74/jump-if-= $is-identifier?:true/disp8
    # if (c == '_') return true
    3d/compare-eax-and 0x5f/imm32/_
    74/jump-if-= $is-identifier?:true/disp8
    # drop case
    25/and-eax-with 0x5f/imm32
    # if (c < 'A') return false
    3d/compare-eax-and 0x41/imm32/A
    7c/jump-if-< $is-identifier?:false/disp8
    # if (c > 'Z') return false
    3d/compare-eax-and 0x5a/imm32/Z
    7f/jump-if-> $is-identifier?:false/disp8
    # otherwise return true
$is-identifier?:true:
    b8/copy-to-eax 1/imm32/true
    eb/jump $is-identifier?:end/disp8
$is-identifier?:false:
    b8/copy-to-eax 0/imm32/false
$is-identifier?:end:
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-is-identifier-dollar:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # (eax..ecx) = "$a"
    b8/copy-to-eax "$a"/imm32
    8b/-> *eax 1/r32/ecx
    8d/copy-address *(eax+ecx+4) 1/r32/ecx
    05/add-to-eax 4/imm32
    # var slice/ecx: slice = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/<- %ecx 4/r32/esp
    #
    (is-identifier? %ecx)
    (check-ints-equal %eax 1 "F - test-is-identifier-dollar")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-is-identifier-underscore:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # (eax..ecx) = "_a"
    b8/copy-to-eax "_a"/imm32
    8b/-> *eax 1/r32/ecx
    8d/copy-address *(eax+ecx+4) 1/r32/ecx
    05/add-to-eax 4/imm32
    # var slice/ecx: slice = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/<- %ecx 4/r32/esp
    #
    (is-identifier? %ecx)
    (check-ints-equal %eax 1 "F - test-is-identifier-underscore")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-is-identifier-a:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # (eax..ecx) = "a$"
    b8/copy-to-eax "a$"/imm32
    8b/-> *eax 1/r32/ecx
    8d/copy-address *(eax+ecx+4) 1/r32/ecx
    05/add-to-eax 4/imm32
    # var slice/ecx: slice = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/<- %ecx 4/r32/esp
    #
    (is-identifier? %ecx)
    (check-ints-equal %eax 1 "F - test-is-identifier-a")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-is-identifier-z:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # (eax..ecx) = "z$"
    b8/copy-to-eax "z$"/imm32
    8b/-> *eax 1/r32/ecx
    8d/copy-address *(eax+ecx+4) 1/r32/ecx
    05/add-to-eax 4/imm32
    # var slice/ecx: slice = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/<- %ecx 4/r32/esp
    #
    (is-identifier? %ecx)
    (check-ints-equal %eax 1 "F - test-is-identifier-z")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-is-identifier-A:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # (eax..ecx) = "A$"
    b8/copy-to-eax "A$"/imm32
    8b/-> *eax 1/r32/ecx
    8d/copy-address *(eax+ecx+4) 1/r32/ecx
    05/add-to-eax 4/imm32
    # var slice/ecx: slice = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/<- %ecx 4/r32/esp
    #
    (is-identifier? %ecx)
    (check-ints-equal %eax 1 "F - test-is-identifier-A")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-is-identifier-Z:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # (eax..ecx) = "Z$"
    b8/copy-to-eax "Z$"/imm32
    8b/-> *eax 1/r32/ecx
    8d/copy-address *(eax+ecx+4) 1/r32/ecx
    05/add-to-eax 4/imm32
    # var slice/ecx: slice = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/<- %ecx 4/r32/esp
    #
    (is-identifier? %ecx)
    (check-ints-equal %eax 1 "F - test-is-identifier-Z")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-is-identifier-at:
    # character before 'A' is invalid
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # (eax..ecx) = "@a"
    b8/copy-to-eax "@a"/imm32
    8b/-> *eax 1/r32/ecx
    8d/copy-address *(eax+ecx+4) 1/r32/ecx
    05/add-to-eax 4/imm32
    # var slice/ecx: slice = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/<- %ecx 4/r32/esp
    #
    (is-identifier? %ecx)
    (check-ints-equal %eax 0 "F - test-is-identifier-@")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-is-identifier-square-bracket:
    # character after 'Z' is invalid
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # (eax..ecx) = "[a"
    b8/copy-to-eax "[a"/imm32
    8b/-> *eax 1/r32/ecx
    8d/copy-address *(eax+ecx+4) 1/r32/ecx
    05/add-to-eax 4/imm32
    # var slice/ecx: slice = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/<- %ecx 4/r32/esp
    #
    (is-identifier? %ecx)
    (check-ints-equal %eax 0 "F - test-is-identifier-@")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-is-identifier-backtick:
    # character before 'a' is invalid
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # (eax..ecx) = "`a"
    b8/copy-to-eax "`a"/imm32
    8b/-> *eax 1/r32/ecx
    8d/copy-address *(eax+ecx+4) 1/r32/ecx
    05/add-to-eax 4/imm32
    # var slice/ecx: slice = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/<- %ecx 4/r32/esp
    #
    (is-identifier? %ecx)
    (check-ints-equal %eax 0 "F - test-is-identifier-backtick")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-is-identifier-curly-brace-open:
    # character after 'z' is invalid; also used for blocks
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # (eax..ecx) = "{a"
    b8/copy-to-eax "{a"/imm32
    8b/-> *eax 1/r32/ecx
    8d/copy-address *(eax+ecx+4) 1/r32/ecx
    05/add-to-eax 4/imm32
    # var slice/ecx: slice = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/<- %ecx 4/r32/esp
    #
    (is-identifier? %ecx)
    (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-open")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-is-identifier-curly-brace-close:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # (eax..ecx) = "}a"
    b8/copy-to-eax "}a"/imm32
    8b/-> *eax 1/r32/ecx
    8d/copy-address *(eax+ecx+4) 1/r32/ecx
    05/add-to-eax 4/imm32
    # var slice/ecx: slice = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/<- %ecx 4/r32/esp
    #
    (is-identifier? %ecx)
    (check-ints-equal %eax 0 "F - test-is-identifier-curly-brace-close")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-is-identifier-hyphen:
    # disallow leading '-' since '->' has special meaning
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # (eax..ecx) = "-a"
    b8/copy-to-eax "-a"/imm32
    8b/-> *eax 1/r32/ecx
    8d/copy-address *(eax+ecx+4) 1/r32/ecx
    05/add-to-eax 4/imm32
    # var slice/ecx: slice = {eax, ecx}
    51/push-ecx
    50/push-eax
    89/<- %ecx 4/r32/esp
    #
    (is-identifier? %ecx)
    (check-ints-equal %eax 0 "F - test-is-identifier-hyphen")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

populate-mu-function-body:  # in: (addr buffered-file), out: (addr function), vars: (addr stack live-var), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    56/push-esi
    57/push-edi
    # esi = in
    8b/-> *(ebp+8) 6/r32/esi
    # edi = out
    8b/-> *(ebp+0xc) 7/r32/edi
    # initialize some global state
    c7 0/subop/copy *Curr-block-depth 1/imm32
    # parse-mu-block(in, vars, out, out->body)
    8d/copy-address *(edi+0x18) 0/r32/eax  # Function-body
    (parse-mu-block %esi *(ebp+0x10) %edi %eax *(ebp+0x14) *(ebp+0x18))
$populate-mu-function-body:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# parses a block, assuming that the leading '{' has already been read by the caller
parse-mu-block:  # in: (addr buffered-file), vars: (addr stack live-var), fn: (addr function), out: (addr handle block), err: (addr buffered-file), ed: (addr exit-descriptor)
    # pseudocode:
    #   var line: (stream byte 512)
    #   var word-slice: slice
    #   allocate(Heap, Stmt-size, out)
    #   var out-addr: (addr block) = lookup(*out)
    #   out-addr->tag = 0/block
    #   out-addr->var = some unique name
    #   push(vars, {out-addr->var, false})
    #   while true                                  # line loop
    #     clear-stream(line)
    #     read-line-buffered(in, line)
    #     if (line->write == 0) break               # end of file
    #     word-slice = next-mu-token(line)
    #     if slice-empty?(word-slice)               # end of line
    #       continue
    #     else if slice-starts-with?(word-slice, "#")
    #       continue
    #     else if slice-equal?(word-slice, "{")
    #       assert(no-tokens-in(line))
    #       block = parse-mu-block(in, vars, fn)
    #       append-to-block(out-addr, block)
    #     else if slice-equal?(word-slice, "}")
    #       break
    #     else if slice-ends-with?(word-slice, ":")
    #       # TODO: error-check the rest of 'line'
    #       --word-slice->end to skip ':'
    #       named-block = parse-mu-named-block(word-slice, in, vars, fn)
    #       append-to-block(out-addr, named-block)
    #     else if slice-equal?(word-slice, "var")
    #       var-def = parse-mu-var-def(line, vars, fn)
    #       append-to-block(out-addr, var-def)
    #     else
    #       stmt = parse-mu-stmt(line, vars, fn)
    #       append-to-block(out-addr, stmt)
    #   pop(vars)
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    57/push-edi
    # var line/ecx: (stream byte 512)
    81 5/subop/subtract %esp 0x200/imm32
    68/push 0x200/imm32/size
    68/push 0/imm32/read
    68/push 0/imm32/write
    89/<- %ecx 4/r32/esp
    # var word-slice/edx: slice
    68/push 0/imm32/end
    68/push 0/imm32/start
    89/<- %edx 4/r32/esp
    # allocate into out
    (allocate Heap *Stmt-size *(ebp+0x14))
    # var out-addr/edi: (addr block) = lookup(*out)
    8b/-> *(ebp+0x14) 7/r32/edi
    (lookup *edi *(edi+4))  # => eax
    89/<- %edi 0/r32/eax
    # out-addr->tag is 0 (block) by default
    # set out-addr->var
    8d/copy-address *(edi+0xc) 0/r32/eax  # Block-var
    (new-block-name *(ebp+0x10) %eax)
    # push(vars, out-addr->var)
    (push *(ebp+0xc) *(edi+0xc))  # Block-var
    (push *(ebp+0xc) *(edi+0x10))  # Block-var
    (push *(ebp+0xc) 0)  # false
    # increment *Curr-block-depth
    ff 0/subop/increment *Curr-block-depth
    {
$parse-mu-block:line-loop:
      # line = read-line-buffered(in)
      (clear-stream %ecx)
      (read-line-buffered *(ebp+8) %ecx)
#?       (write-buffered Stderr "line: ")
#?       (write-stream-data Stderr %ecx)
#? #?       (write-buffered Stderr Newline)  # line has its own newline
#?       (flush Stderr)
#?       (rewind-stream %ecx)
      # if (line->write == 0) break
      81 7/subop/compare *ecx 0/imm32
      0f 84/jump-if-= break/disp32
#?       (write-buffered Stderr "vars:\n")
#?       (dump-vars *(ebp+0xc))
      # word-slice = next-mu-token(line)
      (next-mu-token %ecx %edx)
#?       (write-buffered Stderr "word: ")
#?       (write-slice-buffered Stderr %edx)
#?       (write-buffered Stderr Newline)
#?       (flush Stderr)
      # if slice-empty?(word-slice) continue
      (slice-empty? %edx)
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= loop/disp32
      # if (slice-starts-with?(word-slice, '#') continue
      # . eax = *word-slice->start
      8b/-> *edx 0/r32/eax
      8a/copy-byte *eax 0/r32/AL
      81 4/subop/and %eax 0xff/imm32
      # . if (eax == '#') continue
      3d/compare-eax-and 0x23/imm32/hash
      0f 84/jump-if-= loop/disp32
      # if slice-equal?(word-slice, "{")
      {
$parse-mu-block:check-for-block:
        (slice-equal? %edx "{")
        3d/compare-eax-and 0/imm32/false
        74/jump-if-= break/disp8
        (check-no-tokens-left %ecx)
        # parse new block and append
        # . var tmp/eax: (handle block)
        68/push 0/imm32
        68/push 0/imm32
        89/<- %eax 4/r32/esp
        # .
        (parse-mu-block *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
        (append-to-block Heap %edi  *eax *(eax+4))
        # . reclaim tmp
        81 0/subop/add %esp 8/imm32
        # .
        e9/jump $parse-mu-block:line-loop/disp32
      }
      # if slice-equal?(word-slice, "}") break
$parse-mu-block:check-for-end:
      (slice-equal? %edx "}")
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= break/disp32
      # if slice-ends-with?(word-slice, ":") parse named block and append
      {
$parse-mu-block:check-for-named-block:
        # . eax = *(word-slice->end-1)
        8b/-> *(edx+4) 0/r32/eax
        48/decrement-eax
        8a/copy-byte *eax 0/r32/AL
        81 4/subop/and %eax 0xff/imm32
        # . if (eax != ':') break
        3d/compare-eax-and 0x3a/imm32/colon
        0f 85/jump-if-!= break/disp32
        # TODO: error-check the rest of 'line'
        #
        # skip ':'
        ff 1/subop/decrement *(edx+4)  # Slice-end
        # var tmp/eax: (handle block)
        68/push 0/imm32
        68/push 0/imm32
        89/<- %eax 4/r32/esp
        #
        (parse-mu-named-block %edx *(ebp+8) *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
        (append-to-block Heap %edi  *eax *(eax+4))
        # reclaim tmp
        81 0/subop/add %esp 8/imm32
        #
        e9/jump $parse-mu-block:line-loop/disp32
      }
      # if slice-equal?(word-slice, "var")
      {
$parse-mu-block:check-for-var:
        (slice-equal? %edx "var")
        3d/compare-eax-and 0/imm32/false
        74/jump-if-= break/disp8
        # var tmp/eax: (handle block)
        68/push 0/imm32
        68/push 0/imm32
        89/<- %eax 4/r32/esp
        #
        (parse-mu-var-def %ecx *(ebp+0xc) %eax *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
        (append-to-block Heap %edi  *eax *(eax+4))
        # reclaim tmp
        81 0/subop/add %esp 8/imm32
        #
        e9/jump $parse-mu-block:line-loop/disp32
      }
$parse-mu-block:regular-stmt:
      # otherwise
      # var tmp/eax: (handle block)
      68/push 0/imm32
      68/push 0/imm32
      89/<- %eax 4/r32/esp
      #
      (parse-mu-stmt %ecx *(ebp+0xc) *(ebp+0x10) %eax *(ebp+0x18) *(ebp+0x1c))
      (append-to-block Heap %edi  *eax *(eax+4))
      # reclaim tmp
      81 0/subop/add %esp 8/imm32
      #
      e9/jump loop/disp32
    } # end line loop
    (clean-up-blocks *(ebp+0xc) *Curr-block-depth *(ebp+0x10))
    # decrement *Curr-block-depth
    ff 1/subop/decrement *Curr-block-depth
    # pop(vars)
    (pop *(ebp+0xc))  # => eax
    (pop *(ebp+0xc))  # => eax
    (pop *(ebp+0xc))  # => eax
$parse-mu-block:end:
    # . reclaim locals
    81 0/subop/add %esp 0x214/imm32
    # . restore registers
    5f/pop-to-edi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$parse-mu-block:abort:
    # error("'{' or '}' should be on its own line, but got '")
    (write-buffered *(ebp+0x18) "'{' or '}' should be on its own line, but got '")
    (rewind-stream %ecx)
    (write-stream-data *(ebp+0x18) %ecx)
    (write-buffered *(ebp+0x18) "'\n")
    (flush *(ebp+0x18))
    (stop *(ebp+0x1c) 1)
    # never gets here

new-block-name:  # fn: (addr function), out: (addr handle var)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    # var n/ecx: int = len(fn->name) + 10 for an int + 2 for '$:'
    8b/-> *(ebp+8) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    8b/-> *eax 0/r32/eax  # String-size
    05/add-to-eax 0xd/imm32  # 10 + 2 for '$:'
    89/<- %ecx 0/r32/eax
    # var name/edx: (stream byte n)
    29/subtract-from %esp 1/r32/ecx
    ff 6/subop/push %ecx
    68/push 0/imm32/read
    68/push 0/imm32/write
    89/<- %edx 4/r32/esp
    (clear-stream %edx)
    # eax = fn->name
    8b/-> *(ebp+8) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    # construct result using Next-block-index (and increment it)
    (write %edx "$")
    (write %edx %eax)
    (write %edx ":")
    (write-int32-hex %edx *Next-block-index)
    ff 0/subop/increment *Next-block-index
    # var s/eax: slice = {name->data, name->data + name->write}  (clobbering edx)
    # . eax = name->write
    8b/-> *edx 0/r32/eax
    # . edx = name->data
    8d/copy-address *(edx+0xc) 2/r32/edx
    # . eax = name->write + name->data
    01/add-to %eax 2/r32/edx
    # . push {edx, eax}
    ff 6/subop/push %eax
    ff 6/subop/push %edx
    89/<- %eax 4/r32/esp
    # out = new literal(s)
    (new-literal Heap %eax *(ebp+0xc))
#?     8b/-> *(ebp+0xc) 0/r32/eax
#?     (write-buffered Stderr "type allocid in caller after new-literal: ")
#?     (write-int32-hex-buffered Stderr *(eax+8))
#?     (write-buffered Stderr " for var ")
#?     (write-int32-hex-buffered Stderr %eax)
#?     (write-buffered Stderr Newline)
#?     (flush Stderr)
$new-block-name:end:
    # . reclaim locals
    81 0/subop/add %ecx 0xc/imm32  # name.{read/write/len}
    81 0/subop/add %ecx 8/imm32  # slice
    01/add-to %esp 1/r32/ecx
    # . restore registers
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

check-no-tokens-left:  # line: (addr stream byte)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    # var s/ecx: slice
    68/push 0/imm32/end
    68/push 0/imm32/start
    89/<- %ecx 4/r32/esp
    #
    (next-mu-token *(ebp+8) %ecx)
    # if slice-empty?(s) return
    (slice-empty? %ecx)
    3d/compare-eax-and 0/imm32/false
    75/jump-if-!= $check-no-tokens-left:end/disp8
    # if (slice-starts-with?(s, '#') return
    # . eax = *s->start
    8b/-> *edx 0/r32/eax
    8a/copy-byte *eax 0/r32/AL
    81 4/subop/and %eax 0xff/imm32
    # . if (eax == '#') continue
    3d/compare-eax-and 0x23/imm32/hash
    74/jump-if-= $check-no-tokens-left:end/disp8
    # abort
    (write-buffered Stderr "'{' or '}' should be on its own line, but got '")
    (rewind-stream %ecx)
    (write-stream 2 %ecx)
    (write-buffered Stderr "'\n")
    (flush Stderr)
    # . syscall(exit, 1)
    bb/copy-to-ebx  1/imm32
    e8/call syscall_exit/disp32
    # never gets here
$check-no-tokens-left:end:
    # . reclaim locals
    81 0/subop/add %esp 8/imm32
    # . restore registers
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

parse-mu-named-block:  # name: (addr slice), in: (addr buffered-file), vars: (addr stack live-var), fn: (addr function), out: (addr handle stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
    # pseudocode:
    #   var v: (handle var)
    #   new-literal(name, v)
    #   push(vars, {v, false})
    #   parse-mu-block(in, vars, fn, out)
    #   pop(vars)
    #   out->tag = block
    #   out->var = v
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    57/push-edi
    # var v/ecx: (handle var)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %ecx 4/r32/esp
    #
    (new-literal Heap *(ebp+8) %ecx)
    # push(vars, v)
    (push *(ebp+0x10) *ecx)
    (push *(ebp+0x10) *(ecx+4))
    (push *(ebp+0x10) 0)  # false
    #
    (parse-mu-block *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20))
    # pop v off vars
    (pop *(ebp+0x10))  # => eax
    (pop *(ebp+0x10))  # => eax
    (pop *(ebp+0x10))  # => eax
    # var out-addr/edi: (addr stmt) = lookup(*out)
    8b/-> *(ebp+0x18) 7/r32/edi
    (lookup *edi *(edi+4))  # => eax
    89/<- %edi 0/r32/eax
    # out-addr->tag = named-block
    c7 0/subop/copy *edi 0/imm32/block  # Stmt-tag
    # out-addr->var = v
    8b/-> *ecx 0/r32/eax
    89/<- *(edi+0xc) 0/r32/eax  # Block-var
    8b/-> *(ecx+4) 0/r32/eax
    89/<- *(edi+0x10) 0/r32/eax  # Block-var
$parse-mu-named-block:end:
    # . reclaim locals
    81 0/subop/add %esp 8/imm32
    # . restore registers
    5f/pop-to-edi
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

parse-mu-var-def:  # line: (addr stream byte), vars: (addr stack live-var), out: (addr handle stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    57/push-edi
    # edi = out
    8b/-> *(ebp+0x10) 7/r32/edi
    # var word-slice/ecx: slice
    68/push 0/imm32/end
    68/push 0/imm32/start
    89/<- %ecx 4/r32/esp
    # var v/edx: (handle var)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    # v = parse-var-with-type(next-mu-token(line))
    (next-mu-token *(ebp+8) %ecx)
    (parse-var-with-type %ecx *(ebp+8) %edx *(ebp+0x18) *(ebp+0x1c))
    # var v-addr/eax: (addr var)
    (lookup *edx *(edx+4))  # => eax
    # v->block-depth = *Curr-block-depth
    8b/-> *Curr-block-depth 3/r32/ebx
    89/<- *(eax+0x10) 3/r32/ebx  # Var-block-depth
    # either v has no register and there's no more to this line
    8b/-> *(eax+0x18) 0/r32/eax  # Var-register
    3d/compare-eax-and 0/imm32
    {
      75/jump-if-!= break/disp8
      # TODO: disallow vars of type 'byte' on the stack
      # ensure that there's nothing else on this line
      (next-mu-token *(ebp+8) %ecx)
      (slice-empty? %ecx)  # => eax
      3d/compare-eax-and 0/imm32/false
      0f 84/jump-if-= $parse-mu-var-def:error2/disp32
      #
      (new-var-def Heap  *edx *(edx+4)  %edi)
      e9/jump $parse-mu-var-def:update-vars/disp32
    }
    # or v has a register and there's more to this line
    {
      0f 84/jump-if-= break/disp32
      # TODO: disallow vars of type 'byte' in registers 'esi' or 'edi'
      # TODO: vars of type 'byte' should only be initialized by clearing to 0
      # ensure that the next word is '<-'
      (next-mu-token *(ebp+8) %ecx)
      (slice-equal? %ecx "<-")  # => eax
      3d/compare-eax-and 0/imm32/false
      0f 84/jump-if-= $parse-mu-var-def:error1/disp32
      #
      (new-reg-var-def Heap  *edx *(edx+4)  %edi)
      (lookup *edi *(edi+4))  # => eax
      (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
    }
$parse-mu-var-def:update-vars:
    # push 'v' at end of function
    (push *(ebp+0xc) *edx)
    (push *(ebp+0xc) *(edx+4))
    (push *(ebp+0xc) 0)  # Live-var-register-spilled is unused during parsing
$parse-mu-var-def:end:
    # . reclaim locals
    81 0/subop/add %esp 0x10/imm32
    # . restore registers
    5f/pop-to-edi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$parse-mu-var-def:error1:
    (rewind-stream *(ebp+8))
    # error("register variable requires a valid instruction to initialize but got '" line "'\n")
    (write-buffered *(ebp+0x18) "register variable requires a valid instruction to initialize but got '")
    (flush *(ebp+0x18))
    (write-stream-data *(ebp+0x18) *(ebp+8))
    (write-buffered *(ebp+0x18) "'\n")
    (flush *(ebp+0x18))
    (stop *(ebp+0x1c) 1)
    # never gets here

$parse-mu-var-def:error2:
    (rewind-stream *(ebp+8))
    # error("fn " fn ": var " var ": variables on the stack can't take an initializer\n")
    (write-buffered *(ebp+0x18) "fn ")
    8b/-> *(ebp+0x14) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x18) %eax)
    (write-buffered *(ebp+0x18) ": var ")
    # var v-addr/eax: (addr var) = lookup(v)
    (lookup *edx *(edx+4))  # => eax
    (lookup *eax *(eax+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+0x18) %eax)
    (write-buffered *(ebp+0x18) ": variables on the stack can't take an initializer\n")
    (flush *(ebp+0x18))
    (stop *(ebp+0x1c) 1)
    # never gets here

test-parse-mu-var-def:
    # 'var n: int'
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (write _test-input-stream "n: int\n")  # caller has consumed the 'var'
    c7 0/subop/copy *Curr-block-depth 1/imm32
    # var out/esi: (handle stmt)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %esi 4/r32/esp
    # var vars/ecx: (stack (addr var) 16)
    81 5/subop/subtract %esp 0xc0/imm32
    68/push 0xc0/imm32/size
    68/push 0/imm32/top
    89/<- %ecx 4/r32/esp
    (clear-stack %ecx)
    # convert
    (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
    # var out-addr/esi: (addr stmt)
    (lookup *esi *(esi+4))  # => eax
    89/<- %esi 0/r32/eax
    #
    (check-ints-equal *esi 2 "F - test-parse-mu-var-def/tag")  # Stmt-tag is var-def
    # var v/ecx: (addr var) = lookup(out->var)
    (lookup *(esi+4) *(esi+8))  # Vardef-var Vardef-var => eax
    89/<- %ecx 0/r32/eax
    # v->name
    (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
    (check-strings-equal %eax "n" "F - test-parse-mu-var-def/var-name")
    # v->register
    (check-ints-equal *(ecx+0x18) 0 "F - test-parse-mu-var-def/var-register")  # Var-register
    # v->block-depth
    (check-ints-equal *(ecx+0x10) 1 "F - test-parse-mu-var-def/output-block-depth")  # Var-block-depth
    # v->type == int
    (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
    (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0")  # Type-tree-is-atom
    (check-ints-equal *(eax+4) 1 "F - test-parse-mu-var-def/var-type:1")  # Type-tree-value
    (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-var-def/var-type:2")  # Type-tree-right
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-parse-mu-reg-var-def:
    # 'var n/eax: int <- copy 0'
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (write _test-input-stream "n/eax: int <- copy 0\n")  # caller has consumed the 'var'
    c7 0/subop/copy *Curr-block-depth 1/imm32
    # var out/esi: (handle stmt)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %esi 4/r32/esp
    # var vars/ecx: (stack (addr var) 16)
    81 5/subop/subtract %esp 0xc0/imm32
    68/push 0xc0/imm32/size
    68/push 0/imm32/top
    89/<- %ecx 4/r32/esp
    (clear-stack %ecx)
    # convert
    (parse-mu-var-def _test-input-stream %ecx %esi 0 Stderr 0)
    # var out-addr/esi: (addr stmt)
    (lookup *esi *(esi+4))  # => eax
    89/<- %esi 0/r32/eax
    #
    (check-ints-equal *esi 3 "F - test-parse-mu-reg-var-def/tag")  # Stmt-tag is reg-var-def
    # var v/ecx: (addr var) = lookup(out->outputs->value)
    # . eax: (addr stmt-var) = lookup(out->outputs)
    (lookup *(esi+0x14) *(esi+0x18))  # Regvardef-outputs Regvardef-outputs => eax
    # .
    (check-ints-equal *(eax+8) 0 "F - test-parse-mu-reg-var-def/single-output")  # Stmt-var-next
    # . eax: (addr var) = lookup(eax->value)
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    # . ecx = eax
    89/<- %ecx 0/r32/eax
    # v->name
    (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
    (check-strings-equal %eax "n" "F - test-parse-mu-reg-var-def/output-name")  # Var-name
    # v->register
    (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
    (check-strings-equal %eax "eax" "F - test-parse-mu-reg-var-def/output-register")
    # v->block-depth
    (check-ints-equal *(ecx+0x10) 1 "F - test-parse-mu-reg-var-def/output-block-depth")  # Var-block-depth
    # v->type == int
    (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
    (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/output-type:0")  # Type-tree-is-atom
    (check-ints-equal *(eax+4) 1 "F - test-parse-mu-reg-var-def/output-type:1")  # Type-tree-value
    (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-reg-var-def/output-type:2")  # Type-tree-right
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

parse-mu-stmt:  # line: (addr stream byte), vars: (addr stack live-var), fn: (addr function), out: (addr handle stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
    # Carefully push any outputs on the vars stack _after_ reading the inputs
    # that may conflict with them.
    #
    # The only situation in which outputs are pushed here (when it's not a
    # 'var' vardef stmt), and so can possibly conflict with inputs, is if the
    # output is a function output.
    #
    # pseudocode:
    #   var name: slice
    #   allocate(Heap, Stmt-size, out)
    #   var out-addr: (addr stmt) = lookup(*out)
    #   out-addr->tag = stmt
    #   if stmt-has-outputs?(line)
    #     while true
    #       name = next-mu-token(line)
    #       if (name == '<-') break
    #       assert(is-identifier?(name))
    #       var v: (handle var) = lookup-var-or-find-in-fn-outputs(name, vars, fn)
    #       out-addr->outputs = append(v, out-addr->outputs)
    #   add-operation-and-inputs-to-stmt(out-addr, line, vars)
    #   for output in stmt->outputs:
    #     maybe-define-var(output, vars)
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    57/push-edi
    # var name/ecx: slice
    68/push 0/imm32/end
    68/push 0/imm32/start
    89/<- %ecx 4/r32/esp
    # var is-deref?/edx: boolean = false
    ba/copy-to-edx 0/imm32/false
    # var v: (handle var)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %ebx 4/r32/esp
    #
    (allocate Heap *Stmt-size *(ebp+0x14))
    # var out-addr/edi: (addr stmt) = lookup(*out)
    8b/-> *(ebp+0x14) 7/r32/edi
    (lookup *edi *(edi+4))  # => eax
    89/<- %edi 0/r32/eax
    # out-addr->tag = 1/stmt
    c7 0/subop/copy *edi 1/imm32/stmt1  # Stmt-tag
    {
      (stmt-has-outputs? *(ebp+8))
      3d/compare-eax-and 0/imm32/false
      0f 84/jump-if-= break/disp32
      {
$parse-mu-stmt:read-outputs:
        # name = next-mu-token(line)
        (next-mu-token *(ebp+8) %ecx)
        # if slice-empty?(word-slice) break
        (slice-empty? %ecx)  # => eax
        3d/compare-eax-and 0/imm32/false
        0f 85/jump-if-!= break/disp32
        # if (name == "<-") break
        (slice-equal? %ecx "<-")  # => eax
        3d/compare-eax-and 0/imm32/false
        0f 85/jump-if-!= break/disp32
        # is-deref? = false
        ba/copy-to-edx 0/imm32/false
        # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
        8b/-> *ecx 0/r32/eax  # Slice-start
        8a/copy-byte *eax 0/r32/AL
        81 4/subop/and %eax 0xff/imm32
        3d/compare-eax-and 0x2a/imm32/asterisk
        {
          75/jump-if-!= break/disp8
          ff 0/subop/increment *ecx
          ba/copy-to-edx 1/imm32/true
        }
        # assert(is-identifier?(name))
        (is-identifier? %ecx)  # => eax
        3d/compare-eax-and 0/imm32/false
        0f 84/jump-if-= $parse-mu-stmt:abort/disp32
        #
        (lookup-var-or-find-in-fn-outputs %ecx *(ebp+0xc) *(ebp+0x10) %ebx *(ebp+0x18) *(ebp+0x1c))
        8d/copy-address *(edi+0x14) 0/r32/eax  # Stmt1-outputs
        (append-stmt-var Heap  *ebx *(ebx+4)  *(edi+0x14) *(edi+0x18)  %edx  %eax)  # Stmt1-outputs
        #
        e9/jump loop/disp32
      }
    }
    (add-operation-and-inputs-to-stmt %edi *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))
$parse-mu-stmt:define-outputs:
    # var output/edi: (addr stmt-var) = lookup(out-addr->outputs)
    (lookup *(edi+0x14) *(edi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
    89/<- %edi 0/r32/eax
    {
$parse-mu-stmt:define-outputs-loop:
      # if (output == null) break
      81 7/subop/compare %edi 0/imm32
      74/jump-if-= break/disp8
      #
      (maybe-define-var *edi *(edi+4)  *(ebp+0xc))  # if output is a deref, then it's already been defined,
                                                    # and must be in vars. This call will be a no-op, but safe.
      # output = output->next
      (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
      89/<- %edi 0/r32/eax
      #
      eb/jump loop/disp8
    }
$parse-mu-stmt:end:
    # . reclaim locals
    81 0/subop/add %esp 0x10/imm32
    # . restore registers
    5f/pop-to-edi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$parse-mu-stmt:abort:
    # error("invalid identifier '" name "'\n")
    (write-buffered *(ebp+0x18) "invalid identifier '")
    (write-slice-buffered *(ebp+0x18) %ecx)
    (write-buffered *(ebp+0x18) "'\n")
    (flush *(ebp+0x18))
    (stop *(ebp+0x1c) 1)
    # never gets here

add-operation-and-inputs-to-stmt:  # stmt: (addr stmt), line: (addr stream byte), vars: (addr stack live-var), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # pseudocode:
    #   stmt->name = slice-to-string(next-mu-token(line))
    #   while true
    #     name = next-mu-token(line)
    #     v = lookup-var-or-literal(name)
    #     stmt->inouts = append(v, stmt->inouts)
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    56/push-esi
    57/push-edi
    # edi = stmt
    8b/-> *(ebp+8) 7/r32/edi
    # var name/ecx: slice
    68/push 0/imm32/end
    68/push 0/imm32/start
    89/<- %ecx 4/r32/esp
    # var is-deref?/edx: boolean = false
    ba/copy-to-edx 0/imm32/false
    # var v/esi: (handle var)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %esi 4/r32/esp
$add-operation-and-inputs-to-stmt:read-operation:
    (next-mu-token *(ebp+0xc) %ecx)
    8d/copy-address *(edi+4) 0/r32/eax  # Stmt1-operation or Regvardef-operationStmt1-operation or Regvardef-operation
    (slice-to-string Heap %ecx %eax)
    # var is-get?/ebx: boolean = (name == "get")
    (slice-equal? %ecx "get")  # => eax
    89/<- %ebx 0/r32/eax
    {
$add-operation-and-inputs-to-stmt:read-inouts:
      # name = next-mu-token(line)
      (next-mu-token *(ebp+0xc) %ecx)
      # if slice-empty?(word-slice) break
      (slice-empty? %ecx)  # => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= break/disp32
      # if (name == "<-") abort
      (slice-equal? %ecx "<-")
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= $add-operation-and-inputs-to-stmt:abort/disp32
      # if (is-get? && second operand) lookup or create offset
      {
        81 7/subop/compare %ebx 0/imm32/false
        74/jump-if-= break/disp8
        (lookup *(edi+0xc) *(edi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
        3d/compare-eax-and 0/imm32
        74/jump-if-= break/disp8
        (lookup-or-create-constant %eax %ecx %esi)
#?         (lookup *esi *(esi+4))
#?         (write-buffered Stderr "creating new output var ")
#?         (write-int32-hex-buffered Stderr %eax)
#?         (write-buffered Stderr " for field called ")
#?         (write-slice-buffered Stderr %ecx)
#?         (write-buffered Stderr "; var name ")
#?         (lookup *eax *(eax+4))  # Var-name
#?         (write-buffered Stderr %eax)
#?         (write-buffered Stderr Newline)
#?         (flush Stderr)
        e9/jump $add-operation-and-inputs-to-stmt:save-var/disp32
      }
      # is-deref? = false
      ba/copy-to-edx 0/imm32/false
      # if (slice-starts-with?(name, '*')) ++name->start and set is-deref?
      8b/-> *ecx 0/r32/eax  # Slice-start
      8a/copy-byte *eax 0/r32/AL
      81 4/subop/and %eax 0xff/imm32
      3d/compare-eax-and 0x2a/imm32/asterisk
      {
        75/jump-if-!= break/disp8
$add-operation-and-inputs-to-stmt:inout-is-deref:
        ff 0/subop/increment *ecx
        ba/copy-to-edx 1/imm32/true
      }
      (lookup-var-or-literal %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
$add-operation-and-inputs-to-stmt:save-var:
      8d/copy-address *(edi+0xc) 0/r32/eax
      (append-stmt-var Heap  *esi *(esi+4)  *(edi+0xc) *(edi+0x10)  %edx  %eax)  # Stmt1-inouts or Regvardef-inouts
      #
      e9/jump loop/disp32
    }
$add-operation-and-inputs-to-stmt:end:
    # . reclaim locals
    81 0/subop/add %esp 0x10/imm32
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$add-operation-and-inputs-to-stmt:abort:
    # error("fn ___: invalid identifier in '" line "'\n")
    (write-buffered *(ebp+0x18) "fn ")
    8b/-> *(ebp+0x14) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x18) %eax)
    (rewind-stream *(ebp+0xc))
    (write-buffered *(ebp+0x18) ": invalid identifier in '")
    (write-stream-data *(ebp+0x18) *(ebp+0xc))
    (write-buffered *(ebp+0x18) "'\n")
    (flush *(ebp+0x18))
    (stop *(ebp+0x1c) 1)
    # never gets here

stmt-has-outputs?:  # line: (addr stream byte) -> result/eax: boolean
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    # var word-slice/ecx: slice
    68/push 0/imm32/end
    68/push 0/imm32/start
    89/<- %ecx 4/r32/esp
    # result = false
    b8/copy-to-eax 0/imm32/false
    (rewind-stream *(ebp+8))
    {
      (next-mu-token *(ebp+8) %ecx)
      # if slice-empty?(word-slice) break
      (slice-empty? %ecx)
      3d/compare-eax-and 0/imm32/false
      b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
      0f 85/jump-if-!= break/disp32
      # if slice-starts-with?(word-slice, '#') break
      # . eax = *word-slice->start
      8b/-> *ecx 0/r32/eax
      8a/copy-byte *eax 0/r32/AL
      81 4/subop/and %eax 0xff/imm32
      # . if (eax == '#') break
      3d/compare-eax-and 0x23/imm32/hash
      b8/copy-to-eax 0/imm32/false/result  # restore result (if we're here it's still false)
      0f 84/jump-if-= break/disp32
      # if slice-equal?(word-slice, '<-') return true
      (slice-equal? %ecx "<-")
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= loop/disp8
      b8/copy-to-eax 1/imm32/true
    }
$stmt-has-outputs:end:
    (rewind-stream *(ebp+8))
    # . reclaim locals
    81 0/subop/add %esp 8/imm32
    # . restore registers
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# if 'name' starts with a digit, create a new literal var for it
# otherwise return first 'name' from the top (back) of 'vars' and abort if not found
lookup-var-or-literal:  # name: (addr slice), vars: (addr stack live-var), out: (addr handle var), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    56/push-esi
    # esi = name
    8b/-> *(ebp+8) 6/r32/esi
    # if slice-empty?(name) abort
    (slice-empty? %esi)  # => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $lookup-var-or-literal:abort/disp32
    # var c/ecx: byte = *name->start
    8b/-> *esi 1/r32/ecx
    8a/copy-byte *ecx 1/r32/CL
    81 4/subop/and %ecx 0xff/imm32
    # if (is-decimal-digit?(c) || c == '-') return new var(name)
    {
      81 7/subop/compare %ecx 0x2d/imm32/dash
      74/jump-if-= $lookup-var-or-literal:literal/disp8
      (is-decimal-digit? %ecx)  # => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
$lookup-var-or-literal:literal:
      (new-literal-integer Heap %esi *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
      eb/jump $lookup-var-or-literal:end/disp8
    }
    # else if (c == '"') return new var(name)
    {
      81 7/subop/compare %ecx 0x22/imm32/dquote
      75/jump-if-!= break/disp8
$lookup-var-or-literal:literal-string:
      (new-literal Heap %esi *(ebp+0x10))
      eb/jump $lookup-var-or-literal:end/disp8
    }
    # otherwise return lookup-var(name, vars)
    {
$lookup-var-or-literal:var:
      (lookup-var %esi *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
    }
$lookup-var-or-literal:end:
    # . restore registers
    5e/pop-to-esi
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$lookup-var-or-literal:abort:
    (write-buffered *(ebp+0x18) "fn ")
    8b/-> *(ebp+0x14) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x18) %eax)
    (write-buffered *(ebp+0x18) ": empty variable!")
    (flush *(ebp+0x18))
    (stop *(ebp+0x1c) 1)
    # never gets here

# return first 'name' from the top (back) of 'vars' and abort if not found
lookup-var:  # name: (addr slice), vars: (addr stack live-var), out: (addr handle var), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    #
    (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
    # if (*out == 0) abort
    8b/-> *(ebp+0x10) 0/r32/eax
    81 7/subop/compare *eax 0/imm32
    74/jump-if-= $lookup-var:abort/disp8
$lookup-var:end:
    # . restore registers
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$lookup-var:abort:
    (write-buffered *(ebp+0x18) "fn ")
    8b/-> *(ebp+0x14) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x18) %eax)
    (write-buffered *(ebp+0x18) ": unknown variable '")
    (write-slice-buffered *(ebp+0x18) *(ebp+8))
    (write-buffered *(ebp+0x18) "'\n")
    (flush *(ebp+0x18))
    (stop *(ebp+0x1c) 1)
    # never gets here

# return first 'name' from the top (back) of 'vars', and 0/null if not found
# ensure that 'name' if in a register is the topmost variable in that register
lookup-var-helper:  # name: (addr slice), vars: (addr stack live-var), out: (addr handle var), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # pseudocode:
    #   var curr: (addr handle var) = &vars->data[vars->top - 12]
    #   var min = vars->data
    #   while curr >= min
    #     var v: (handle var) = *curr
    #     if v->name == name
    #       return
    #     curr -= 12
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    56/push-esi
    57/push-edi
    # clear out
    (zero-out *(ebp+0x10) *Handle-size)
    # esi = vars
    8b/-> *(ebp+0xc) 6/r32/esi
    # ebx = vars->top
    8b/-> *esi 3/r32/ebx
    # if (vars->top > vars->size) abort
    3b/compare<- *(esi+4) 0/r32/eax
    0f 8f/jump-if-> $lookup-var-helper:error1/disp32
    # var min/edx: (addr handle var) = vars->data
    8d/copy-address *(esi+8) 2/r32/edx
    # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
    8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
    # var var-in-reg/edi: 8 addrs
    68/push 0/imm32
    68/push 0/imm32
    68/push 0/imm32
    68/push 0/imm32
    68/push 0/imm32
    68/push 0/imm32
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edi 4/r32/esp
    {
$lookup-var-helper:loop:
      # if (curr < min) return
      39/compare %ebx 2/r32/edx
      0f 82/jump-if-addr< break/disp32
      # var v/ecx: (addr var) = lookup(*curr)
      (lookup *ebx *(ebx+4))  # => eax
      89/<- %ecx 0/r32/eax
      # var vn/eax: (addr array byte) = lookup(v->name)
      (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
      # if (vn == name) return curr
      (slice-equal? *(ebp+8) %eax)  # => eax
      3d/compare-eax-and 0/imm32/false
      {
        74/jump-if-= break/disp8
$lookup-var-helper:found:
        # var vr/eax: (addr array byte) = lookup(v->register)
        (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
        3d/compare-eax-and 0/imm32
        {
          74/jump-if-= break/disp8
$lookup-var-helper:found-register:
          # var reg/eax: int = get(Registers, vr)
          (get Mu-registers %eax 0xc "Mu-registers")  # => eax
          8b/-> *eax 0/r32/eax
          # if (var-in-reg[reg]) error
          8b/-> *(edi+eax<<2) 0/r32/eax
          3d/compare-eax-and 0/imm32
          0f 85/jump-if-!= $lookup-var-helper:error2/disp32
        }
$lookup-var-helper:return:
        # esi = out
        8b/-> *(ebp+0x10) 6/r32/esi
        # *out = *curr
        8b/-> *ebx 0/r32/eax
        89/<- *esi 0/r32/eax
        8b/-> *(ebx+4) 0/r32/eax
        89/<- *(esi+4) 0/r32/eax
        # return
        eb/jump $lookup-var-helper:end/disp8
      }
      # 'name' not yet found; update var-in-reg if v in register
      # . var vr/eax: (addr array byte) = lookup(v->register)
      (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
      # . if (var == 0) continue
      3d/compare-eax-and 0/imm32
      74/jump-if-= $lookup-var-helper:continue/disp8
      # . var reg/eax: int = get(Registers, vr)
      (get Mu-registers %eax 0xc "Mu-registers")  # => eax
      8b/-> *eax 0/r32/eax
      # . if (var-in-reg[reg] == 0) var-in-reg[reg] = v
      81 7/subop/compare *(edi+eax<<2) 0/imm32
      75/jump-if-!= $lookup-var-helper:continue/disp8
      89/<- *(edi+eax<<2) 1/r32/ecx
$lookup-var-helper:continue:
      # curr -= 12
      81 5/subop/subtract %ebx 0xc/imm32
      e9/jump loop/disp32
    }
$lookup-var-helper:end:
    # . reclaim locals
    81 0/subop/add %esp 0x20/imm32
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$lookup-var-helper:error1:
    (write-buffered *(ebp+0x18) "fn ")
    8b/-> *(ebp+0x14) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x18) %eax)
    (write-buffered *(ebp+0x18) ": malformed stack when looking up '")
    (write-slice-buffered *(ebp+0x18) *(ebp+8))
    (write-buffered *(ebp+0x18) "'\n")
    (flush *(ebp+0x18))
    (stop *(ebp+0x1c) 1)
    # never gets here

$lookup-var-helper:error2:
    # eax contains the conflicting var at this point
    (write-buffered *(ebp+0x18) "fn ")
    50/push-eax
    8b/-> *(ebp+0x14) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x18) %eax)
    58/pop-eax
    (write-buffered *(ebp+0x18) ": register ")
    50/push-eax
    (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
    (write-buffered *(ebp+0x18) %eax)
    58/pop-to-eax
    (write-buffered *(ebp+0x18) " reads var '")
    (write-slice-buffered *(ebp+0x18) *(ebp+8))
    (write-buffered *(ebp+0x18) "' after writing var '")
    (lookup *eax *(eax+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+0x18) %eax)
    (write-buffered *(ebp+0x18) "'\n")
    (flush *(ebp+0x18))
    (stop *(ebp+0x1c) 1)
    # never gets here

dump-vars:  # vars: (addr stack live-var)
    # pseudocode:
    #   var curr: (addr handle var) = &vars->data[vars->top - 12]
    #   var min = vars->data
    #   while curr >= min
    #     var v: (handle var) = *curr
    #     print v
    #     curr -= 12
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    52/push-edx
    53/push-ebx
    56/push-esi
    # esi = vars
    8b/-> *(ebp+8) 6/r32/esi
    # ebx = vars->top
    8b/-> *esi 3/r32/ebx
    # var min/edx: (addr handle var) = vars->data
    8d/copy-address *(esi+8) 2/r32/edx
    # var curr/ebx: (addr handle var) = &vars->data[vars->top - 12]
    8d/copy-address *(esi+ebx-4) 3/r32/ebx  # vars + 8 + vars->type - 12
    {
$dump-vars:loop:
      # if (curr < min) return
      39/compare %ebx 2/r32/edx
      0f 82/jump-if-addr< break/disp32
      #
      (write-buffered Stderr "  var@")
      (dump-var 2 %ebx)
      # curr -= 12
      81 5/subop/subtract %ebx 0xc/imm32
      e9/jump loop/disp32
    }
$dump-vars:end:
    # . restore registers
    5e/pop-to-esi
    5b/pop-to-ebx
    5a/pop-to-edx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

== data
# Like Registers, but no esp or ebp
Mu-registers:  # (addr stream {(handle array byte), int})
  # a table is a stream
  0x48/imm32/write
  0/imm32/read
  0x48/imm32/length
  # data
  # it is perfectly ok to use fake alloc-ids -- as long as you never try to reclaim them
  0x11/imm32/alloc-id $Mu-register-eax/imm32 0/imm32
  0x11/imm32/alloc-id $Mu-register-ecx/imm32 1/imm32
  0x11/imm32/alloc-id $Mu-register-edx/imm32 2/imm32
  0x11/imm32/alloc-id $Mu-register-ebx/imm32 3/imm32
  0x11/imm32/alloc-id $Mu-register-esi/imm32 6/imm32
  0x11/imm32/alloc-id $Mu-register-edi/imm32 7/imm32

$Mu-register-eax:
  0x11/imm32/alloc-id
  3/imm32/size
  0x65/e 0x61/a 0x78/x

$Mu-register-ecx:
  0x11/imm32/alloc-id
  3/imm32/size
  0x65/e 0x63/c 0x78/x

$Mu-register-edx:
  0x11/imm32/alloc-id
  3/imm32/size
  0x65/e 0x64/d 0x78/x

$Mu-register-ebx:
  0x11/imm32/alloc-id
  3/imm32/size
  0x65/e 0x62/b 0x78/x

$Mu-register-esi:
  0x11/imm32/alloc-id
  3/imm32/size
  0x65/e 0x73/s 0x69/i

$Mu-register-edi:
  0x11/imm32/alloc-id
  3/imm32/size
  0x65/e 0x64/d 0x69/i

== code

# return first 'name' from the top (back) of 'vars' and create a new var for a fn output if not found
lookup-var-or-find-in-fn-outputs:  # name: (addr slice), vars: (addr stack live-var), fn: (addr function), out: (addr handle var), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    #
    (lookup-var-helper *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x10) *(ebp+0x18) *(ebp+0x1c))  # arg order slightly different; 'fn' is deemphasized
    {
      # if (out != 0) return
      8b/-> *(ebp+0x14) 0/r32/eax
      81 7/subop/compare *eax 0/imm32
      75/jump-if-!= break/disp8
      # if name is one of fn's outputs, return it
      (find-in-function-outputs *(ebp+0x10) *(ebp+8) *(ebp+0x14))
      8b/-> *(ebp+0x14) 0/r32/eax
      81 7/subop/compare *eax 0/imm32
      # otherwise abort
      0f 84/jump-if-= $lookup-or-define-var:abort/disp32
    }
$lookup-or-define-var:end:
    # . restore registers
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$lookup-or-define-var:abort:
    (write-buffered *(ebp+0x18) "unknown variable '")
    (write-slice-buffered *(ebp+0x18) *(ebp+8))
    (write-buffered *(ebp+0x18) "'\n")
    (flush *(ebp+0x18))
    (stop *(ebp+0x1c) 1)
    # never gets here

find-in-function-outputs:  # fn: (addr function), name: (addr slice), out: (addr handle var)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    # var curr/ecx: (addr list var) = lookup(fn->outputs)
    8b/-> *(ebp+8) 1/r32/ecx
    (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
    89/<- %ecx 0/r32/eax
    # while curr != null
    {
      81 7/subop/compare %ecx 0/imm32
      74/jump-if-= break/disp8
      # var v/eax: (addr var) = lookup(curr->value)
      (lookup *ecx *(ecx+4))  # List-value List-value => eax
      # var s/eax: (addr array byte) = lookup(v->name)
      (lookup *eax *(eax+4))  # Var-name Var-name => eax
      # if (s == name) return curr->value
      (slice-equal? *(ebp+0xc) %eax)  # => eax
      3d/compare-eax-and 0/imm32/false
      {
        74/jump-if-= break/disp8
        # var edi = out
        57/push-edi
        8b/-> *(ebp+0x10) 7/r32/edi
        # *out = curr->value
        8b/-> *ecx 0/r32/eax
        89/<- *edi 0/r32/eax
        8b/-> *(ecx+4) 0/r32/eax
        89/<- *(edi+4) 0/r32/eax
        #
        5f/pop-to-edi
        eb/jump $find-in-function-outputs:end/disp8
      }
      # curr = curr->next
      (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
      89/<- %ecx 0/r32/eax
      #
      eb/jump loop/disp8
    }
    b8/copy-to-eax 0/imm32
$find-in-function-outputs:end:
    # . restore registers
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# push 'out' to 'vars' if not already there; it's assumed to be a fn output
maybe-define-var:  # out: (handle var), vars: (addr stack live-var)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    # var out-addr/eax: (addr var)
    (lookup *(ebp+8) *(ebp+0xc))  # => eax
    #
    (binding-exists? %eax *(ebp+0x10))  # => eax
    3d/compare-eax-and 0/imm32/false
    75/jump-if-!= $maybe-define-var:end/disp8
    # otherwise update vars
    (push *(ebp+0x10) *(ebp+8))
    (push *(ebp+0x10) *(ebp+0xc))
    (push *(ebp+0x10) 0)  # 'out' is always a fn output; never spill it
$maybe-define-var:end:
    # . restore registers
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# simpler version of lookup-var-helper
binding-exists?:  # target: (addr var), vars: (addr stack live-var) -> result/eax: boolean
    # pseudocode:
    #   var curr: (addr handle var) = &vars->data[vars->top - 12]
    #   var min = vars->data
    #   while curr >= min
    #     var v: (handle var) = *curr
    #     if v->name == target->name
    #       return true
    #     curr -= 12
    #   return false
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    52/push-edx
    56/push-esi
    # var target-name/ecx: (addr array byte) = lookup(target->name)
    8b/-> *(ebp+8) 0/r32/eax
    (lookup *eax *(eax+4))  # Var-name Var-name => eax
    89/<- %ecx 0/r32/eax
    # esi = vars
    8b/-> *(ebp+0xc) 6/r32/esi
    # eax = vars->top
    8b/-> *esi 0/r32/eax
    # var min/edx: (addr handle var) = vars->data
    8d/copy-address *(esi+8) 2/r32/edx
    # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
    8d/copy-address *(esi+eax-4) 6/r32/esi  # vars + 8 + vars->type - 12
    {
$binding-exists?:loop:
      # if (curr < min) return
      39/compare %esi 2/r32/edx
      0f 82/jump-if-addr< break/disp32
      # var v/eax: (addr var) = lookup(*curr)
      (lookup *esi *(esi+4))  # => eax
      # var vn/eax: (addr array byte) = lookup(v->name)
      (lookup *eax *(eax+4))  # Var-name Var-name => eax
      # if (vn == target-name) return true
      (string-equal? %ecx %eax)  # => eax
      3d/compare-eax-and 0/imm32/false
      75/jump-if-!= $binding-exists?:end/disp8  # eax already contains true
      # curr -= 12
      81 5/subop/subtract %esi 0xc/imm32
      e9/jump loop/disp32
    }
    b8/copy-to-eax 0/imm32/false
$binding-exists?:end:
    # . restore registers
    5e/pop-to-esi
    5a/pop-to-edx
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-parse-mu-stmt:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (write _test-input-stream "increment n\n")
    # var vars/ecx: (stack (addr var) 16)
    81 5/subop/subtract %esp 0xc0/imm32
    68/push 0xc0/imm32/size
    68/push 0/imm32/top
    89/<- %ecx 4/r32/esp
    (clear-stack %ecx)
    # var v/edx: (handle var)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    # var s/eax: (handle array byte)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %eax 4/r32/esp
    # v = new var("n")
    (copy-array Heap "n" %eax)
    (new-var Heap *eax *(eax+4) %edx)
    #
    (push %ecx *edx)
    (push %ecx *(edx+4))
    (push %ecx 0)
    # var out/eax: (handle stmt)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %eax 4/r32/esp
    # convert
    (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
    # var out-addr/edx: (addr stmt) = lookup(*out)
    (lookup *eax *(eax+4))  # => eax
    89/<- %edx 0/r32/eax
    # out->tag
    (check-ints-equal *edx 1 "F - test-parse-mu-stmt/tag")  # Stmt-tag is Stmt1
    # out->operation
    (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
    (check-strings-equal %eax "increment" "F - test-parse-mu-stmt/name")  # Stmt1-operation
    # out->inouts->value->name
    # . eax = out->inouts
    (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    # . eax = out->inouts->value
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    # . eax = out->inouts->value->name
    (lookup *eax *(eax+4))  # Var-name Var-name => eax
    # .
    (check-strings-equal %eax "n" "F - test-parse-mu-stmt/inout:0")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-parse-mu-stmt-with-comma:
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-input-stream)
    (write _test-input-stream "copy-to n, 3\n")
    # var vars/ecx: (stack (addr var) 16)
    81 5/subop/subtract %esp 0xc0/imm32
    68/push 0xc0/imm32/size
    68/push 0/imm32/top
    89/<- %ecx 4/r32/esp
    (clear-stack %ecx)
    # var v/edx: (handle var)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edx 4/r32/esp
    # var s/eax: (handle array byte)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %eax 4/r32/esp
    # v = new var("n")
    (copy-array Heap "n" %eax)
    (new-var Heap *eax *(eax+4) %edx)
    #
    (push %ecx *edx)
    (push %ecx *(edx+4))
    (push %ecx 0)
    # var out/eax: (handle stmt)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %eax 4/r32/esp
    # convert
    (parse-mu-stmt _test-input-stream %ecx 0 %eax Stderr 0)
    # var out-addr/edx: (addr stmt) = lookup(*out)
    (lookup *eax *(eax+4))  # => eax
    89/<- %edx 0/r32/eax
    # out->tag
    (check-ints-equal *edx 1 "F - test-parse-mu-stmt-with-comma/tag")  # Stmt-tag is Stmt1
    # out->operation
    (lookup *(edx+4) *(edx+8))  # Stmt1-operation Stmt1-operation => eax
    (check-strings-equal %eax "copy-to" "F - test-parse-mu-stmt-with-comma/name")  # Stmt1-operation
    # out->inouts->value->name
    # . eax = out->inouts
    (lookup *(edx+0xc) *(edx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    # . eax = out->inouts->value
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    # . eax = out->inouts->value->name
    (lookup *eax *(eax+4))  # Var-name Var-name => eax
    # .
    (check-strings-equal %eax "n" "F - test-parse-mu-stmt-with-comma/inout:0")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

new-var:  # ad: (addr allocation-descriptor), name: (handle array byte), out: (addr handle var)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    # ecx = out
    8b/-> *(ebp+0x14) 1/r32/ecx
    #
    (allocate *(ebp+8) *Var-size %ecx)
    # var out-addr/eax: (addr var)
    (lookup *ecx *(ecx+4))  # => eax
    # out-addr->name = name
    8b/-> *(ebp+0xc) 1/r32/ecx
    89/<- *eax 1/r32/ecx  # Var-name
    8b/-> *(ebp+0x10) 1/r32/ecx
    89/<- *(eax+4) 1/r32/ecx  # Var-name
#?     (write-buffered Stderr "var ")
#?     (lookup *(ebp+0xc) *(ebp+0x10))
#?     (write-buffered Stderr %eax)
#?     (write-buffered Stderr " at ")
#?     8b/-> *(ebp+0x14) 1/r32/ecx
#?     (lookup *ecx *(ecx+4))  # => eax
#?     (write-int32-hex-buffered Stderr %eax)
#?     (write-buffered Stderr Newline)
#?     (flush Stderr)
$new-var:end:
    # . restore registers
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

new-literal-integer:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    # if (!is-hex-int?(name)) abort
    (is-hex-int? *(ebp+0xc))  # => eax
    3d/compare-eax-and 0/imm32/false
    0f 84/jump-if-= $new-literal-integer:abort/disp32
    # a little more error-checking
    (check-mu-hex-int *(ebp+0xc) *(ebp+0x18) *(ebp+0x1c))
    # out = new var(s)
    (new-var-from-slice *(ebp+8) *(ebp+0xc) *(ebp+0x10))
    # var out-addr/ecx: (addr var) = lookup(*out)
    8b/-> *(ebp+0x10) 0/r32/eax
    (lookup *eax *(eax+4))  # => eax
    89/<- %ecx 0/r32/eax
    # out-addr->block-depth = *Curr-block-depth
    8b/-> *Curr-block-depth 0/r32/eax
    89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
    # out-addr->type = new tree()
    8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
    (allocate *(ebp+8) *Type-tree-size %eax)
    (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
    c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
    # nothing else to do; default type is 'literal'
$new-literal-integer:end:
    # . reclaim locals
    81 0/subop/add %esp 8/imm32
    # . restore registers
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$new-literal-integer:abort:
    (write-buffered *(ebp+0x18) "fn ")
    8b/-> *(ebp+0x14) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x18) %eax)
    (write-buffered *(ebp+0x18) ": variable '")
    (write-slice-buffered *(ebp+0x18) *(ebp+0xc))
    (write-buffered *(ebp+0x18) "' cannot begin with a digit (or do you have a typo in a number?)\n")
    (flush *(ebp+0x18))
    (stop *(ebp+0x1c) 1)
    # never gets here

# precondition: name is a valid hex integer; require a '0x' prefix
check-mu-hex-int:  # name: (addr slice), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    # ecx = name
    8b/-> *(ebp+8) 1/r32/ecx
    # var start/edx: (addr byte) = name->start
    8b/-> *ecx 2/r32/edx
    # if (*start == '-') ++start
    b8/copy-to-eax 0/imm32
    8a/copy-byte *edx 0/r32/AL
    3d/compare-eax-and 0x2d/imm32/dash
    {
      75/jump-if-!= break/disp8
      42/increment-edx
    }
    # var end/ecx: (addr byte) = name->end
    8b/-> *(ecx+4) 1/r32/ecx
    # var len/eax: int = name->end - name->start
    89/<- %eax 1/r32/ecx
    29/subtract-from %eax 2/r32/edx
    # if (len <= 1) return
    3d/compare-eax-with 1/imm32
    0f 8e/jump-if-<= $check-mu-hex-int:end/disp32
$check-mu-hex-int:length->-1:
    # if slice-starts-with?({start, end}, "0x") return
    # . var tmp = {start, end}
    51/push-ecx
    52/push-edx
    89/<- %eax 4/r32/esp
    # .
    (slice-starts-with? %eax "0x")  # => eax
    # . reclaim tmp
    81 0/subop/add %esp 8/imm32
    # .
    3d/compare-eax-with 0/imm32/false
    75/jump-if-!= $check-mu-hex-int:end/disp8
$check-mu-hex-int:abort:
    # otherwise abort
    (write-buffered *(ebp+0xc) "literal integers are always hex in Mu; either start '")
    (write-slice-buffered *(ebp+0xc) *(ebp+8))
    (write-buffered *(ebp+0xc) "' with a '0x' to be unambiguous, or convert it to decimal.\n")
    (flush *(ebp+0xc))
    (stop *(ebp+0x10) 1)
$check-mu-hex-int:end:
    # . restore registers
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

new-literal:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    # var s/ecx: (handle array byte)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %ecx 4/r32/esp
    # s = slice-to-string(name)
    (slice-to-string Heap *(ebp+0xc) %ecx)
    # allocate to out
    (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
    # var out-addr/ecx: (addr var) = lookup(*out)
    8b/-> *(ebp+0x10) 1/r32/ecx
    (lookup *ecx *(ecx+4))  # => eax
    89/<- %ecx 0/r32/eax
    # out-addr->block-depth = *Curr-block-depth
    8b/-> *Curr-block-depth 0/r32/eax
    89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
    # out-addr->type/eax = new type
    8d/copy-address *(ecx+8) 0/r32/eax  # Var-type
    (allocate *(ebp+8) *Type-tree-size %eax)
    (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
    # nothing else to do; default type is 'literal'
    c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
$new-literal:end:
    # . reclaim locals
    81 0/subop/add %esp 8/imm32
    # . restore registers
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

new-var-from-slice:  # ad: (addr allocation-descriptor), name: (addr slice), out: (addr handle var)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    # var tmp/ecx: (handle array byte)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %ecx 4/r32/esp
    # tmp = slice-to-string(name)
    (slice-to-string Heap *(ebp+0xc) %ecx)
    # out = new-var(tmp)
    (new-var *(ebp+8) *ecx *(ecx+4) *(ebp+0x10))
$new-var-from-slice:end:
    # . reclaim locals
    81 0/subop/add %esp 8/imm32
    # . restore registers
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

new-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    #
    (allocate *(ebp+8) *Stmt-size *(ebp+0x14))
    # var out-addr/eax: (addr stmt) = lookup(*out)
    8b/-> *(ebp+0x14) 0/r32/eax
    (lookup *eax *(eax+4))  # => eax
    # out-addr->tag = stmt
    c7 0/subop/copy *eax 2/imm32/tag/var-on-stack  # Stmt-tag
    # result->var = var
    8b/-> *(ebp+0xc) 1/r32/ecx
    89/<- *(eax+4) 1/r32/ecx  # Vardef-var
    8b/-> *(ebp+0x10) 1/r32/ecx
    89/<- *(eax+8) 1/r32/ecx  # Vardef-var
$new-var-def:end:
    # . restore registers
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

new-reg-var-def:  # ad: (addr allocation-descriptor), var: (handle var), out: (addr handle stmt)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    # eax = out
    8b/-> *(ebp+0x14) 0/r32/eax
    #
    (allocate *(ebp+8) *Stmt-size %eax)
    # var out-addr/eax: (addr stmt) = lookup(*out)
    (lookup *eax *(eax+4))  # => eax
    # set tag
    c7 0/subop/copy *eax 3/imm32/tag/var-in-register  # Stmt-tag
    # set output
    8d/copy-address *(eax+0x14) 0/r32/eax  # Regvardef-outputs
    (append-stmt-var Heap  *(ebp+0xc) *(ebp+0x10)  0 0  0  %eax)
$new-reg-var-def:end:
    # . restore registers
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

append-list:  # ad: (addr allocation-descriptor), value: (handle _type), list: (handle list _type), out: (addr handle list _type)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    57/push-edi
    # edi = out
    8b/-> *(ebp+0x1c) 7/r32/edi
    # *out = new list
    (allocate *(ebp+8) *List-size %edi)
    # var out-addr/edi: (addr list _type) = lookup(*out)
    (lookup *edi *(edi+4))  # => eax
    89/<- %edi 0/r32/eax
    # out-addr->value = value
    8b/-> *(ebp+0xc) 0/r32/eax
    89/<- *edi 0/r32/eax  # List-value
    8b/-> *(ebp+0x10) 0/r32/eax
    89/<- *(edi+4) 0/r32/eax  # List-value
    # if (list == null) return
    81 7/subop/compare *(ebp+0x14) 0/imm32
    74/jump-if-= $append-list:end/disp8
    # otherwise append
$append-list:non-empty-list:
    # var curr/eax: (addr list _type) = lookup(list)
    (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
    # while (curr->next != null) curr = curr->next
    {
      81 7/subop/compare *(eax+8) 0/imm32  # List-next
      74/jump-if-= break/disp8
      # curr = lookup(curr->next)
      (lookup *(eax+8) *(eax+0xc))  # List-next, List-next => eax
      #
      eb/jump loop/disp8
    }
    # edi = out
    8b/-> *(ebp+0x1c) 7/r32/edi
    # curr->next = out
    8b/-> *edi 1/r32/ecx
    89/<- *(eax+8) 1/r32/ecx  # List-next
    8b/-> *(edi+4) 1/r32/ecx
    89/<- *(eax+0xc) 1/r32/ecx  # List-next
    # out = list
    8b/-> *(ebp+0x14) 1/r32/ecx
    89/<- *edi 1/r32/ecx
    8b/-> *(ebp+0x18) 1/r32/ecx
    89/<- *(edi+4) 1/r32/ecx
$append-list:end:
    # . restore registers
    5f/pop-to-edi
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

append-stmt-var:  # ad: (addr allocation-descriptor), v: (handle var), vars: (handle stmt-var), is-deref?: boolean, out: (addr handle stmt-var)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    57/push-edi
    # edi = out
    8b/-> *(ebp+0x20) 7/r32/edi
    # out = new stmt-var
    (allocate *(ebp+8) *Stmt-var-size %edi)
    # var out-addr/ecx: (addr stmt-var) = lookup(*out)
    (lookup *edi *(edi+4))  # => eax
    89/<- %ecx 0/r32/eax
    # out-addr->value = v
    8b/-> *(ebp+0xc) 0/r32/eax
    89/<- *ecx 0/r32/eax  # Stmt-var-value
    8b/-> *(ebp+0x10) 0/r32/eax
    89/<- *(ecx+4) 0/r32/eax  # Stmt-var-value
    # out-addr->is-deref? = is-deref?
    8b/-> *(ebp+0x1c) 0/r32/eax
    89/<- *(ecx+0x10) 0/r32/eax  # Stmt-var-is-deref
    # if (vars == null) return result
    81 7/subop/compare *(ebp+0x14) 0/imm32/null
    74/jump-if-= $append-stmt-var:end/disp8
    # otherwise append
    # var curr/eax: (addr stmt-var) = lookup(vars)
    (lookup *(ebp+0x14) *(ebp+0x18))  # => eax
    # while (curr->next != null) curr = curr->next
    {
      81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
      74/jump-if-= break/disp8
      # curr = lookup(curr->next)
      (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next, Stmt-var-next => eax
      #
      eb/jump loop/disp8
    }
    # curr->next = out
    8b/-> *edi 1/r32/ecx
    89/<- *(eax+8) 1/r32/ecx  # Stmt-var-next
    8b/-> *(edi+4) 1/r32/ecx
    89/<- *(eax+0xc) 1/r32/ecx  # Stmt-var-next
    # out = vars
    8b/-> *(ebp+0x14) 1/r32/ecx
    89/<- *edi 1/r32/ecx
    8b/-> *(ebp+0x18) 1/r32/ecx
    89/<- *(edi+4) 1/r32/ecx
$append-stmt-var:end:
    # . restore registers
    5f/pop-to-edi
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

append-to-block:  # ad: (addr allocation-descriptor), block: (addr block), x: (handle stmt)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    56/push-esi
    # esi = block
    8b/-> *(ebp+0xc) 6/r32/esi
    # block->stmts = append(x, block->stmts)
    8d/copy-address *(esi+4) 0/r32/eax  # Block-stmts
    (append-list *(ebp+8)  *(ebp+0x10) *(ebp+0x14)  *(esi+4) *(esi+8)  %eax)  # ad, x, x, Block-stmts, Block-stmts
$append-to-block:end:
    # . restore registers
    5e/pop-to-esi
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

## Parsing types
# We need to create metadata on user-defined types, and we need to use this
# metadata as we parse instructions.
# However, we also want to allow types to be used before their definitions.
# This means we can't ever assume any type data structures exist.

lookup-or-create-constant:  # container: (addr stmt-var), field-name: (addr slice), out: (addr handle var)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    56/push-esi
    # var container-type/esi: type-id
    (container-type *(ebp+8))  # => eax
    89/<- %esi 0/r32/eax
    # var tmp/eax: (handle typeinfo) = find-or-create-typeinfo(container-type)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %eax 4/r32/esp
    (find-or-create-typeinfo %esi %eax)
    # var tmp-addr/eax: (addr typeinfo) = lookup(tmp)
    (lookup *eax *(eax+4))  # => eax
    # result = find-or-create-typeinfo-output-var(typeinfo, field-name)
#?     (write-buffered Stderr "constant: ")
#?     (write-slice-buffered Stderr *(ebp+0xc))
#?     (write-buffered Stderr Newline)
#?     (flush Stderr)
    (find-or-create-typeinfo-output-var %eax *(ebp+0xc) *(ebp+0x10))
#?     8b/-> *(ebp+0x10) 0/r32/eax
#?     (write-buffered Stderr "@")
#?     (lookup *eax *(eax+4))
#?     (write-int32-hex-buffered Stderr %eax)
#?     (lookup *eax *(eax+4))
#?     (write-buffered Stderr %eax)
#?     (write-buffered Stderr Newline)
#?     (flush Stderr)
#?     (write-buffered Stderr "offset: ")
#?     8b/-> *(eax+0x14) 0/r32/eax
#?     (write-int32-hex-buffered Stderr %eax)
#?     (write-buffered Stderr Newline)
#?     (flush Stderr)
$lookup-or-create-constant:end:
    # . reclaim locals
    81 0/subop/add %esp 8/imm32
    # . restore registers
    5e/pop-to-esi
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# if addr var:
#   container->var->type->right->left->value
# otherwise
#   container->var->type->value
container-type:  # container: (addr stmt-var) -> result/eax: type-id
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    #
    8b/-> *(ebp+8) 0/r32/eax
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
    {
      81 7/subop/compare *(eax+8) 0/imm32  # Type-tree-right
      74/jump-if-= break/disp8
      (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
      (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
    }
    8b/-> *(eax+4) 0/r32/eax  # Type-tree-value
$container-type:end:
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

is-container?:  # t: type-id -> result/eax: boolean
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    #
    8b/-> *(ebp+8) 0/r32/eax
    c1/shift 4/subop/left %eax 2/imm8
    3b/compare 0/r32/eax *Primitive-type-ids
    0f 9d/set-if->= %al
    81 4/subop/and %eax 0xff/imm32
$is-container?:end:
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

find-or-create-typeinfo:  # t: type-id, out: (addr handle typeinfo)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    57/push-edi
    # edi = out
    8b/-> *(ebp+0xc) 7/r32/edi
    # var fields/ecx: (handle table (handle array byte) (handle typeinfo-entry))
    68/push 0/imm32
    68/push 0/imm32
    89/<- %ecx 4/r32/esp
    # find-typeinfo(t, out)
    (find-typeinfo *(ebp+8) %edi)
    {
      # if (*out != 0) break
      81 7/subop/compare *edi 0/imm32
      0f 85/jump-if-!= break/disp32
$find-or-create-typeinfo:create:
      # *out = allocate
      (allocate Heap *Typeinfo-size %edi)
      # var tmp/eax: (addr typeinfo) = lookup(*out)
      (lookup *edi *(edi+4))  # => eax
#?     (write-buffered Stderr "created typeinfo at ")
#?     (write-int32-hex-buffered Stderr %eax)
#?     (write-buffered Stderr " for type-id ")
#?     (write-int32-hex-buffered Stderr *(ebp+8))
#?     (write-buffered Stderr Newline)
#?     (flush Stderr)
      # tmp->id = t
      8b/-> *(ebp+8) 2/r32/edx
      89/<- *eax 2/r32/edx  # Typeinfo-id
      # tmp->fields = new table
      # . fields = new table
      (new-stream Heap 0x40 *Typeinfo-fields-row-size %ecx)
      # . tmp->fields = fields
      8b/-> *ecx 2/r32/edx
      89/<- *(eax+4) 2/r32/edx  # Typeinfo-fields
      8b/-> *(ecx+4) 2/r32/edx
      89/<- *(eax+8) 2/r32/edx  # Typeinfo-fields
      # tmp->next = Program->types
      8b/-> *_Program-types 1/r32/ecx
      89/<- *(eax+0x10) 1/r32/ecx  # Typeinfo-next
      8b/-> *_Program-types->payload 1/r32/ecx
      89/<- *(eax+0x14) 1/r32/ecx  # Typeinfo-next
      # Program->types = out
      8b/-> *edi 1/r32/ecx
      89/<- *_Program-types 1/r32/ecx
      8b/-> *(edi+4) 1/r32/ecx
      89/<- *_Program-types->payload 1/r32/ecx
    }
$find-or-create-typeinfo:end:
    # . reclaim locals
    81 0/subop/add %esp 8/imm32
    # . restore registers
    5f/pop-to-edi
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

find-typeinfo:  # t: type-id, out: (addr handle typeinfo)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    57/push-edi
    # ecx = t
    8b/-> *(ebp+8) 1/r32/ecx
    # edi = out
    8b/-> *(ebp+0xc) 7/r32/edi
    # *out = Program->types
    8b/-> *_Program-types 0/r32/eax
    89/<- *edi 0/r32/eax
    8b/-> *_Program-types->payload 0/r32/eax
    89/<- *(edi+4) 0/r32/eax
    {
$find-typeinfo:loop:
      # if (*out == 0) break
      81 7/subop/compare *edi 0/imm32
      74/jump-if-= break/disp8
$find-typeinfo:check:
      # var tmp/eax: (addr typeinfo) = lookup(*out)
      (lookup *edi *(edi+4))  # => eax
      # if (tmp->id == t) break
      39/compare *eax 1/r32/ecx  # Typeinfo-id
      74/jump-if-= break/disp8
$find-typeinfo:continue:
      # *out = tmp->next
      8b/-> *(eax+0x10) 2/r32/edx  # Typeinfo-next
      89/<- *edi 2/r32/edx
      8b/-> *(eax+0x14) 2/r32/edx  # Typeinfo-next
      89/<- *(edi+4) 2/r32/edx
      #
      eb/jump loop/disp8
    }
$find-typeinfo:end:
    # . restore registers
    5f/pop-to-edi
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

find-or-create-typeinfo-output-var:  # T: (addr typeinfo), f: (addr slice), out: (addr handle var)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    52/push-edx
    57/push-edi
    # var dest/edi: (handle typeinfo-entry)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %edi 4/r32/esp
    # find-or-create-typeinfo-fields(T, f, dest)
    (find-or-create-typeinfo-fields *(ebp+8) *(ebp+0xc) %edi)
    # var dest-addr/edi: (addr typeinfo-entry) = lookup(dest)
    (lookup *edi *(edi+4))  # => eax
    89/<- %edi 0/r32/eax
    # if dest-addr->output-var doesn't exist, create it
    {
      81 7/subop/compare *(edi+0xc) 0/imm32  # Typeinfo-entry-output-var
      0f 85/jump-if-!= break/disp32
      # dest-addr->output-var = new var(dummy name, type, -1 offset)
      # . var name/eax: (handle array byte) = "field"
      68/push 0/imm32
      68/push 0/imm32
      89/<- %eax 4/r32/esp
      (slice-to-string Heap *(ebp+0xc) %eax)
      # . new var
      8d/copy-address *(edi+0xc) 2/r32/edx
      (new-var Heap  *eax *(eax+4)  %edx)
      # . reclaim name
      81 0/subop/add %esp 8/imm32
      # var result/edx: (addr var) = lookup(dest-addr->output-var)
      (lookup *(edi+0xc) *(edi+0x10))  # => eax
      89/<- %edx 0/r32/eax
      # result->type = new constant type
      8d/copy-address *(edx+8) 0/r32/eax  # Var-type
      (allocate Heap *Type-tree-size %eax)
      (lookup *(edx+8) *(edx+0xc))  # => eax
      c7 0/subop/copy *eax 1/imm32/true  # Type-tree-is-atom
      c7 0/subop/copy *(eax+4) 6/imm32/constant  # Type-tree-value
      c7 0/subop/copy *(eax+8) 0/imm32  # Type-tree-left
      c7 0/subop/copy *(eax+0xc) 0/imm32  # Type-tree-right
      c7 0/subop/copy *(eax+0x10) 0/imm32  # Type-tree-right
      # result->offset isn't filled out yet
      c7 0/subop/copy *(edx+0x14) -1/imm32/uninitialized  # Var-offset
    }
    # out = dest-addr->output-var
    8b/-> *(ebp+0x10) 2/r32/edx
    8b/-> *(edi+0xc) 0/r32/eax  # Typeinfo-entry-output-var
    89/<- *edx 0/r32/eax
    8b/-> *(edi+0x10) 0/r32/eax  # Typeinfo-entry-output-var
    89/<- *(edx+4) 0/r32/eax
$find-or-create-typeinfo-output-var:end:
    # . reclaim locals
    81 0/subop/add %esp 8/imm32
    # . restore registers
    5f/pop-to-edi
    5a/pop-to-edx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

find-or-create-typeinfo-fields:  # T: (addr typeinfo), f: (addr slice), out: (addr handle typeinfo-entry)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    56/push-esi
    57/push-edi
    # eax = lookup(T->fields)
    8b/-> *(ebp+8) 0/r32/eax
    (lookup *(eax+4) *(eax+8))  # Typeinfo-fields Typeinfo-fields => eax
    # edi = out
    8b/-> *(ebp+0x10) 7/r32/edi
    # var src/esi: (addr handle typeinfo-entry) = get-or-insert-slice(T->fields, f)
    (get-or-insert-slice %eax *(ebp+0xc) *Typeinfo-fields-row-size Heap)  # => eax
    89/<- %esi 0/r32/eax
    # if src doesn't exist, allocate it
    {
      81 7/subop/compare *esi 0/imm32
      75/jump-if-!= break/disp8
      (allocate Heap *Typeinfo-entry-size %esi)
#?       (write-buffered Stderr "handle at ")
#?       (write-int32-hex-buffered Stderr %esi)
#?       (write-buffered Stderr ": ")
#?       (write-int32-hex-buffered Stderr *esi)
#?       (write-buffered Stderr " ")
#?       (write-int32-hex-buffered Stderr *(esi+4))
#?       (write-buffered Stderr Newline)
#?       (flush Stderr)
#?       (lookup *esi *(esi+4))
#?       (write-buffered Stderr "created typeinfo fields at ")
#?       (write-int32-hex-buffered Stderr %esi)
#?       (write-buffered Stderr " for ")
#?       (write-int32-hex-buffered Stderr *(ebp+8))
#?       (write-buffered Stderr Newline)
#?       (flush Stderr)
    }
    # *out = src
    # . *edi = *src
    8b/-> *esi 0/r32/eax
    89/<- *edi 0/r32/eax
    8b/-> *(esi+4) 0/r32/eax
    89/<- *(edi+4) 0/r32/eax
$find-or-create-typeinfo-fields:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

populate-mu-type:  # in: (addr stream byte), t: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
    # pseudocode:
    #   var line: (stream byte 512)
    #   curr-index = 0
    #   while true
    #     clear-stream(line)
    #     read-line-buffered(in, line)
    #     if line->write == 0
    #       abort
    #     word-slice = next-mu-token(line)
    #     if slice-empty?(word-slice)               # end of line
    #       continue
    #     if slice-equal?(word-slice, "}")
    #       break
    #     var v: (handle var) = parse-var-with-type(word-slice, line)
    #     var r: (handle typeinfo-fields) = find-or-create-typeinfo-fields(t, word-slice/v->name)
    #     TODO: ensure that r->first is null
    #     r->index = curr-index
    #     curr-index++
    #     r->input-var = v
    #     if r->output-var == 0
    #       r->output-var = new literal
    #     TODO: ensure nothing else in line
    # t->total-size-in-bytes = -2 (not yet initialized)
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # var curr-index: int at *(ebp-4)
    68/push 0/imm32
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    56/push-esi
    57/push-edi
    # edi = t
    8b/-> *(ebp+0xc) 7/r32/edi
    # var line/ecx: (stream byte 512)
    81 5/subop/subtract %esp 0x200/imm32
    68/push 0x200/imm32/size
    68/push 0/imm32/read
    68/push 0/imm32/write
    89/<- %ecx 4/r32/esp
    # var word-slice/edx: slice
    68/push 0/imm32/end
    68/push 0/imm32/start
    89/<- %edx 4/r32/esp
    # var v/esi: (handle var)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %esi 4/r32/esp
    # var r/ebx: (handle typeinfo-entry)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %ebx 4/r32/esp
    {
$populate-mu-type:line-loop:
      (clear-stream %ecx)
      (read-line-buffered *(ebp+8) %ecx)
      # if (line->write == 0) abort
      81 7/subop/compare *ecx 0/imm32
      0f 84/jump-if-= $populate-mu-type:error1/disp32
#?       # dump line {{{
#?       (write 2 "parse-mu: ^")
#?       (write-stream 2 %ecx)
#?       (write 2 "$\n")
#?       (rewind-stream %ecx)
#?       # }}}
      (next-mu-token %ecx %edx)
      # if slice-empty?(word-slice) continue
      (slice-empty? %edx)  # => eax
      3d/compare-eax-and 0/imm32
      0f 85/jump-if-!= loop/disp32
      # if slice-equal?(word-slice, "}") break
      (slice-equal? %edx "}")
      3d/compare-eax-and 0/imm32
      0f 85/jump-if-!= break/disp32
$populate-mu-type:parse-element:
      # v = parse-var-with-type(word-slice, first-line)
      # must do this first to strip the trailing ':' from word-slice before
      # using it in find-or-create-typeinfo-fields below
      # TODO: clean up that mutation in parse-var-with-type
      (parse-var-with-type %edx %ecx %esi *(ebp+0x10) *(ebp+0x14))
      # if v is an addr, abort
      (lookup *esi *(esi+4))  # => eax
      (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
      (is-mu-addr-type? %eax)  # => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= $populate-mu-type:error2/disp32
      # if v is an array, abort  (we could support it, but initialization gets complex)
      (lookup *esi *(esi+4))  # => eax
      (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
      (is-mu-array-type? %eax)  # => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= $populate-mu-type:error3/disp32
      # if v is a byte, abort
      (lookup *esi *(esi+4))  # => eax
      (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
      (is-simple-mu-type? %eax 8)  # byte => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= $populate-mu-type:error4/disp32
      # if v is a slice, abort
      (lookup *esi *(esi+4))  # => eax
      (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
      (is-simple-mu-type? %eax 0xc)  # slice => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= $populate-mu-type:error5/disp32
      # if v is a stream, abort  (we could support it, but initialization gets even more complex)
      (lookup *esi *(esi+4))  # => eax
      (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
      (is-mu-stream-type? %eax)  # => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= $populate-mu-type:error6/disp32
      # var tmp/ecx
      51/push-ecx
$populate-mu-type:create-typeinfo-fields:
      # var r/ebx: (handle typeinfo-entry)
      (find-or-create-typeinfo-fields %edi %edx %ebx)
      # r->index = curr-index
      (lookup *ebx *(ebx+4))  # => eax
      8b/-> *(ebp-4) 1/r32/ecx
#?       (write-buffered Stderr "saving index ")
#?       (write-int32-hex-buffered Stderr %ecx)
#?       (write-buffered Stderr " at ")
#?       (write-int32-hex-buffered Stderr %edi)
#?       (write-buffered Stderr Newline)
#?       (flush Stderr)
      89/<- *(eax+8) 1/r32/ecx  # Typeinfo-entry-index
      # ++curr-index
      ff 0/subop/increment *(ebp-4)
$populate-mu-type:set-input-type:
      # r->input-var = v
      8b/-> *esi 1/r32/ecx
      89/<- *eax 1/r32/ecx  # Typeinfo-entry-input-var
      8b/-> *(esi+4) 1/r32/ecx
      89/<- *(eax+4) 1/r32/ecx  # Typeinfo-entry-input-var
      # restore line
      59/pop-to-ecx
      {
$populate-mu-type:create-output-type:
        # if (r->output-var == 0) create a new var with some placeholder data
        81 7/subop/compare *(eax+0xc) 0/imm32  # Typeinfo-entry-output-var
        75/jump-if-!= break/disp8
        8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
        (new-literal Heap %edx %eax)
      }
      e9/jump loop/disp32
    }
$populate-mu-type:invalidate-total-size-in-bytes:
    # Offsets and total size may not be accurate here since we may not yet
    # have encountered the element types.
    # We'll recompute them separately after parsing the entire program.
    c7 0/subop/copy *(edi+0xc) -2/imm32/uninitialized  # Typeinfo-total-size-in-bytes
$populate-mu-type:end:
    # . reclaim locals
    81 0/subop/add %esp 0x224/imm32
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # reclaim curr-index
    81 0/subop/add %esp 4/imm32
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$populate-mu-type:error1:
    # error("incomplete type definition '" t->name "'\n")
    (write-buffered *(ebp+0x10) "incomplete type definition '")
    (type-name *edi)  # Typeinfo-id => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) "\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$populate-mu-type:error2:
    (write-buffered *(ebp+0x10) "type ")
    (type-name *edi)  # Typeinfo-id => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": 'addr' elements not allowed\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$populate-mu-type:error3:
    (write-buffered *(ebp+0x10) "type ")
    (type-name *edi)  # Typeinfo-id => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": 'array' elements not allowed for now\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$populate-mu-type:error4:
    (write-buffered *(ebp+0x10) "type ")
    (type-name *edi)  # Typeinfo-id => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": 'byte' elements not allowed\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$populate-mu-type:error5:
    (write-buffered *(ebp+0x10) "type ")
    (type-name *edi)  # Typeinfo-id => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": 'slice' elements not allowed\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$populate-mu-type:error6:
    (write-buffered *(ebp+0x10) "type ")
    (type-name *edi)  # Typeinfo-id => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": 'stream' elements not allowed for now\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

type-name:  # index: int -> result/eax: (addr array byte)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    #
    (index Type-id *(ebp+8))
$type-name:end:
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

index:  # arr: (addr stream (handle array byte)), index: int -> result/eax: (addr array byte)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    56/push-esi
    # TODO: bounds-check index
    # esi = arr
    8b/-> *(ebp+8) 6/r32/esi
    # eax = index
    8b/-> *(ebp+0xc) 0/r32/eax
    # eax = *(arr + 12 + index)
    8b/-> *(esi+eax<<2+0xc) 0/r32/eax
$index:end:
    # . restore registers
    5e/pop-to-esi
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

#######################################################
# Compute type sizes
#######################################################

# Compute the sizes of all user-defined types.
# We'll need the sizes of their elements, which may be other user-defined
# types, which we will compute as needed.

# Initially, all user-defined types have their sizes set to -2 (invalid)
populate-mu-type-sizes:  # err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
$populate-mu-type-sizes:total-sizes:
    # var curr/eax: (addr typeinfo) = lookup(Program->types)
    (lookup *_Program-types *_Program-types->payload)  # => eax
    {
      # if (curr == null) break
      3d/compare-eax-and 0/imm32/null
      74/jump-if-= break/disp8
      (populate-mu-type-sizes-in-type %eax *(ebp+8) *(ebp+0xc))
      # curr = lookup(curr->next)
      (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
      eb/jump loop/disp8
    }
$populate-mu-type-sizes:offsets:
    # curr = *Program->types
    (lookup *_Program-types *_Program-types->payload)  # => eax
    {
      # if (curr == null) break
      3d/compare-eax-and 0/imm32/null
      74/jump-if-= break/disp8
      (populate-mu-type-offsets %eax *(ebp+8) *(ebp+0xc))
      # curr = curr->next
      (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
      eb/jump loop/disp8
    }
$populate-mu-type-sizes:end:
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# compute sizes of all fields, recursing as necessary
# sum up all their sizes to arrive at total size
# fields may be out of order, but that doesn't affect the answer
populate-mu-type-sizes-in-type:  # T: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    56/push-esi
    57/push-edi
    # esi = T
    8b/-> *(ebp+8) 6/r32/esi
    # if T is already computed, return
    81 7/subop/compare *(esi+0xc) 0/imm32  # Typeinfo-total-size-in-bytes
    0f 8d/jump-if->= $populate-mu-type-sizes-in-type:end/disp32
    # if T is being computed, abort
    81 7/subop/compare *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
    0f 84/jump-if-= $populate-mu-type-sizes-in-type:abort/disp32
    # tag T (-2 to -1) to avoid infinite recursion
    c7 0/subop/copy *(esi+0xc) -1/imm32/being-computed  # Typeinfo-total-size-in-bytes
    # var total-size/edi: int = 0
    bf/copy-to-edi 0/imm32
    # - for every field, if it's a user-defined type, compute its size
    # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
    (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
    89/<- %ecx 0/r32/eax
    # var table-size/edx: int = table->write
    8b/-> *ecx 2/r32/edx  # stream-write
    # var curr/ecx: (addr table_row) = table->data
    8d/copy-address *(ecx+0xc) 1/r32/ecx
    # var max/edx: (addr table_row) = table->data + table->write
    8d/copy-address *(ecx+edx) 2/r32/edx
    {
$populate-mu-type-sizes-in-type:loop:
      # if (curr >= max) break
      39/compare %ecx 2/r32/edx
      73/jump-if-addr>= break/disp8
      # var t/eax: (addr typeinfo-entry) = lookup(curr->value)
      (lookup *(ecx+8) *(ecx+0xc))  # => eax
      # if (t->input-var == 0) silently ignore it; we'll emit a nice error message while type-checking
      81 7/subop/compare *eax 0/imm32  # Typeinfo-entry-input-var
      74/jump-if-= $populate-mu-type-sizes-in-type:end/disp8
      # compute size of t->input-var
      (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
      (compute-size-of-var %eax *(ebp+0xc) *(ebp+0x10))  # => eax
      # result += eax
      01/add-to %edi 0/r32/eax
      # curr += row-size
      81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
      #
      eb/jump loop/disp8
    }
    # - save result
    89/<- *(esi+0xc) 7/r32/edi  # Typeinfo-total-size-in-bytes
$populate-mu-type-sizes-in-type:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$populate-mu-type-sizes-in-type:abort:
    (write-buffered *(ebp+0xc) "cycle in type definitions\n")
    (flush *(ebp+0xc))
    (stop *(ebp+0x10) 1)
    # never gets here

# Analogous to size-of, except we need to compute what size-of can just read
# off the right data structures.
compute-size-of-var:  # in: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . push registers
    51/push-ecx
    # var t/ecx: (addr type-tree) = lookup(v->type)
    8b/-> *(ebp+8) 1/r32/ecx
    (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
    89/<- %ecx 0/r32/eax
    # if (t->is-atom == false) t = lookup(t->left)
    {
      81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
      75/jump-if-!= break/disp8
      (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
      89/<- %ecx 0/r32/eax
    }
    # TODO: ensure t is an atom
    (compute-size-of-type-id *(ecx+4) *(ebp+0xc) *(ebp+0x10))  # Type-tree-value => eax
$compute-size-of-var:end:
    # . restore registers
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

compute-size-of-type-id:  # t: type-id, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    # var out/ecx: (handle typeinfo)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %ecx 4/r32/esp
    # eax = t
    8b/-> *(ebp+8) 0/r32/eax
    # if t is a literal, return 0
    3d/compare-eax-and 0/imm32/literal
    0f 84/jump-if-= $compute-size-of-type-id:end/disp32  # eax changes type from type-id to int
    # if t is a byte, return 4 (because we don't really support non-multiples of 4)
    3d/compare-eax-and 8/imm32/byte
    {
      75/jump-if-!= break/disp8
      b8/copy-to-eax 4/imm32
      eb/jump $compute-size-of-type-id:end/disp8
    }
    # if t is a handle, return 8
    3d/compare-eax-and 4/imm32/handle
    {
      75/jump-if-!= break/disp8
      b8/copy-to-eax 8/imm32
      eb/jump $compute-size-of-type-id:end/disp8  # eax changes type from type-id to int
    }
    # if t is a slice, return 8
    3d/compare-eax-and 0xc/imm32/slice
    {
      75/jump-if-!= break/disp8
      b8/copy-to-eax 8/imm32
      eb/jump $compute-size-of-type-id:end/disp8  # eax changes type from type-id to int
    }
    # if t is a user-defined type, compute its size
    # TODO: support non-atom type
    (find-typeinfo %eax %ecx)
    {
      81 7/subop/compare *ecx 0/imm32
      74/jump-if-= break/disp8
$compute-size-of-type-id:user-defined:
      (lookup *ecx *(ecx+4))  # => eax
      (populate-mu-type-sizes-in-type %eax *(ebp+0xc) *(ebp+0x10))
      8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
      eb/jump $compute-size-of-type-id:end/disp8
    }
    # otherwise return the word size
    b8/copy-to-eax 4/imm32
$compute-size-of-type-id:end:
    # . reclaim locals
    81 0/subop/add %esp 8/imm32
    # . restore registers
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# at this point we have total sizes for all user-defined types
# compute offsets for each element
# complication: fields may be out of order
populate-mu-type-offsets:  # in: (addr typeinfo), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    56/push-esi
    57/push-edi
#?     (dump-typeinfos "aaa\n")
    # var curr-offset/edi: int = 0
    bf/copy-to-edi 0/imm32
    # var table/ecx: (addr table string_key (handle typeinfo-entry)) = lookup(in->fields)
    8b/-> *(ebp+8) 1/r32/ecx
    (lookup *(ecx+4) *(ecx+8))  # Typeinfo-fields Typeinfo-fields => eax
    89/<- %ecx 0/r32/eax
    # var num-elems/edx: int = table->write / Typeinfo-fields-row-size
    8b/-> *ecx 2/r32/edx  # stream-write
    c1 5/subop/shift-right-logical  %edx 4/imm8
    # var i/ebx: int = 0
    bb/copy-to-ebx 0/imm32
    {
$populate-mu-type-offsets:loop:
      39/compare %ebx 2/r32/edx
      0f 8d/jump-if->= break/disp32
#?       (write-buffered Stderr "looking up index ")
#?       (write-int32-hex-buffered Stderr %ebx)
#?       (write-buffered Stderr " in ")
#?       (write-int32-hex-buffered Stderr *(ebp+8))
#?       (write-buffered Stderr Newline)
#?       (flush Stderr)
      # var v/esi: (addr typeinfo-entry)
      (locate-typeinfo-entry-with-index %ecx %ebx *(ebp+0xc) *(ebp+0x10))  # => eax
      89/<- %esi 0/r32/eax
      # if v is null, silently move on; we'll emit a nice error message while type-checking
      81 7/subop/compare %esi 0/imm32  # Typeinfo-entry-input-var
      74/jump-if-= $populate-mu-type-offsets:end/disp8
      # if (v->input-var == 0) silently ignore v; we'll emit a nice error message while type-checking
      81 7/subop/compare *esi 0/imm32  # Typeinfo-entry-input-var
      74/jump-if-= $populate-mu-type-offsets:end/disp8
      # v->output-var->offset = curr-offset
      # . eax: (addr var)
      (lookup *(esi+0xc) *(esi+0x10))  # Typeinfo-entry-output-var Typeinfo-entry-output-var => eax
      89/<- *(eax+0x14) 7/r32/edi  # Var-offset
      # curr-offset += size-of(v->input-var)
      (lookup *esi *(esi+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
      (size-of %eax)  # => eax
      01/add-to %edi 0/r32/eax
      # ++i
      43/increment-ebx
      e9/jump loop/disp32
    }
$populate-mu-type-offsets:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

locate-typeinfo-entry-with-index:  # table: (addr table (handle array byte) (handle typeinfo-entry)), idx: int, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: (addr typeinfo-entry)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    52/push-edx
    53/push-ebx
    56/push-esi
    57/push-edi
    # esi = table
    8b/-> *(ebp+8) 6/r32/esi
    # var curr/ecx: (addr row (handle array byte) (handle typeinfo-entry)) = table->data
    8d/copy-address *(esi+0xc) 1/r32/ecx
    # var max/edx: (addr byte) = &table->data[table->write]
    8b/-> *esi 2/r32/edx
    8d/copy-address *(ecx+edx) 2/r32/edx
    {
$locate-typeinfo-entry-with-index:loop:
      39/compare %ecx 2/r32/edx
      73/jump-if-addr>= break/disp8
      # var v/eax: (addr typeinfo-entry)
      (lookup *(ecx+8) *(ecx+0xc))  # => eax
      # if (v->index == idx) return v
      8b/-> *(eax+8) 3/r32/ebx  # Typeinfo-entry-index
#?       (write-buffered Stderr "comparing ")
#?       (write-int32-hex-buffered Stderr %ebx)
#?       (write-buffered Stderr " and ")
#?       (write-int32-hex-buffered Stderr *(ebp+0xc))
#?       (write-buffered Stderr Newline)
#?       (flush Stderr)
      39/compare *(ebp+0xc) 3/r32/ebx
      74/jump-if-= $locate-typeinfo-entry-with-index:end/disp8
      # curr += Typeinfo-entry-size
      81 0/subop/add %ecx 0x10/imm32  # Typeinfo-entry-size
      #
      eb/jump loop/disp8
    }
    # return 0
    b8/copy-to-eax 0/imm32
$locate-typeinfo-entry-with-index:end:
#?     (write-buffered Stderr "returning ")
#?     (write-int32-hex-buffered Stderr %eax)
#?     (write-buffered Stderr Newline)
#?     (flush Stderr)
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

dump-typeinfos:  # hdr: (addr array byte)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    #
    (write-buffered Stderr *(ebp+8))
    (flush Stderr)
    # var curr/eax: (addr typeinfo) = lookup(Program->types)
    (lookup *_Program-types *_Program-types->payload)  # => eax
    {
      # if (curr == null) break
      3d/compare-eax-and 0/imm32
      74/jump-if-= break/disp8
      (write-buffered Stderr "---\n")
      (flush Stderr)
      (dump-typeinfo %eax)
      # curr = lookup(curr->next)
      (lookup *(eax+0x10) *(eax+0x14))  # Typeinfo-next Typeinfo-next => eax
      eb/jump loop/disp8
    }
$dump-typeinfos:end:
    # . restore registers
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

dump-typeinfo:  # in: (addr typeinfo)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    56/push-esi
    57/push-edi
    # esi = in
    8b/-> *(ebp+8) 6/r32/esi
    # var table/ecx: (addr table (handle array byte) (handle typeinfo-entry)) = lookup(T->fields)
    (lookup *(esi+4) *(esi+8))  # Typeinfo-fields Typeinfo-fields => eax
    89/<- %ecx 0/r32/eax
    (write-buffered Stderr "id:")
    (write-int32-hex-buffered Stderr *esi)
    (write-buffered Stderr "\n")
    (write-buffered Stderr "fields @ ")
    (write-int32-hex-buffered Stderr %ecx)
    (write-buffered Stderr Newline)
    (flush Stderr)
    (write-buffered Stderr "  write: ")
    (write-int32-hex-buffered Stderr *ecx)
    (write-buffered Stderr Newline)
    (flush Stderr)
    (write-buffered Stderr "  read: ")
    (write-int32-hex-buffered Stderr *(ecx+4))
    (write-buffered Stderr Newline)
    (flush Stderr)
    (write-buffered Stderr "  size: ")
    (write-int32-hex-buffered Stderr *(ecx+8))
    (write-buffered Stderr Newline)
    (flush Stderr)
    # var table-size/edx: int = table->write
    8b/-> *ecx 2/r32/edx  # stream-write
    # var curr/ecx: (addr table_row) = table->data
    8d/copy-address *(ecx+0xc) 1/r32/ecx
    # var max/edx: (addr table_row) = table->data + table->write
    8d/copy-address *(ecx+edx) 2/r32/edx
    {
$dump-typeinfo:loop:
      # if (curr >= max) break
      39/compare %ecx 2/r32/edx
      0f 83/jump-if-addr>= break/disp32
      (write-buffered Stderr "  row:\n")
      (write-buffered Stderr "    key: ")
      (write-int32-hex-buffered Stderr *ecx)
      (write-buffered Stderr ",")
      (write-int32-hex-buffered Stderr *(ecx+4))
      (write-buffered Stderr " = '")
      (lookup *ecx *(ecx+4))
      (write-buffered Stderr %eax)
      (write-buffered Stderr "' @ ")
      (write-int32-hex-buffered Stderr %eax)
      (write-buffered Stderr Newline)
      (flush Stderr)
      (write-buffered Stderr "    value: ")
      (write-int32-hex-buffered Stderr *(ecx+8))
      (write-buffered Stderr ",")
      (write-int32-hex-buffered Stderr *(ecx+0xc))
      (write-buffered Stderr " = typeinfo-entry@")
      (lookup *(ecx+8) *(ecx+0xc))
      (write-int32-hex-buffered Stderr %eax)
      (write-buffered Stderr Newline)
      (flush Stderr)
      (write-buffered Stderr "        input var@")
      (dump-var 5 %eax)
      (lookup *(ecx+8) *(ecx+0xc))
      (write-buffered Stderr "        index: ")
      (write-int32-hex-buffered Stderr *(eax+8))
      (write-buffered Stderr Newline)
      (flush Stderr)
      (write-buffered Stderr "        output var@")
      8d/copy-address *(eax+0xc) 0/r32/eax  # Typeinfo-entry-output-var
      (dump-var 5 %eax)
      (flush Stderr)
      # curr += row-size
      81 0/subop/add %ecx 0x10/imm32  # Typeinfo-fields-row-size
      #
      e9/jump loop/disp32
    }
$dump-typeinfo:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

dump-var:  # indent: int, v: (addr handle var)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    53/push-ebx
    # eax = v
    8b/-> *(ebp+0xc) 0/r32/eax
    #
    (write-int32-hex-buffered Stderr *eax)
    (write-buffered Stderr ",")
    (write-int32-hex-buffered Stderr *(eax+4))
    (write-buffered Stderr "->")
    (lookup *eax *(eax+4))
    (write-int32-hex-buffered Stderr %eax)
    (write-buffered Stderr Newline)
    (flush Stderr)
    {
      3d/compare-eax-and 0/imm32
      0f 84/jump-if-= break/disp32
      (emit-indent Stderr *(ebp+8))
      (write-buffered Stderr "name: ")
      89/<- %ebx 0/r32/eax
      (write-int32-hex-buffered Stderr *ebx)  # Var-name
      (write-buffered Stderr ",")
      (write-int32-hex-buffered Stderr *(ebx+4))  # Var-name
      (write-buffered Stderr "->")
      (lookup *ebx *(ebx+4))  # Var-name
      (write-int32-hex-buffered Stderr %eax)
      {
        3d/compare-eax-and 0/imm32
        74/jump-if-= break/disp8
        (write-buffered Stderr Space)
        (write-buffered Stderr %eax)
      }
      (write-buffered Stderr Newline)
      (flush Stderr)
      (emit-indent Stderr *(ebp+8))
      (write-buffered Stderr "block depth: ")
      (write-int32-hex-buffered Stderr *(ebx+0x10))  # Var-block-depth
      (write-buffered Stderr Newline)
      (flush Stderr)
      (emit-indent Stderr *(ebp+8))
      (write-buffered Stderr "stack offset: ")
      (write-int32-hex-buffered Stderr *(ebx+0x14))  # Var-offset
      (write-buffered Stderr Newline)
      (flush Stderr)
      (emit-indent Stderr *(ebp+8))
      (write-buffered Stderr "reg: ")
      (write-int32-hex-buffered Stderr *(ebx+0x18))  # Var-register
      (write-buffered Stderr ",")
      (write-int32-hex-buffered Stderr *(ebx+0x1c))  # Var-register
      (write-buffered Stderr "->")
      (flush Stderr)
      (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register
      (write-int32-hex-buffered Stderr %eax)
      {
        3d/compare-eax-and 0/imm32
        74/jump-if-= break/disp8
        (write-buffered Stderr Space)
        (write-buffered Stderr %eax)
      }
      (write-buffered Stderr Newline)
      (flush Stderr)
    }
$dump-var:end:
    # . restore registers
    5b/pop-to-ebx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

#######################################################
# Type-checking
#######################################################

check-mu-types:  # err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    # var curr/eax: (addr function) = lookup(Program->functions)
    (lookup *_Program-functions *_Program-functions->payload)  # => eax
    {
$check-mu-types:loop:
      # if (curr == null) break
      3d/compare-eax-and 0/imm32
      0f 84/jump-if-= break/disp32
#?       # dump curr->name {{{
#?       50/push-eax
#?       (lookup *eax *(eax+4))  # Function-name Function-name => eax
#?       (write-buffered Stderr %eax)
#?       (write-buffered Stderr Newline)
#?       (flush Stderr)
#?       58/pop-to-eax
#?       # }}}
      (check-mu-function %eax *(ebp+8) *(ebp+0xc))
      # curr = lookup(curr->next)
      (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
      e9/jump loop/disp32
    }
$check-mu-types:end:
    # . restore registers
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

check-mu-function:  # fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    # eax = f
    8b/-> *(ebp+8) 0/r32/eax
    # TODO: anything to check in header?
    # var body/eax: (addr block) = lookup(f->body)
    (lookup *(eax+0x18) *(eax+0x1c))  # Function-body Function-body => eax
    (check-mu-block %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10))
$check-mu-function:end:
    # . restore registers
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

check-mu-block:  # block: (addr block), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    # eax = block
    8b/-> *(ebp+8) 0/r32/eax
    # var stmts/eax: (addr list stmt) = lookup(block->statements)
    (lookup *(eax+4) *(eax+8))  # Block-stmts Block-stmts => eax
    #
    {
$check-mu-block:check-empty:
      3d/compare-eax-and 0/imm32
      0f 84/jump-if-= break/disp32
      # emit block->statements
      (check-mu-stmt-list %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
    }
$check-mu-block:end:
    # . restore registers
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

check-mu-stmt-list:  # stmts: (addr list stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    56/push-esi
    # esi = stmts
    8b/-> *(ebp+8) 6/r32/esi
    {
$check-mu-stmt-list:loop:
      81 7/subop/compare %esi 0/imm32
      0f 84/jump-if-= break/disp32
      # var curr-stmt/eax: (addr stmt) = lookup(stmts->value)
      (lookup *esi *(esi+4))  # List-value List-value => eax
      {
$check-mu-stmt-list:check-for-block:
        81 7/subop/compare *eax 0/imm32/block  # Stmt-tag
        75/jump-if-!= break/disp8
$check-mu-stmt-list:block:
        (check-mu-block %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
        eb/jump $check-mu-stmt-list:continue/disp8
      }
      {
$check-mu-stmt-list:check-for-stmt1:
        81 7/subop/compare *eax 1/imm32/stmt1  # Stmt-tag
        0f 85/jump-if-!= break/disp32
$check-mu-stmt-list:stmt1:
        (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
        eb/jump $check-mu-stmt-list:continue/disp8
      }
      {
$check-mu-stmt-list:check-for-reg-var-def:
        81 7/subop/compare *eax 3/imm32/reg-var-def  # Stmt-tag
        0f 85/jump-if-!= break/disp32
$check-mu-stmt-list:reg-var-def:
        (check-mu-stmt %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
        eb/jump $check-mu-stmt-list:continue/disp8
      }
$check-mu-stmt-list:continue:
      # TODO: raise an error on unrecognized Stmt-tag
      (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
      89/<- %esi 0/r32/eax
      e9/jump loop/disp32
    }
$check-mu-stmt-list:end:
    # . restore registers
    5e/pop-to-esi
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

check-mu-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    # - if stmt's operation matches a primitive, check against it
    (has-primitive-name? *(ebp+8))  # => eax
    3d/compare-eax-and 0/imm32/false
    {
      74/jump-if-= break/disp8
      (check-mu-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
      e9/jump $check-mu-stmt:end/disp32
    }
    # - otherwise find a function to check against
    # var f/eax: (addr function) = lookup(*Program->functions)
    (lookup *_Program-functions *_Program-functions->payload)  # => eax
    (find-matching-function %eax *(ebp+8))  # => eax
    3d/compare-eax-and 0/imm32
    {
      74/jump-if-= break/disp8
      (check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
      eb/jump $check-mu-stmt:end/disp8
    }
    # var f/eax: (addr function) = lookup(*Program->signatures)
    (lookup *_Program-signatures *_Program-signatures->payload)  # => eax
    (find-matching-function %eax *(ebp+8))  # => eax
    3d/compare-eax-and 0/imm32
    {
      74/jump-if-= break/disp8
      (check-mu-call *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
      eb/jump $check-mu-stmt:end/disp8
    }
    # - otherwise abort
    e9/jump $check-mu-stmt:unknown-call/disp32
$check-mu-stmt:end:
    # . restore registers
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$check-mu-stmt:unknown-call:
    (write-buffered *(ebp+0x10) "unknown function '")
    8b/-> *(ebp+8) 0/r32/eax
    (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) "'\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

has-primitive-name?:  # stmt: (addr stmt) -> result/eax: boolean
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    56/push-esi
    # var name/esi: (addr array byte) = lookup(stmt->operation)
    8b/-> *(ebp+8) 6/r32/esi
    (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
    89/<- %esi 0/r32/eax
    # if (name == "get") return true
    (string-equal? %esi "get")  # => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $has-primitive-name?:end/disp32
    # if (name == "index") return true
    (string-equal? %esi "index")  # => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $has-primitive-name?:end/disp32
    # if (name == "length") return true
    (string-equal? %esi "length")  # => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $has-primitive-name?:end/disp32
    # if (name == "compute-offset") return true
    (string-equal? %esi "compute-offset")  # => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $has-primitive-name?:end/disp32
    # if (name == "copy-object") return true
    (string-equal? %esi "copy-object")  # => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $has-primitive-name?:end/disp32
    # if (name == "allocate") return true
    (string-equal? %esi "allocate")  # => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $has-primitive-name?:end/disp32
    # if (name == "populate") return true
    (string-equal? %esi "populate")  # => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $has-primitive-name?:end/disp32
    # if (name == "populate-stream") return true
    (string-equal? %esi "populate-stream")  # => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $has-primitive-name?:end/disp32
    # if (name == "read-from-stream") return true
    (string-equal? %esi "read-from-stream")  # => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $has-primitive-name?:end/disp32
    # if (name == "write-to-stream") return true
    (string-equal? %esi "write-to-stream")  # => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $has-primitive-name?:end/disp32
    # var curr/ecx: (addr primitive) = Primitives
    b9/copy-to-ecx Primitives/imm32
    {
$has-primitive-name?:loop:
      # if (curr == null) break
      81 7/subop/compare %ecx 0/imm32
      74/jump-if-= break/disp8
      # if (primitive->name == name) return true
      (lookup *ecx *(ecx+4))  # Primitive-name Primitive-name => eax
      (string-equal? %esi %eax)  # => eax
      3d/compare-eax-and 0/imm32/false
      75/jump-if-!= $has-primitive-name?:end/disp8
$has-primitive-name?:next-primitive:
      # curr = curr->next
      (lookup *(ecx+0x38) *(ecx+0x3c))  # Primitive-next Primitive-next => eax
      89/<- %ecx 0/r32/eax
      #
      e9/jump loop/disp32
    }
    # return null
    b8/copy-to-eax 0/imm32
$has-primitive-name?:end:
    # . restore registers
    5e/pop-to-esi
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

check-mu-primitive:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    # var op/ecx: (addr array byte) = lookup(stmt->operation)
    8b/-> *(ebp+8) 0/r32/eax
    (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
    89/<- %ecx 0/r32/eax
    # if (op == "copy") check-mu-copy-stmt
    {
      (string-equal? %ecx "copy")  # => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
      (check-mu-copy-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
      e9/jump $check-mu-primitive:end/disp32
    }
    # if (op == "copy-to") check-mu-copy-to-stmt
    {
      (string-equal? %ecx "copy-to")  # => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
      (check-mu-copy-to-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
      e9/jump $check-mu-primitive:end/disp32
    }
    # if (op == "compare") check-mu-compare-stmt
    {
      (string-equal? %ecx "compare")  # => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
      (check-mu-compare-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
      e9/jump $check-mu-primitive:end/disp32
    }
    # if (op == "address") check-mu-address-stmt
    {
      (string-equal? %ecx "address")  # => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
      (check-mu-address-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
      e9/jump $check-mu-primitive:end/disp32
    }
    # if (op == "get") check-mu-get-stmt
    {
      (string-equal? %ecx "get")  # => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
      (check-mu-get-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
      e9/jump $check-mu-primitive:end/disp32
    }
    # if (op == "index") check-mu-index-stmt
    {
      (string-equal? %ecx "index")  # => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
      (check-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
      e9/jump $check-mu-primitive:end/disp32
    }
    # if (op == "length") check-mu-length-stmt
    {
      (string-equal? %ecx "length")  # => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
      (check-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
      e9/jump $check-mu-primitive:end/disp32
    }
    # if (op == "compute-offset") check-mu-compute-offset-stmt
    {
      (string-equal? %ecx "compute-offset")  # => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
      (check-mu-compute-offset-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
      e9/jump $check-mu-primitive:end/disp32
    }
    # if (op == "copy-object") check-mu-copy-object-stmt
    {
      (string-equal? %ecx "copy-object")  # => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
      (check-mu-copy-object-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
      e9/jump $check-mu-primitive:end/disp32
    }
    # if (op == "allocate") check-mu-allocate-stmt
    {
      (string-equal? %ecx "allocate")  # => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
      (check-mu-allocate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
      e9/jump $check-mu-primitive:end/disp32
    }
    # if (op == "populate") check-mu-populate-stmt
    {
      (string-equal? %ecx "populate")  # => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
      (check-mu-populate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
      e9/jump $check-mu-primitive:end/disp32
    }
    # if (op == "populate-stream") check-mu-populate-stream-stmt
    {
      (string-equal? %ecx "populate-stream")  # => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
      (check-mu-populate-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
      e9/jump $check-mu-primitive:end/disp32
    }
    # if (op == "read-from-stream") check-mu-read-from-stream-stmt
    {
      (string-equal? %ecx "read-from-stream")  # => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
      (check-mu-read-from-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
      e9/jump $check-mu-primitive:end/disp32
    }
    # if (op == "write-to-stream") check-mu-write-to-stream-stmt
    {
      (string-equal? %ecx "write-to-stream")  # => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
      (check-mu-write-to-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
      e9/jump $check-mu-primitive:end/disp32
    }
    # otherwise check-numberlike-stmt
    (check-mu-numberlike-primitive *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
$check-mu-primitive:end:
    # . restore registers
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# by default, Mu primitives should only operate on 'number-like' types
check-mu-numberlike-primitive:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    56/push-esi
    # esi = stmt
    8b/-> *(ebp+8) 6/r32/esi
    # var gas/ecx: int = 2
    b9/copy-to-ecx 2/imm32
    # - check at most 1 output
    # var output/eax: (addr stmt-var) = stmt->outputs
    (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
    {
      3d/compare-eax-and 0/imm32
      74/jump-if-= break/disp8
$check-mu-numberlike-primitive:output:
      (check-mu-numberlike-output %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
      (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
      3d/compare-eax-and 0/imm32
      0f 85/jump-if-!= $check-mu-numberlike-primitive:error-too-many-outputs/disp32
      # check output is in a register
      # --gas
      49/decrement-ecx
    }
    # - check first inout
    (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    {
      3d/compare-eax-and 0/imm32
      0f 84/jump-if-= $check-mu-numberlike-primitive:end/disp32
$check-mu-numberlike-primitive:first-inout:
      (check-mu-numberlike-arg %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
      # --gas
      49/decrement-ecx
    }
    # - check second inout
    (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
    {
      3d/compare-eax-and 0/imm32
      74/jump-if-= $check-mu-numberlike-primitive:end/disp8
$check-mu-numberlike-primitive:second-inout:
      # is a second inout allowed?
      81 7/subop/compare %ecx 0/imm32
      0f 84/jump-if-= $check-mu-numberlike-primitive:error-too-many-inouts/disp32
$check-mu-numberlike-primitive:second-inout-permitted:
      (check-mu-numberlike-arg %eax *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
    }
$check-mu-numberlike-primitive:third-inout:
    # if there's a third arg, raise an error
    81 7/subop/compare *(eax+8) 0/imm32  # Stmt-var-next
    0f 85/jump-if-!= $check-mu-numberlike-primitive:error-too-many-inouts/disp32
$check-mu-numberlike-primitive:end:
    # . restore registers
    5e/pop-to-esi
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$check-mu-numberlike-primitive:error-too-many-inouts:
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt ")
    (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": too many inouts; most primitives support at most two arguments, across inouts and outputs\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$check-mu-numberlike-primitive:error-too-many-outputs:
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt ")
    (lookup *(esi+4) *(esi+8))  # Stmt1-operation Stmt1-operation => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": too many outputs; most primitives support at most one output\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

check-mu-numberlike-arg:  # v: (addr stmt-var), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    56/push-esi
    # var t/esi: (addr type-tree) = lookup(v->value->type)
    8b/-> *(ebp+8) 0/r32/eax
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
    89/<- %esi 0/r32/eax
$check-mu-numberlike-arg:check-literal:
    # if t is an int, return
    (is-simple-mu-type? %esi 0)  # literal => eax
    3d/compare-eax-and 0/imm32/false
    75/jump-if-!= $check-mu-numberlike-arg:end/disp8
$check-mu-numberlike-arg:check-addr:
    # if t is an addr and v is dereferenced, return
    {
      (is-mu-addr-type? %esi)  # => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
      8b/-> *(ebp+8) 0/r32/eax
      8b/-> *(eax+0x10) 0/r32/eax
      3d/compare-eax-and 0/imm32/false
      75/jump-if-!= $check-mu-numberlike-arg:end/disp8
    }
$check-mu-numberlike-arg:output-checks:
    (check-mu-numberlike-output *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18))
$check-mu-numberlike-arg:end:
    # . restore registers
    5e/pop-to-esi
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

check-mu-numberlike-output:  # v: (addr stmt-var), stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    56/push-esi
    # var t/esi: (addr type-tree) = lookup(v->value->type)
    8b/-> *(ebp+8) 0/r32/eax
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
    89/<- %esi 0/r32/eax
$check-mu-numberlike-output:check-int:
    # if t is an int, return
    (is-simple-mu-type? %esi 1)  # int => eax
    3d/compare-eax-and 0/imm32/false
    75/jump-if-!= $check-mu-numberlike-output:end/disp8
$check-mu-numberlike-output:check-boolean:
    # if t is a boolean, return
    (is-simple-mu-type? %esi 5)  # boolean => eax
    3d/compare-eax-and 0/imm32/false
    75/jump-if-!= $check-mu-numberlike-output:end/disp8
$check-mu-numberlike-output:check-byte:
    # if t is a byte, return
    (is-simple-mu-type? %esi 8)  # byte => eax
    3d/compare-eax-and 0/imm32/false
    75/jump-if-!= $check-mu-numberlike-output:end/disp8
    e9/jump $check-mu-numberlike-output:fail/disp32
$check-mu-numberlike-output:end:
    # . restore registers
    5e/pop-to-esi
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$check-mu-numberlike-output:fail:
    # otherwise raise an error
    (write-buffered *(ebp+0x14) "fn ")
    8b/-> *(ebp+0x10) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x14) %eax)
    (write-buffered *(ebp+0x14) ": stmt ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
    (write-buffered *(ebp+0x14) %eax)
    (write-buffered *(ebp+0x14) ": only non-addr scalar args permitted\n")
    (flush *(ebp+0x14))
    (stop *(ebp+0x18) 1)
    # never gets here

check-mu-copy-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
$check-mu-copy-stmt:end:
    # . restore registers
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

check-mu-copy-to-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
$check-mu-copy-to-stmt:end:
    # . restore registers
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

check-mu-compare-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
$check-mu-compare-stmt:end:
    # . restore registers
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

check-mu-address-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
$check-mu-address-stmt:end:
    # . restore registers
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

check-mu-get-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    56/push-esi
    57/push-edi
    # esi = stmt
    8b/-> *(ebp+8) 6/r32/esi
    # - check for 0 inouts
    # var base/ecx: (addr var) = stmt->inouts->value
    (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    3d/compare-eax-and 0/imm32/false
    0f 84/jump-if-= $check-mu-get-stmt:error-too-few-inouts/disp32
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    89/<- %ecx 0/r32/eax
$check-mu-get-stmt:check-base:
    # - check base type
    # if it's an 'addr', check that it's in a register
    # var base-type/ebx: (addr type-tree) = lookup(base->type)
    (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
    89/<- %ebx 0/r32/eax
    {
      81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
      0f 85/jump-if-!= break/disp32
$check-mu-get-stmt:base-is-compound:
      # if (type->left != addr) break
      (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
      (is-simple-mu-type? %eax 2)  # addr => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
$check-mu-get-stmt:base-is-addr:
      # now check for register
      81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
      0f 84/jump-if-= $check-mu-get-stmt:error-base-type-addr-but-not-register/disp32
$check-mu-get-stmt:base-is-addr-in-register:
      # type->left is now an addr; skip it
      (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
      81 7/subop/compare *(eax+0xc) 0/imm32  # Type-tree-right
      0f 85/jump-if-!= $check-mu-get-stmt:error-bad-base/disp32
$check-mu-get-stmt:base-is-addr-to-atom-in-register:
      (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
      89/<- %ebx 0/r32/eax
    }
$check-mu-get-stmt:check-base-typeinfo:
    # ensure type is a container
    # var base-type-id/ebx: type-id = base-type->value
    8b/-> *(ebx+4) 3/r32/ebx  # Type-tree-value
    (is-container? %ebx)  # => eax
    3d/compare-eax-and 0/imm32/false
    0f 84/jump-if-= $check-mu-get-stmt:error-bad-base/disp32
    # var base-typeinfo/edx: (addr typeinfo) = find-typeinfo(base-type-id)
    # . var container/ecx: (handle typeinfo)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %ecx 4/r32/esp
    # .
    (find-typeinfo %ebx %ecx)
    (lookup *ecx *(ecx+4))  # => eax
    # . reclaim container
    81 0/subop/add %esp 8/imm32
    # .
    89/<- %edx 0/r32/eax
    # var offset/ecx: (addr stmt-var) = stmt->inouts->next
    (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
    89/<- %ecx 0/r32/eax
    # - check for 1 inout
    3d/compare-eax-and 0/imm32/false
    0f 84/jump-if-= $check-mu-get-stmt:error-too-few-inouts/disp32
    # var offset/ecx: (addr var) = lookup(offset->value)
    (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
    89/<- %ecx 0/r32/eax
    # - check for valid field
    81 7/subop/compare *(ecx+0x14) -1/imm32/uninitialized  # Var-offset
    0f 84/jump-if-= $check-mu-get-stmt:error-bad-field/disp32
    # - check for too many inouts
    (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
    (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $check-mu-get-stmt:error-too-many-inouts/disp32
    # var output/edi: (addr var) = stmt->outputs->value
    (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
    # - check for 0 outputs
    3d/compare-eax-and 0/imm32/false
    0f 84/jump-if-= $check-mu-get-stmt:error-too-few-outputs/disp32
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    89/<- %edi 0/r32/eax
$check-mu-get-stmt:check-output-type:
    # - check output type
    # must be in register
    (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
    3d/compare-eax-and 0/imm32
    0f 84/jump-if-= $check-mu-get-stmt:error-output-not-in-register/disp32
    # must have a non-atomic type
    (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
    81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
    0f 85/jump-if-!= $check-mu-get-stmt:error-output-type-not-address/disp32
    # type must start with (addr ...)
    (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
    (is-simple-mu-type? %eax 2)  # => eax
    3d/compare-eax-and 0/imm32/false
    0f 84/jump-if-= $check-mu-get-stmt:error-output-type-not-address/disp32
$check-mu-get-stmt:check-output-type-match:
    # payload of addr type must match 'type' definition
    (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
    (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
    # if (payload->right == null) payload = payload->left
    81 7/subop/compare *(eax+0xc) 0/imm32/null  # Type-tree-right
    {
      75/jump-if-!= break/disp8
      (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
    }
    89/<- %edi 0/r32/eax
    # . var output-name/ecx: (addr array byte)
    (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
    89/<- %ecx 0/r32/eax
    # . var base-typeinfo-entry/eax: (addr handle typeinfo-entry)
    (lookup *(edx+4) *(edx+8))  # Typeinfo-fields Typeinfo-fields => eax
    (get %eax %ecx 0x10)  # => eax
    # .
    (lookup *eax *(eax+4))  # => eax
    (lookup *eax *(eax+4))  # Typeinfo-entry-input-var Typeinfo-entry-input-var => eax
    (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
    # .
    (type-equal? %edi %eax)  # => eax
    3d/compare-eax-and 0/imm32/false
    0f 84/jump-if-= $check-mu-get-stmt:error-bad-output-type/disp32
    # - check for too many outputs
    (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
    (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $check-mu-get-stmt:error-too-many-outputs/disp32
$check-mu-get-stmt:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$check-mu-get-stmt:error-too-few-inouts:
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt get: too few inouts (2 required)\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$check-mu-get-stmt:error-too-many-inouts:
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt get: too many inouts (2 required)\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$check-mu-get-stmt:error-too-few-outputs:
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt get: must have an output\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$check-mu-get-stmt:error-too-many-outputs:
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt get: too many outputs (1 required)\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$check-mu-get-stmt:error-bad-base:
    # error("fn " fn ": stmt get: var '" base->name "' must have a 'type' definition\n")
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt get: var '")
    (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    (lookup *eax *(eax+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) "' must have a 'type' definition\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$check-mu-get-stmt:error-base-type-addr-but-not-register:
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt get: var '")
    (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    (lookup *eax *(eax+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) "' is an 'addr' type, and so must live in a register\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$check-mu-get-stmt:error-bad-field:
    # error("fn " fn ": stmt get: type " type " has no member called '" curr->name "'\n")
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt get: type '")
    # . write(Type-id->data[tmp])
    bf/copy-to-edi Type-id/imm32
    (write-buffered *(ebp+0x10) *(edi+ebx<<2+0xc))
    # .
    (write-buffered *(ebp+0x10) "' has no member called '")
    (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) "'\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$check-mu-get-stmt:error-output-not-in-register:
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt get: output '")
    (lookup *edi *(edi+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) "' is not in a register\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$check-mu-get-stmt:error-output-type-not-address:
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt get: output must be an address\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$check-mu-get-stmt:error-bad-output-type:
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt get: wrong output type for member '")
    (write-buffered *(ebp+0x10) %ecx)
    (write-buffered *(ebp+0x10) "' of type '")
    bf/copy-to-edi Type-id/imm32
    (write-buffered *(ebp+0x10) *(edi+ebx<<2+0xc))
    (write-buffered *(ebp+0x10) "'\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

check-mu-index-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    56/push-esi
    57/push-edi
    # esi = stmt
    8b/-> *(ebp+8) 6/r32/esi
    # - check for 0 inouts
    # var base/ecx: (addr var) = stmt->inouts->value
    (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
$check-mu-index-stmt:check-no-inouts:
    3d/compare-eax-and 0/imm32
    0f 84/jump-if-= $check-mu-index-stmt:error-too-few-inouts/disp32
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    89/<- %ecx 0/r32/eax
    # - check base type is either (addr array ...) in register or (array ...) on stack
    # var base-type/ebx: (addr type-tree) = lookup(base->type)
    (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
    89/<- %ebx 0/r32/eax
    # if base-type is an atom, abort with a precise error
    81 7/subop/compare *ebx 0/imm32/false  # Type-tree-is-atom
    {
      74/jump-if-= break/disp8
      (is-simple-mu-type? %ebx 3)  # array => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= $check-mu-index-stmt:error-base-array-atom-type/disp32
      0f 84/jump-if-= $check-mu-index-stmt:error-base-non-array-type/disp32
    }
$check-mu-index-stmt:base-is-compound:
    # if type->left not addr or array, abort
    {
      (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
      (is-simple-mu-type? %eax 2)  # addr => eax
      3d/compare-eax-and 0/imm32/false
      75/jump-if-!= break/disp8
      (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
      (is-simple-mu-type? %eax 3)  # array => eax
      3d/compare-eax-and 0/imm32/false
      75/jump-if-!= break/disp8
      e9/jump $check-mu-index-stmt:error-base-non-array-type/disp32
    }
    # if (type->left == addr) ensure type->right->left == array and type->register exists
    {
      (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
      (is-simple-mu-type? %eax 2)  # addr => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
$check-mu-index-stmt:base-is-addr:
      (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
      (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
      (is-simple-mu-type? %eax 3)  # array => eax
      3d/compare-eax-and 0/imm32/false
      0f 84/jump-if-= $check-mu-index-stmt:error-base-non-array-type/disp32
$check-mu-index-stmt:check-base-addr-is-register:
      81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
      0f 84/jump-if-= $check-mu-index-stmt:error-base-address-array-type-on-stack/disp32
    }
    # if (type->left == array) ensure type->register doesn't exist
    {
      (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
      (is-simple-mu-type? %eax 3)  # array => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
$check-mu-index-stmt:base-is-array:
      81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
      0f 85/jump-if-!= $check-mu-index-stmt:error-base-array-type-in-register/disp32
    }
    # if (base-type->left == addr) base-type = base-type->right
    {
      (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
      (is-simple-mu-type? %eax 2)  # addr => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
      (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
      89/<- %ebx 0/r32/eax
    }
    # - check for 1 inout
    # var index/ecx: (addr stmt-var) = stmt->inouts->next->value
    (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
$check-mu-index-stmt:check-single-inout:
    3d/compare-eax-and 0/imm32
    0f 84/jump-if-= $check-mu-index-stmt:error-too-few-inouts/disp32
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    89/<- %ecx 0/r32/eax
    # - check index is either a literal or register
    # var index-type/edx: (addr type-tree)
    (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
    89/<- %edx 0/r32/eax
    # if index type is an atom, it must be a literal or int
    81 7/subop/compare *edx 0/imm32/false  # Type-tree-is-atom
    {
      74/jump-if-= break/disp8
$check-mu-index-stmt:index-type-is-atom:
      (is-simple-mu-type? %edx 0)  # literal => eax
      3d/compare-eax-and 0/imm32/false
      75/jump-if-!= $check-mu-index-stmt:index-type-done/disp8
      (is-simple-mu-type? %edx 1)  # int => eax
      3d/compare-eax-and 0/imm32/false
      75/jump-if-!= $check-mu-index-stmt:index-type-done/disp8
      (is-simple-mu-type? %edx 7)  # offset => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= $check-mu-index-stmt:error-index-offset-atom-type/disp32
      e9/jump $check-mu-index-stmt:error-invalid-index-type/disp32
    }
    # if index type is a non-atom: it must be an offset
    {
      75/jump-if-!= break/disp8
$check-mu-index-stmt:index-type-is-non-atom:
      (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
      (is-simple-mu-type? %eax 7)  # offset => eax
      3d/compare-eax-and 0/imm32/false
      0f 84/jump-if-= $check-mu-index-stmt:error-invalid-index-type/disp32
    }
$check-mu-index-stmt:index-type-done:
    # check index is either a literal or in a register
    {
      (is-simple-mu-type? %edx 0)  # literal => eax
      3d/compare-eax-and 0/imm32/false
      75/jump-if-!= break/disp8
$check-mu-index-stmt:check-index-in-register:
      81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
      0f 84/jump-if-= $check-mu-index-stmt:error-index-on-stack/disp32
    }
    # - if index is an 'int', check that element type of base has size 1, 2, 4 or 8 bytes.
    {
      (is-simple-mu-type? %edx 1)  # int => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
$check-mu-index-stmt:check-index-can-be-int:
      (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
      (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
      (array-element-size %eax)  # => eax
      3d/compare-eax-and 1/imm32
      74/jump-if-= break/disp8
      3d/compare-eax-and 2/imm32
      74/jump-if-= break/disp8
      3d/compare-eax-and 4/imm32
      74/jump-if-= break/disp8
      3d/compare-eax-and 8/imm32
      74/jump-if-= break/disp8
      e9/jump $check-mu-index-stmt:error-index-needs-offset/disp32
    }
    # - check for too many inouts
    (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
    (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $check-mu-index-stmt:error-too-many-inouts/disp32
    # - check for 0 outputs
    # var output/edi: (addr var) = stmt->outputs->value
    (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
    3d/compare-eax-and 0/imm32/false
    0f 84/jump-if-= $check-mu-index-stmt:error-too-few-outputs/disp32
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    89/<- %edi 0/r32/eax
    # - check output type
    # must have a non-atomic type
    (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
    89/<- %edx 0/r32/eax
    81 7/subop/compare *edx 0/imm32/false  # Type-tree-is-atom
    0f 85/jump-if-!= $check-mu-index-stmt:error-output-type-not-address/disp32
    # type must start with (addr ...)
    (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
    (is-simple-mu-type? %eax 2)  # addr => eax
    3d/compare-eax-and 0/imm32/false
    0f 84/jump-if-= $check-mu-index-stmt:error-output-type-not-address/disp32
    # if tail(base-type) != tail(output-type) abort
    (type-tail %ebx)  # => eax
    89/<- %ebx 0/r32/eax
    (type-tail %edx)  # => eax
    (type-equal? %ebx %eax)  # => eax
    3d/compare-eax-and 0/imm32/false
    0f 84/jump-if-= $check-mu-index-stmt:error-bad-output-type/disp32
    # - check for too many outputs
    (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
    (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
    3d/compare-eax-and 0/imm32/false
    0f 85/jump-if-!= $check-mu-index-stmt:error-too-many-outputs/disp32
$check-mu-index-stmt:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$check-mu-index-stmt:error-base-non-array-type:
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt index: var '")
    (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) "' is not an array\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$check-mu-index-stmt:error-base-array-atom-type:
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt index: array '")
    (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) "' must specify the type of its elements\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$check-mu-index-stmt:error-base-address-array-type-on-stack:
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt index: var '")
    (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) "' is an addr to an array, and so must live in a register\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$check-mu-index-stmt:error-base-array-type-in-register:
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt index: var '")
    (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) "' is an array, and so must live on the stack\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$check-mu-index-stmt:error-too-few-inouts:
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt index: too few inouts (2 required)\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$check-mu-index-stmt:error-invalid-index-type:
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt index: second argument '")
    (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) "' must be an int or offset\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$check-mu-index-stmt:error-index-offset-atom-type:
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt index: offset '")
    (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) "' must specify the type of array elements\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$check-mu-index-stmt:error-index-on-stack:
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt index: second argument '")
    (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) "' must be in a register\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$check-mu-index-stmt:error-index-needs-offset:
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt index: cannot take an int for array '")
    (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    (lookup *eax *(eax+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) "'; create an offset instead. See mu.md for details.\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$check-mu-index-stmt:error-too-many-inouts:
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt index: too many inouts (2 required)\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$check-mu-index-stmt:error-too-few-outputs:
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt index: must have an output\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$check-mu-index-stmt:error-too-many-outputs:
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt index: too many outputs (1 required)\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$check-mu-index-stmt:error-output-not-in-register:
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt index: output '")
    (lookup *edi *(edi+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) "' is not in a register\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$check-mu-index-stmt:error-output-type-not-address:
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt index: output '")
    (lookup *edi *(edi+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) "' must be an address\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$check-mu-index-stmt:error-bad-output-type:
    (write-buffered *(ebp+0x10) "fn ")
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) ": stmt index: output '")
    (lookup *edi *(edi+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) "' does not have the right type\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

check-mu-length-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
$check-mu-length-stmt:end:
    # . restore registers
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

check-mu-compute-offset-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
$check-mu-compute-offset-stmt:end:
    # . restore registers
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

check-mu-copy-object-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
$check-mu-copy-object-stmt:end:
    # . restore registers
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

check-mu-allocate-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
$check-mu-allocate-stmt:end:
    # . restore registers
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

check-mu-populate-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
$check-mu-populate-stmt:end:
    # . restore registers
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

check-mu-populate-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
$check-mu-populate-stream-stmt:end:
    # . restore registers
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

check-mu-read-from-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
$check-mu-read-from-stream-stmt:end:
    # . restore registers
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

check-mu-write-to-stream-stmt:  # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
$check-mu-write-to-stream-stmt:end:
    # . restore registers
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

check-mu-call:  # stmt: (addr stmt), callee: (addr function), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # var type-parameters: (addr table (handle array byte) (addr type-tree) 8)
    68/push 0/imm32
    # var type-parameters-storage: (table (handle array byte) (addr type-tree) 8)
    81 5/subop/subtract %esp 0x60/imm32
    68/push 0x60/imm32/size
    68/push 0/imm32/read
    68/push 0/imm32/write
    # save a pointer to type-parameters-storage at type-parameters
    89/<- *(ebp-4) 4/r32/esp
    (clear-stream *(ebp-4))
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    56/push-esi
    57/push-edi
    # esi = stmt
    8b/-> *(ebp+8) 6/r32/esi
    # edi = callee
    8b/-> *(ebp+0xc) 7/r32/edi
    # var inouts/ecx: (addr stmt-var) = lookup(stmt->inouts)
    (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    89/<- %ecx 0/r32/eax
    # var expected/edx: (addr list var) = lookup(f->inouts)
    (lookup *(edi+8) *(edi+0xc))  # Function-inouts Function-inouts => eax
    89/<- %edx 0/r32/eax
    {
$check-mu-call:check-for-inouts:
      # if (inouts == 0) break
      81 7/subop/compare %ecx 0/imm32
      0f 84/jump-if-= break/disp32
      # if (expected == 0) error
      81 7/subop/compare %edx 0/imm32
      0f 84/jump-if-= break/disp32
$check-mu-call:check-inout-type:
      # var v/eax: (addr v) = lookup(inouts->value)
      (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
      # var t/ebx: (addr type-tree) = lookup(v->type)
      (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
      89/<- %ebx 0/r32/eax
      # if (inouts->is-deref?) t = t->right  # TODO: check that t->left is an addr
      81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
      {
        74/jump-if-= break/disp8
        (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
        89/<- %ebx 0/r32/eax
        # if t->right is null, t = t->left
        81 7/subop/compare *(ebx+0xc) 0/imm32  # Type-tree-right
        75/jump-if-!= break/disp8
        (lookup *(ebx+4) *(ebx+8))  # Type-tree-left Type-tree-left => eax
        89/<- %ebx 0/r32/eax
      }
      # var v2/eax: (addr v) = lookup(expected->value)
      (lookup *edx *(edx+4))  # List-value List-value => eax
      # var t2/eax: (addr type-tree) = lookup(v2->type)
      (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
      # if (t != t2) error
      (type-match? %eax %ebx *(ebp-4))  # => eax
      3d/compare-eax-and 0/imm32/false
      {
        0f 85/jump-if-!= break/disp32
        (write-buffered *(ebp+0x14) "fn ")
        8b/-> *(ebp+0x10) 0/r32/eax
        (lookup *eax *(eax+4))  # Function-name Function-name => eax
        (write-buffered *(ebp+0x14) %eax)
        (write-buffered *(ebp+0x14) ": call ")
        (lookup *edi *(edi+4))  # Function-name Function-name => eax
        (write-buffered *(ebp+0x14) %eax)
        (write-buffered *(ebp+0x14) ": type for inout '")
        (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
        (lookup *eax *(eax+4))  # Var-name Var-name => eax
        (write-buffered *(ebp+0x14) %eax)
        (write-buffered *(ebp+0x14) "' is not right\n")
        (flush *(ebp+0x14))
        (stop *(ebp+0x18) 1)
      }
$check-mu-call:continue-to-next-inout:
      # inouts = lookup(inouts->next)
      (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
      89/<- %ecx 0/r32/eax
      # expected = lookup(expected->next)
      (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
      89/<- %edx 0/r32/eax
      #
      e9/jump loop/disp32
    }
$check-mu-call:check-inout-count:
    # if (inouts == expected) proceed
    39/compare %ecx 2/r32/edx
    {
      0f 84/jump-if-= break/disp32
      # exactly one of the two is null
      # if (inouts == 0) error("too many inouts")
      {
        81 7/subop/compare %ecx 0/imm32
        0f 84/jump-if-= break/disp32
        (write-buffered *(ebp+0x14) "fn ")
        8b/-> *(ebp+0x10) 0/r32/eax
        (lookup *eax *(eax+4))  # Function-name Function-name => eax
        (write-buffered *(ebp+0x14) %eax)
        (write-buffered *(ebp+0x14) ": call ")
        (lookup *edi *(edi+4))  # Function-name Function-name => eax
        (write-buffered *(ebp+0x14) %eax)
        (write-buffered *(ebp+0x14) ": too many inouts\n")
        (flush *(ebp+0x14))
        (stop *(ebp+0x18) 1)
      }
      # if (expected == 0) error("too few inouts")
      {
        81 7/subop/compare %edx 0/imm32
        0f 84/jump-if-= break/disp32
        (write-buffered *(ebp+0x14) "fn ")
        8b/-> *(ebp+0x10) 0/r32/eax
        (lookup *eax *(eax+4))  # Function-name Function-name => eax
        (write-buffered *(ebp+0x14) %eax)
        (write-buffered *(ebp+0x14) ": call ")
        (lookup *edi *(edi+4))  # Function-name Function-name => eax
        (write-buffered *(ebp+0x14) %eax)
        (write-buffered *(ebp+0x14) ": too few inouts\n")
        (flush *(ebp+0x14))
        (stop *(ebp+0x18) 1)
      }
    }
$check-mu-call:check-outputs:
    # var outputs/ecx: (addr stmt-var) = lookup(stmt->outputs)
    (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
    89/<- %ecx 0/r32/eax
    # var expected/edx: (addr list var) = lookup(f->outputs)
    (lookup *(edi+0x10) *(edi+0x14))  # Function-outputs Function-outputs => eax
    89/<- %edx 0/r32/eax
    {
$check-mu-call:check-for-outputs:
      # if (outputs == 0) break
      81 7/subop/compare %ecx 0/imm32
      0f 84/jump-if-= break/disp32
      # if (expected == 0) error
      81 7/subop/compare %edx 0/imm32
      0f 84/jump-if-= break/disp32
$check-mu-call:check-output-type:
      # var v/eax: (addr v) = lookup(outputs->value)
      (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
      # var t/ebx: (addr type-tree) = lookup(v->type)
      (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
      89/<- %ebx 0/r32/eax
      # if (outputs->is-deref?) t = t->right  # TODO: check that t->left is an addr
      81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
      {
        74/jump-if-= break/disp8
        (lookup *(ebx+0xc) *(ebx+0x10))  # Type-tree-right Type-tree-right => eax
        89/<- %ebx 0/r32/eax
      }
      # var v2/eax: (addr v) = lookup(expected->value)
      (lookup *edx *(edx+4))  # List-value List-value => eax
      # var t2/eax: (addr type-tree) = lookup(v2->type)
      (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
      # if (t != t2) error
      (type-match? %eax %ebx *(ebp-4))  # => eax
      3d/compare-eax-and 0/imm32/false
      {
        0f 85/jump-if-!= break/disp32
        (write-buffered *(ebp+0x14) "fn ")
        8b/-> *(ebp+0x10) 0/r32/eax
        (lookup *eax *(eax+4))  # Function-name Function-name => eax
        (write-buffered *(ebp+0x14) %eax)
        (write-buffered *(ebp+0x14) ": call ")
        (lookup *edi *(edi+4))  # Function-name Function-name => eax
        (write-buffered *(ebp+0x14) %eax)
        (write-buffered *(ebp+0x14) ": type for output '")
        (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
        (lookup *eax *(eax+4))  # Var-name Var-name => eax
        (write-buffered *(ebp+0x14) %eax)
        (write-buffered *(ebp+0x14) "' is not right\n")
        (flush *(ebp+0x14))
        (stop *(ebp+0x18) 1)
      }
$check-mu-call:check-output-register:
      # var v/eax: (addr v) = lookup(outputs->value)
      (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
      # var r/ebx: (addr array byte) = lookup(v->register)
      (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
      89/<- %ebx 0/r32/eax
      # var v2/eax: (addr v) = lookup(expected->value)
      (lookup *edx *(edx+4))  # Stmt-var-value Stmt-var-value => eax
      # var r2/eax: (addr array byte) = lookup(v2->register)
      (lookup *(eax+18) *(eax+0x1c))  # Var-register Var-register => eax
      # if (r != r2) error
      (string-equal? %eax %ebx)  # => eax
      3d/compare-eax-and 0/imm32/false
      {
        0f 85/jump-if-!= break/disp32
        (write-buffered *(ebp+0x14) "fn ")
        8b/-> *(ebp+0x10) 0/r32/eax
        (lookup *eax *(eax+4))  # Function-name Function-name => eax
        (write-buffered *(ebp+0x14) %eax)
        (write-buffered *(ebp+0x14) ": call ")
        (lookup *edi *(edi+4))  # Function-name Function-name => eax
        (write-buffered *(ebp+0x14) %eax)
        (write-buffered *(ebp+0x14) ": register for output '")
        (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
        (lookup *eax *(eax+4))  # Var-name Var-name => eax
        (write-buffered *(ebp+0x14) %eax)
        (write-buffered *(ebp+0x14) "' is not right\n")
        (flush *(ebp+0x14))
        (stop *(ebp+0x18) 1)
      }
$check-mu-call:continue-to-next-output:
      # outputs = lookup(outputs->next)
      (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
      89/<- %ecx 0/r32/eax
      # expected = lookup(expected->next)
      (lookup *(edx+8) *(edx+0xc))  # List-next List-next => eax
      89/<- %edx 0/r32/eax
      #
      e9/jump loop/disp32
    }
$check-mu-call:check-output-count:
    # if (outputs == expected) proceed
    39/compare %ecx 2/r32/edx
    {
      0f 84/jump-if-= break/disp32
      # exactly one of the two is null
      # if (outputs == 0) error("too many outputs")
      {
        81 7/subop/compare %ecx 0/imm32
        0f 84/jump-if-= break/disp32
        (write-buffered *(ebp+0x14) "fn ")
        8b/-> *(ebp+0x10) 0/r32/eax
        (lookup *eax *(eax+4))  # Function-name Function-name => eax
        (write-buffered *(ebp+0x14) %eax)
        (write-buffered *(ebp+0x14) ": call ")
        (lookup *edi *(edi+4))  # Function-name Function-name => eax
        (write-buffered *(ebp+0x14) %eax)
        (write-buffered *(ebp+0x14) ": too many outputs\n")
        (flush *(ebp+0x14))
        (stop *(ebp+0x18) 1)
      }
      # if (expected == 0) error("too few outputs")
      {
        81 7/subop/compare %edx 0/imm32
        0f 84/jump-if-= break/disp32
        (write-buffered *(ebp+0x14) "fn ")
        8b/-> *(ebp+0x10) 0/r32/eax
        (lookup *eax *(eax+4))  # Function-name Function-name => eax
        (write-buffered *(ebp+0x14) %eax)
        (write-buffered *(ebp+0x14) ": call ")
        (lookup *edi *(edi+4))  # Function-name Function-name => eax
        (write-buffered *(ebp+0x14) %eax)
        (write-buffered *(ebp+0x14) ": too few outputs\n")
        (flush *(ebp+0x14))
        (stop *(ebp+0x18) 1)
      }
    }
$check-mu-call:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . reclaim locals exclusively on the stack
    81 0/subop/add %esp 0x70/imm32
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# like type-equal? but takes literals into account
type-match?:  # def: (addr type-tree), call: (addr type-tree), type-parameters: (addr table (handle array byte) (addr type-tree)) -> result/eax: boolean
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # if (call == literal) return true  # TODO: more precise
    (is-simple-mu-type? *(ebp+0xc) 0)  # literal => eax
    3d/compare-eax-and 0/imm32/false
    b8/copy-to-eax 1/imm32/true
    75/jump-if-!= $type-match?:end/disp8
$type-match?:baseline:
    # otherwise fall back
    (type-component-match? *(ebp+8) *(ebp+0xc) *(ebp+0x10))  # => eax
$type-match?:end:
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

type-component-match?:  # def: (addr type-tree), call: (addr type-tree), type-parameters: (addr table (handle array byte) (addr type-tree)) -> result/eax: boolean
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    52/push-edx
    53/push-ebx
    # ecx = def
    8b/-> *(ebp+8) 1/r32/ecx
    # edx = call
    8b/-> *(ebp+0xc) 2/r32/edx
$type-component-match?:compare-addr:
    # if (def == call) return true
    8b/-> %ecx 0/r32/eax  # Var-type
    39/compare %edx 0/r32/eax  # Var-type
    b8/copy-to-eax 1/imm32/true
    0f 84/jump-if-= $type-component-match?:end/disp32
    # if (def == 0) return false
    b8/copy-to-eax 0/imm32/false
    81 7/subop/compare %ecx 0/imm32  # Type-tree-is-atom
    0f 84/jump-if-= $type-component-match?:end/disp32
    # if (call == 0) return false
    81 7/subop/compare %edx 0/imm32  # Type-tree-is-atom
    0f 84/jump-if-= $type-component-match?:end/disp32
    # if def is a type parameter, just check in type-parameters
    {
$type-component-match?:check-type-parameter:
      81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
      74/jump-if-= break/disp8
      81 7/subop/compare *(ecx+4) 0xa/imm32/type-parameter  # Type-tree-value
      75/jump-if-!= break/disp8
$type-component-match?:type-parameter:
      (type-parameter-match? *(ecx+8) *(ecx+0xc)  %edx  *(ebp+0x10))  # => eax
      e9/jump $type-component-match?:end/disp32
    }
    # if def is a list containing just a type parameter, just check in type-parameters
    {
$type-component-match?:check-list-type-parameter:
      # if def is a list..
      81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
      75/jump-if-!= break/disp8
      #   ..that's a singleton
      81 7/subop/compare *(ecx+0xc) 0/imm32  # Type-tree-left
      75/jump-if-!= break/disp8
      #   ..and whose head is a type parameter
      (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
      81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
      74/jump-if-= break/disp8
      81 7/subop/compare *(eax+4) 0xa/imm32/type-parameter  # Type-tree-value
      75/jump-if-!= break/disp8
$type-component-match?:list-type-parameter:
      (type-parameter-match? *(eax+8) *(eax+0xc)  %edx  *(ebp+0x10))  # => eax
      e9/jump $type-component-match?:end/disp32
    }
$type-component-match?:compare-atom-state:
    # if (def->is-atom? != call->is-atom?) return false
    8b/-> *ecx 3/r32/ebx  # Type-tree-is-atom
    39/compare *edx 3/r32/ebx  # Type-tree-is-atom
    b8/copy-to-eax 0/imm32/false
    0f 85/jump-if-!= $type-component-match?:end/disp32
    # if def->is-atom? return (def->value == call->value)
    {
$type-component-match?:check-atom:
      81 7/subop/compare %ebx 0/imm32/false
      74/jump-if-= break/disp8
$type-component-match?:is-atom:
      8b/-> *(ecx+4) 0/r32/eax  # Type-tree-value
      39/compare *(edx+4) 0/r32/eax  # Type-tree-value
      0f 94/set-if-= %al
      81 4/subop/and %eax 0xff/imm32
      e9/jump $type-component-match?:end/disp32
    }
$type-component-match?:check-left:
    # if (!type-component-match?(def->left, call->left)) return false
    (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
    89/<- %ebx 0/r32/eax
    (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
    (type-component-match? %ebx %eax *(ebp+0x10))  # => eax
    3d/compare-eax-and 0/imm32/false
    74/jump-if-= $type-component-match?:end/disp8
$type-component-match?:check-right:
    # return type-component-match?(def->right, call->right)
    (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
    89/<- %ebx 0/r32/eax
    (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
    (type-component-match? %ebx %eax *(ebp+0x10))  # => eax
$type-component-match?:end:
    # . restore registers
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

type-parameter-match?:  # type-parameter-name: (handle array byte), type: (addr type-tree), type-parameters: (addr table (handle array byte) (addr type-tree)) -> result/eax: boolean
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    #
    (get-or-insert-handle *(ebp+0x14)  *(ebp+8) *(ebp+0xc)  0xc)  # => eax
    # if parameter wasn't saved, save it
    {
      81 7/subop/compare *eax 0/imm32
      75/jump-if-!= break/disp8
      8b/-> *(ebp+0x10) 1/r32/ecx
      89/<- *eax 1/r32/ecx
    }
    #
    (type-equal? *(ebp+0x10) *eax)  # => eax
$type-parameter-match?:end:
    # . restore registers
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

size-of:  # v: (addr var) -> result/eax: int
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    # var t/ecx: (addr type-tree) = lookup(v->type)
    8b/-> *(ebp+8) 1/r32/ecx
#?     (write-buffered Stderr "size-of ")
#?     (write-int32-hex-buffered Stderr %ecx)
#?     (write-buffered Stderr Newline)
#?     (write-buffered Stderr "type allocid: ")
#?     (write-int32-hex-buffered Stderr *(ecx+8))
#?     (write-buffered Stderr Newline)
#?     (flush Stderr)
    (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
    89/<- %ecx 0/r32/eax
    # if is-mu-array?(t) return size-of-array(t)
    {
      (is-mu-array? %ecx)  # => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
      (size-of-array %ecx)  # => eax
      eb/jump $size-of:end/disp8
    }
    # if is-mu-stream?(t) return size-of-stream(t)
    {
      (is-mu-stream? %ecx)  # => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
      (size-of-stream %ecx)  # => eax
      eb/jump $size-of:end/disp8
    }
    # if (!t->is-atom?) t = lookup(t->left)
    {
      81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
      75/jump-if-!= break/disp8
      (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
      89/<- %ecx 0/r32/eax
    }
    # TODO: assert t->is-atom?
    (size-of-type-id *(ecx+4))  # Type-tree-value => eax
$size-of:end:
    # . restore registers
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

size-of-deref:  # v: (addr var) -> result/eax: int
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    # var t/ecx: (addr type-tree) = lookup(v->type)
    8b/-> *(ebp+8) 1/r32/ecx
    (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
    89/<- %ecx 0/r32/eax
    # TODO: assert(t is an addr)
    # t = lookup(t->right)
    (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
    89/<- %ecx 0/r32/eax
    # if is-mu-array?(t) return size-of-array(t)
    {
      (is-mu-array? %ecx)  # => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
      (size-of-array %ecx)  # => eax
      eb/jump $size-of-deref:end/disp8
    }
    # if is-mu-stream?(t) return size-of-stream(t)
    {
      (is-mu-stream? %ecx)  # => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
      (size-of-stream %ecx)  # => eax
      eb/jump $size-of-deref:end/disp8
    }
    # if (!t->is-atom?) t = lookup(t->left)
    {
      81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
      75/jump-if-!= break/disp8
      (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
      89/<- %ecx 0/r32/eax
    }
    # TODO: assert t->is-atom?
    (size-of-type-id *(ecx+4))  # Type-tree-value => eax
$size-of-deref:end:
    # . restore registers
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

is-mu-array?:  # t: (addr type-tree) -> result/eax: boolean
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    # ecx = t
    8b/-> *(ebp+8) 1/r32/ecx
    # if t->is-atom?, return false
    81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
    75/jump-if-!= $is-mu-array?:return-false/disp8
    # if !t->left->is-atom?, return false
    (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
    81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
    74/jump-if-= $is-mu-array?:return-false/disp8
    # return t->left->value == array
    81 7/subop/compare *(eax+4) 3/imm32/array-type-id  # Type-tree-value
    0f 94/set-if-= %al
    81 4/subop/and %eax 0xff/imm32
    eb/jump $is-mu-array?:end/disp8
$is-mu-array?:return-false:
    b8/copy-to-eax 0/imm32/false
$is-mu-array?:end:
    # . restore registers
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# size of a statically allocated array where the size is part of the type expression
size-of-array:  # a: (addr type-tree) -> result/eax: int
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    52/push-edx
    #
    8b/-> *(ebp+8) 1/r32/ecx
    # TODO: assert that a->left is 'array'
    (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
    89/<- %ecx 0/r32/eax
    # var elem-type/edx: type-id = a->right->left->value
    (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
    8b/-> *(eax+4) 2/r32/edx  # Type-tree-value
    # TODO: assert that a->right->right->left->value == size
    # var array-size/ecx: int = a->right->right->left->value-size
    (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
    (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
    8b/-> *(eax+8) 1/r32/ecx  # Type-tree-value-size
    # return 4 + array-size * size-of(elem-type)
    (size-of-type-id-as-array-element %edx)  # => eax
    f7 4/subop/multiply-into-edx-eax %ecx
    05/add-to-eax 4/imm32  # for array size
    # TODO: check edx for overflow
$size-of-array:end:
    # . restore registers
    5a/pop-to-edx
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

is-mu-stream?:  # t: (addr type-tree) -> result/eax: boolean
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    # ecx = t
    8b/-> *(ebp+8) 1/r32/ecx
    # if t->is-atom?, return false
    81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
    75/jump-if-!= $is-mu-stream?:return-false/disp8
    # if !t->left->is-atom?, return false
    (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
    81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
    74/jump-if-= $is-mu-stream?:return-false/disp8
    # return t->left->value == stream
    81 7/subop/compare *(eax+4) 0xb/imm32/stream-type-id  # Type-tree-value
    0f 94/set-if-= %al
    81 4/subop/and %eax 0xff/imm32
    eb/jump $is-mu-stream?:end/disp8
$is-mu-stream?:return-false:
    b8/copy-to-eax 0/imm32/false
$is-mu-stream?:end:
    # . restore registers
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# size of a statically allocated stream where the size is part of the type expression
size-of-stream:  # a: (addr type-tree) -> result/eax: int
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    #
    (size-of-array *(ebp+8))  # assumes we ignore the actual type name 'array' in the type
    05/add-to-eax 8/imm32  # for read/write pointers
$size-of-stream:end:
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

size-of-type-id:  # t: type-id -> result/eax: int
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    # var out/ecx: (handle typeinfo)
    68/push 0/imm32
    68/push 0/imm32
    89/<- %ecx 4/r32/esp
    # eax = t
    8b/-> *(ebp+8) 0/r32/eax
    # if t is a literal, return 0
    3d/compare-eax-and 0/imm32
    0f 84/jump-if-= $size-of-type-id:end/disp32  # eax changes type from type-id to int
    # if t is a byte, return 4 (because we don't really support non-multiples of 4)
    3d/compare-eax-and 8/imm32/byte
    {
      75/jump-if-!= break/disp8
      b8/copy-to-eax 4/imm32
      eb/jump $size-of-type-id:end/disp8
    }
    # if t is a handle, return 8
    3d/compare-eax-and 4/imm32/handle
    {
      75/jump-if-!= break/disp8
      b8/copy-to-eax 8/imm32
      eb/jump $size-of-type-id:end/disp8  # eax changes type from type-id to int
    }
    # if t is a slice, return 8
    3d/compare-eax-and 0xc/imm32/slice
    {
      75/jump-if-!= break/disp8
      b8/copy-to-eax 8/imm32
      eb/jump $size-of-type-id:end/disp8  # eax changes type from type-id to int
    }
    # if t is a user-defined type, return its size
    # TODO: support non-atom type
    (find-typeinfo %eax %ecx)
    {
      81 7/subop/compare *ecx 0/imm32
      74/jump-if-= break/disp8
$size-of-type-id:user-defined:
      (lookup *ecx *(ecx+4))  # => eax
      8b/-> *(eax+0xc) 0/r32/eax  # Typeinfo-total-size-in-bytes
      eb/jump $size-of-type-id:end/disp8
    }
    # otherwise return the word size
    b8/copy-to-eax 4/imm32
$size-of-type-id:end:
    # . reclaim locals
    81 0/subop/add %esp 8/imm32
    # . restore registers
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# Minor violation of our type system since it returns an addr. But we could
# replace it with a handle some time.
# Returns null if t is an atom.
type-tail:  # t: (addr type-tree) -> out/eax: (addr type-tree)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    # eax = 0
    b8/copy-to-eax 0/imm32
    # ecx = t
    8b/-> *(ebp+8) 1/r32/ecx
$type-tail:check-atom:
    # if t->is-atom? return 0
    81 7/subop/compare *ecx 0/imm32/false  # Type-tree-is-atom
    0f 85/jump-if-!= $type-tail:end/disp32
    # var tail = t->right
    (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
    89/<- %ecx 0/r32/eax
$type-tail:check-singleton:
    # if (tail->right == 0) return tail->left
    {
      81 7/subop/compare *(ecx+0xc) 0/imm32  # Type-tree-right
      75/jump-if-!= break/disp8
      (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
      e9/jump $type-tail:end/disp32
    }
    # if tail->right->left is an array-capacity, return tail->left
    {
$type-tail:check-array-capacity:
      (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
      81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
      75/jump-if-!= break/disp8
$type-tail:check-array-capacity-1:
      (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
      3d/compare-eax-and 0/imm32
      74/jump-if-= break/disp8
$type-tail:check-array-capacity-2:
      (is-simple-mu-type? %eax 9)  # array-capacity => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
$type-tail:array-capacity:
      (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
      eb/jump $type-tail:end/disp8
    }
$type-tail:check-compound-left:
    # if !tail->left->is-atom? return tail->left
    (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
    81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
    74/jump-if-= $type-tail:end/disp8
$type-tail:return-tail:
    # return tail
    89/<- %eax 1/r32/ecx
$type-tail:end:
    # . restore registers
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

type-equal?:  # a: (addr type-tree), b: (addr type-tree) -> result/eax: boolean
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    52/push-edx
    53/push-ebx
    # ecx = a
    8b/-> *(ebp+8) 1/r32/ecx
    # edx = b
    8b/-> *(ebp+0xc) 2/r32/edx
$type-equal?:compare-addr:
    # if (a == b) return true
    8b/-> %ecx 0/r32/eax  # Var-type
    39/compare %edx 0/r32/eax  # Var-type
    b8/copy-to-eax 1/imm32/true
    0f 84/jump-if-= $type-equal?:end/disp32
$type-equal?:compare-null-a:
    # if (a == 0) return false
    b8/copy-to-eax 0/imm32/false
    81 7/subop/compare %ecx 0/imm32
    0f 84/jump-if-= $type-equal?:end/disp32
$type-equal?:compare-null-b:
    # if (b == 0) return false
    81 7/subop/compare %edx 0/imm32
    0f 84/jump-if-= $type-equal?:end/disp32
$type-equal?:compare-atom-state:
    # if (a->is-atom? != b->is-atom?) return false
    8b/-> *ecx 3/r32/ebx  # Type-tree-is-atom
    39/compare *edx 3/r32/ebx  # Type-tree-is-atom
    b8/copy-to-eax 0/imm32/false
    0f 85/jump-if-!= $type-equal?:end/disp32
    # if a->is-atom? return (a->value == b->value)
    {
$type-equal?:check-atom:
      81 7/subop/compare %ebx 0/imm32/false
      74/jump-if-= break/disp8
$type-equal?:is-atom:
      8b/-> *(ecx+4) 0/r32/eax  # Type-tree-value
      39/compare *(edx+4) 0/r32/eax  # Type-tree-value
      0f 94/set-if-= %al
      81 4/subop/and %eax 0xff/imm32
      e9/jump $type-equal?:end/disp32
    }
$type-equal?:check-left:
    # if (!type-equal?(a->left, b->left)) return false
    (lookup *(ecx+4) *(ecx+8))  # Type-tree-left Type-tree-left => eax
    89/<- %ebx 0/r32/eax
    (lookup *(edx+4) *(edx+8))  # Type-tree-left Type-tree-left => eax
    (type-equal? %eax %ebx)  # => eax
    3d/compare-eax-and 0/imm32/false
    74/jump-if-= $type-equal?:end/disp8
$type-equal?:check-right:
    # return type-equal?(a->right, b->right)
    (lookup *(ecx+0xc) *(ecx+0x10))  # Type-tree-right Type-tree-right => eax
    89/<- %ebx 0/r32/eax
    (lookup *(edx+0xc) *(edx+0x10))  # Type-tree-right Type-tree-right => eax
    (type-equal? %eax %ebx)  # => eax
$type-equal?:end:
    # . restore registers
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

#######################################################
# Code-generation
#######################################################

== data

# Global state added to each var record when performing code-generation.
Curr-local-stack-offset:  # (addr int)
    0/imm32

== code

emit-subx:  # out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    # var curr/eax: (addr function) = *Program->functions
    (lookup *_Program-functions *_Program-functions->payload)  # => eax
    {
      # if (curr == null) break
      3d/compare-eax-and 0/imm32
      0f 84/jump-if-= break/disp32
      (emit-subx-function *(ebp+8) %eax *(ebp+0xc) *(ebp+0x10))
      # curr = lookup(curr->next)
      (lookup *(eax+0x20) *(eax+0x24))  # Function-next Function-next => eax
      e9/jump loop/disp32
    }
$emit-subx:end:
    # . restore registers
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

emit-subx-function:  # out: (addr buffered-file), f: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # some preprocessing
    (populate-mu-type-offsets-in-inouts *(ebp+0xc))
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    # initialize some global state
    c7 0/subop/copy *Curr-block-depth 1/imm32  # Important: keep this in sync with the parse phase
    c7 0/subop/copy *Curr-local-stack-offset 0/imm32
    # ecx = f
    8b/-> *(ebp+0xc) 1/r32/ecx
    # var vars/edx: (stack (addr var) 256)
    81 5/subop/subtract %esp 0xc00/imm32
    68/push 0xc00/imm32/size
    68/push 0/imm32/top
    89/<- %edx 4/r32/esp
    # var name/eax: (addr array byte) = lookup(f->name)
    (lookup *ecx *(ecx+4))  # Function-name Function-name => eax
    #
    (write-buffered *(ebp+8) %eax)
    (write-buffered *(ebp+8) ":\n")
    (emit-subx-prologue *(ebp+8))
    # var body/eax: (addr block) = lookup(f->body)
    (lookup *(ecx+0x18) *(ecx+0x1c))  # Function-body Function-body => eax
    #
    (emit-subx-block *(ebp+8) %eax %edx *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
    (emit-subx-epilogue *(ebp+8))
    # TODO: validate that *Curr-block-depth and *Curr-local-stack-offset have
    # been cleaned up
$emit-subx-function:end:
    # . reclaim locals
    81 0/subop/add %esp 0xc08/imm32
    # . restore registers
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

populate-mu-type-offsets-in-inouts:  # f: (addr function)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    57/push-edi
    # var next-offset/edx: int = 8
    ba/copy-to-edx 8/imm32
    # var curr/ecx: (addr list var) = lookup(f->inouts)
    8b/-> *(ebp+8) 1/r32/ecx
    (lookup *(ecx+8) *(ecx+0xc))  # Function-inouts Function-inouts => eax
    89/<- %ecx 0/r32/eax
    {
$populate-mu-type-offsets-in-inouts:loop:
      81 7/subop/compare %ecx 0/imm32
      74/jump-if-= break/disp8
      # var v/ebx: (addr var) = lookup(curr->value)
      (lookup *ecx *(ecx+4))  # List-value List-value => eax
      89/<- %ebx 0/r32/eax
#?       (lookup *ebx *(ebx+4))
#?       (write-buffered Stderr "setting offset of fn inout ")
#?       (write-buffered Stderr %eax)
#?       (write-buffered Stderr "@")
#?       (write-int32-hex-buffered Stderr %ebx)
#?       (write-buffered Stderr " to ")
#?       (write-int32-hex-buffered Stderr %edx)
#?       (write-buffered Stderr Newline)
#?       (flush Stderr)
      # v->offset = next-offset
      89/<- *(ebx+0x14) 2/r32/edx  # Var-offset
      # next-offset += size-of(v)
      (size-of %ebx)  # => eax
      01/add-to %edx 0/r32/eax
      # curr = lookup(curr->next)
      (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
      89/<- %ecx 0/r32/eax
      #
      eb/jump loop/disp8
    }
$populate-mu-type-offsets-in-inouts:end:
    # . restore registers
    5f/pop-to-edi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

emit-subx-stmt-list:  # out: (addr buffered-file), stmts: (addr list stmt), vars: (addr stack live-var), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    53/push-ebx
    56/push-esi
    # esi = stmts
    8b/-> *(ebp+0xc) 6/r32/esi
    #
    {
$emit-subx-stmt-list:loop:
      81 7/subop/compare %esi 0/imm32
      0f 84/jump-if-= break/disp32
      # var curr-stmt/ecx: (addr stmt) = lookup(stmts->value)
      (lookup *esi *(esi+4))  # List-value List-value => eax
      89/<- %ecx 0/r32/eax
      {
$emit-subx-stmt-list:check-for-block:
        81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
        75/jump-if-!= break/disp8
$emit-subx-stmt-list:block:
        (emit-subx-block *(ebp+8) %ecx *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
      }
      {
$emit-subx-stmt-list:check-for-stmt:
        81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
        0f 85/jump-if-!= break/disp32
$emit-subx-stmt-list:stmt1:
        {
          (is-mu-branch? %ecx)  # => eax
          3d/compare-eax-and 0/imm32/false
          0f 84/jump-if-= break/disp32
$emit-subx-stmt-list:branch-stmt:
          # unconditional loops {{{
          {
            # if (!string-equal?(var->operation, "loop")) break
            (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
            (string-equal? %eax "loop")  # => eax
            3d/compare-eax-and 0/imm32/false
            0f 84/jump-if-= break/disp32
$emit-subx-stmt-list:unconditional-loop:
            81 7/subop/compare *(ecx+0xc) 0/imm32  # Stmt1-inouts
            # simple unconditional loops without a target
            {
              0f 85/jump-if-!= break/disp32
$emit-subx-stmt-list:zero-arg-unconditional-loop:
              (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth)
              (emit-indent *(ebp+8) *Curr-block-depth)
              (write-buffered *(ebp+8) "e9/jump loop/disp32")
              (write-buffered *(ebp+8) Newline)
              e9/jump $emit-subx-stmt-list:clean-up/disp32  # skip remaining statements; they're dead code
            }
            # unconditional loops with a target
            {
              0f 84/jump-if-= break/disp32
              (emit-subx-cleanup-and-unconditional-nonlocal-branch *(ebp+8) %ecx *(ebp+0x10))
              e9/jump $emit-subx-stmt-list:clean-up/disp32
            }
          }
          # }}}
          # unconditional breaks {{{
          {
            # if (!string-equal?(curr-stmt->operation, "break")) break
            (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
            (string-equal? %eax "break")  # => eax
            3d/compare-eax-and 0/imm32/false
            0f 84/jump-if-= break/disp32
$emit-subx-stmt-list:unconditional-break:
            81 7/subop/compare *(ecx+0xc) 0/imm32  # Stmt1-inouts
            # simple unconditional breaks without a target
            0f 84/jump-if-= $emit-subx-stmt-list:emit-cleanup/disp32  # easy: just skip remaining statements
            # unconditional breaks with a target
            (emit-subx-cleanup-and-unconditional-nonlocal-branch *(ebp+8) %ecx *(ebp+0x10))
            e9/jump $emit-subx-stmt-list:clean-up/disp32
          }
          # }}}
          # simple conditional branches without a target {{{
          81 7/subop/compare *(ecx+0xc) 0/imm32  # Stmt1-inouts
          {
            0f 85/jump-if-!= break/disp32
$emit-subx-stmt-list:zero-arg-conditional-branch:
            # var old-block-depth/ebx: int = Curr-block-depth - 1
            8b/-> *Curr-block-depth 3/r32/ebx
            # cleanup prologue
            (emit-indent *(ebp+8) *Curr-block-depth)
            (write-buffered *(ebp+8) "{\n")
            ff 0/subop/increment *Curr-block-depth
            #
            (emit-reverse-break *(ebp+8) %ecx)
            # clean up until old block depth
            (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) %ebx)
            # var target-block-depth/ebx: int = Curr-block-depth - 1
            4b/decrement-ebx
            # emit jump to target block
            (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
            (string-starts-with? %eax "break")  # => eax
            3d/compare-eax-and 0/imm32/false
            {
              74/jump-if-= break/disp8
              (emit-unconditional-jump-to-depth *(ebp+8) *(ebp+0x10) %ebx "break")
            }
            3d/compare-eax-and 0/imm32/false  # just in case the function call modified flags
            {
              75/jump-if-!= break/disp8
              (emit-unconditional-jump-to-depth *(ebp+8) *(ebp+0x10) %ebx "loop")
            }
            # cleanup epilogue
            ff 1/subop/decrement *Curr-block-depth
            (emit-indent *(ebp+8) *Curr-block-depth)
            (write-buffered *(ebp+8) "}\n")
            # continue
            e9/jump $emit-subx-stmt-list:continue/disp32
          }
          # }}}
          # conditional branches with an explicit target {{{
          {
            0f 84/jump-if-= break/disp32
$emit-subx-stmt-list:conditional-branch-with-target:
            # cleanup prologue
            (emit-indent *(ebp+8) *Curr-block-depth)
            (write-buffered *(ebp+8) "{\n")
            ff 0/subop/increment *Curr-block-depth
            #
            (emit-reverse-break *(ebp+8) %ecx)
            (emit-subx-cleanup-and-unconditional-nonlocal-branch *(ebp+8) %ecx *(ebp+0x10))
            # cleanup epilogue
            ff 1/subop/decrement *Curr-block-depth
            (emit-indent *(ebp+8) *Curr-block-depth)
            (write-buffered *(ebp+8) "}\n")
            # continue
            e9/jump $emit-subx-stmt-list:continue/disp32
          }
          # }}}
        }
$emit-subx-stmt-list:1-to-1:
        (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
        e9/jump $emit-subx-stmt-list:continue/disp32
      }
      {
$emit-subx-stmt-list:check-for-var-def:
        81 7/subop/compare *ecx 2/imm32/var-def  # Stmt-tag
        75/jump-if-!= break/disp8
$emit-subx-stmt-list:var-def:
        (emit-subx-var-def *(ebp+8) %ecx)
        (push *(ebp+0x10) *(ecx+4))  # Vardef-var
        (push *(ebp+0x10) *(ecx+8))  # Vardef-var
        (push *(ebp+0x10) 0)  # Live-var-register-spilled = 0 for vars on the stack
        #
        eb/jump $emit-subx-stmt-list:continue/disp8
      }
      {
$emit-subx-stmt-list:check-for-reg-var-def:
        81 7/subop/compare *ecx 3/imm32/reg-var-def  # Stmt-tag
        0f 85/jump-if-!= break/disp32
$emit-subx-stmt-list:reg-var-def:
        # TODO: ensure that there's exactly one output
        (push-output-and-maybe-emit-spill *(ebp+8) %ecx *(ebp+0x10) %esi *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
        # emit the instruction as usual
        (emit-subx-stmt *(ebp+8) %ecx Primitives *(ebp+0x18) *(ebp+0x1c))
        #
        eb/jump $emit-subx-stmt-list:continue/disp8
      }
$emit-subx-stmt-list:continue:
      # TODO: raise an error on unrecognized Stmt-tag
      (lookup *(esi+8) *(esi+0xc))  # List-next List-next => eax
      89/<- %esi 0/r32/eax
      e9/jump loop/disp32
    }
$emit-subx-stmt-list:emit-cleanup:
    (emit-cleanup-code-until-depth *(ebp+8) *(ebp+0x10) *Curr-block-depth)
$emit-subx-stmt-list:clean-up:
    (clean-up-stack-offset-state *(ebp+0x10) *Curr-block-depth)
    (clean-up-blocks *(ebp+0x10) *Curr-block-depth *(ebp+0x14))
$emit-subx-stmt-list:end:
    # . restore registers
    5e/pop-to-esi
    5b/pop-to-ebx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# 'later-stmts' includes 'stmt', but will behave the same even without it; reg-var-def stmts are guaranteed not to write to function outputs.
push-output-and-maybe-emit-spill:  # out: (addr buffered-file), stmt: (addr reg-var-def), vars: (addr stack (handle var)), later-stmts: (addr list stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    # ecx = stmt
    8b/-> *(ebp+0xc) 1/r32/ecx
    # var sv/eax: (addr stmt-var) = lookup(curr-stmt->outputs)
    (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
    # TODO: assert !sv->is-deref?
    # var v/ecx: (addr var) = lookup(sv->value)
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    89/<- %ecx 0/r32/eax
    # v->block-depth = *Curr-block-depth
    8b/-> *Curr-block-depth 0/r32/eax
    89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
#?     (write-buffered Stderr "var ")
#?     (lookup *ecx *(ecx+4))
#?     (write-buffered Stderr %eax)
#?     (write-buffered Stderr " at depth ")
#?     (write-int32-hex-buffered Stderr *(ecx+0x10))
#?     (write-buffered Stderr Newline)
#?     (flush Stderr)
    # ensure that v is in a register
    81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
    0f 84/jump-if-= $push-output-and-maybe-emit-spill:abort/disp32
    # var emit-spill?/edx: boolean = not-yet-spilled-this-block? && will-not-write-some-register?(fn)
    (not-yet-spilled-this-block? %ecx *(ebp+0x10))  # => eax
    89/<- %edx 0/r32/eax
    3d/compare-eax-and 0/imm32/false
    0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
    (will-not-write-some-register? %ecx *(ebp+0x14) *(ebp+0x18))  # => eax
    89/<- %edx 0/r32/eax
    # check emit-spill?
    3d/compare-eax-and 0/imm32/false
    0f 84/jump-if-= $push-output-and-maybe-emit-spill:push/disp32
    # TODO: assert(size-of(output) == 4)
    # *Curr-local-stack-offset -= 4
    81 5/subop/subtract *Curr-local-stack-offset 4/imm32
    # emit spill
    (emit-indent *(ebp+8) *Curr-block-depth)
    (write-buffered *(ebp+8) "ff 6/subop/push %")
    (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
    (write-buffered *(ebp+8) %eax)
    (write-buffered *(ebp+8) Newline)
$push-output-and-maybe-emit-spill:push:
    8b/-> *(ebp+0xc) 1/r32/ecx
    (lookup *(ecx+0x14) *(ecx+0x18))  # Regvardef-outputs Regvardef-outputs => eax
    # push(vars, {sv->value, emit-spill?})
    (push *(ebp+0x10) *eax)  # Stmt-var-value
    (push *(ebp+0x10) *(eax+4))  # Stmt-var-value
    (push *(ebp+0x10) %edx)
$push-output-and-maybe-emit-spill:end:
    # . restore registers
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$push-output-and-maybe-emit-spill:abort:
    # error("var '" var->name "' initialized from an instruction must live in a register\n")
    (write-buffered *(ebp+0x1c) "var '")
    (write-buffered *(ebp+0x1c) *eax)  # Var-name
    (write-buffered *(ebp+0x1c) "' initialized from an instruction must live in a register\n")
    (flush *(ebp+0x1c))
    (stop *(ebp+0x20) 1)
    # never gets here

emit-subx-cleanup-and-unconditional-nonlocal-branch:  # out: (addr buffered-file), stmt: (addr stmt1), vars: (addr stack live-var)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    # ecx = stmt
    8b/-> *(ebp+0xc) 1/r32/ecx
    # var target/eax: (addr array byte) = curr-stmt->inouts->value->name
    (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    (lookup *eax *(eax+4))  # Var-name Var-name => eax
    # clean up until target block
    (emit-cleanup-code-until-target *(ebp+8) *(ebp+0x10) %eax)
    # emit jump to target block
    (emit-indent *(ebp+8) *Curr-block-depth)
    (write-buffered *(ebp+8) "e9/jump ")
    (write-buffered *(ebp+8) %eax)
    (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
    (string-starts-with? %eax "break")
    3d/compare-eax-and 0/imm32/false
    {
      74/jump-if-= break/disp8
      (write-buffered *(ebp+8) ":break/disp32\n")
    }
    3d/compare-eax-and 0/imm32/false  # just in case the function call modified flags
    {
      75/jump-if-!= break/disp8
      (write-buffered *(ebp+8) ":loop/disp32\n")
    }
$emit-subx-cleanup-and-unconditional-nonlocal-branch:end:
    # . restore registers
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

is-mu-branch?:  # stmt: (addr stmt1) -> result/eax: boolean
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    # ecx = lookup(stmt->operation)
    8b/-> *(ebp+8) 1/r32/ecx
    (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
    89/<- %ecx 0/r32/eax
    # if (stmt->operation starts with "loop") return true
    (string-starts-with? %ecx "loop")  # => eax
    3d/compare-eax-and 0/imm32/false
    75/jump-if-not-equal $is-mu-branch?:end/disp8
    # otherwise return (stmt->operation starts with "break")
    (string-starts-with? %ecx "break")  # => eax
$is-mu-branch?:end:
    # . restore registers
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

emit-reverse-break:  # out: (addr buffered-file), stmt: (addr stmt1)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    # eax = stmt
    8b/-> *(ebp+0xc) 0/r32/eax
    #
    (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
    (get Reverse-branch %eax 0x10 "reverse-branch: ")  # => eax: (addr handle array byte)
    (emit-indent *(ebp+8) *Curr-block-depth)
    (lookup *eax *(eax+4))  # => eax
    (write-buffered *(ebp+8) %eax)
    (write-buffered *(ebp+8) " break/disp32\n")
$emit-reverse-break:end:
    # . restore registers
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

== data

# Table from Mu branch instructions to the reverse SubX opcodes for them.
Reverse-branch:  # (table (handle array byte) (handle array byte))
  # a table is a stream
  0x140/imm32/write
  0/imm32/read
  0x140/imm32/size
  # data
  0x11/imm32/alloc-id   _string-break-if-=/imm32                0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
  0x11/imm32/alloc-id   _string-loop-if-=/imm32                 0x11/imm32/alloc-id   _string_0f_85_jump_label/imm32
  0x11/imm32/alloc-id   _string-break-if-!=/imm32               0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
  0x11/imm32/alloc-id   _string-loop-if-!=/imm32                0x11/imm32/alloc-id   _string_0f_84_jump_label/imm32
  0x11/imm32/alloc-id   _string-break-if-</imm32                0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
  0x11/imm32/alloc-id   _string-loop-if-</imm32                 0x11/imm32/alloc-id   _string_0f_8d_jump_label/imm32
  0x11/imm32/alloc-id   _string-break-if->/imm32                0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
  0x11/imm32/alloc-id   _string-loop-if->/imm32                 0x11/imm32/alloc-id   _string_0f_8e_jump_label/imm32
  0x11/imm32/alloc-id   _string-break-if-<=/imm32               0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
  0x11/imm32/alloc-id   _string-loop-if-<=/imm32                0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
  0x11/imm32/alloc-id   _string-break-if->=/imm32               0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
  0x11/imm32/alloc-id   _string-loop-if->=/imm32                0x11/imm32/alloc-id   _string_0f_8c_jump_label/imm32
  0x11/imm32/alloc-id   _string-break-if-addr</imm32            0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
  0x11/imm32/alloc-id   _string-loop-if-addr</imm32             0x11/imm32/alloc-id   _string_0f_83_jump_label/imm32
  0x11/imm32/alloc-id   _string-break-if-addr>/imm32            0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
  0x11/imm32/alloc-id   _string-loop-if-addr>/imm32             0x11/imm32/alloc-id   _string_0f_86_jump_label/imm32
  0x11/imm32/alloc-id   _string-break-if-addr<=/imm32           0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
  0x11/imm32/alloc-id   _string-loop-if-addr<=/imm32            0x11/imm32/alloc-id   _string_0f_87_jump_label/imm32
  0x11/imm32/alloc-id   _string-break-if-addr>=/imm32           0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32
  0x11/imm32/alloc-id   _string-loop-if-addr>=/imm32            0x11/imm32/alloc-id   _string_0f_82_jump_label/imm32

== code

emit-unconditional-jump-to-depth:  # out: (addr buffered-file), vars: (addr stack live-var), depth: int, label-suffix: (addr array byte)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    56/push-esi
    # ecx = vars
    8b/-> *(ebp+0xc) 1/r32/ecx
    # var eax: int = vars->top
    8b/-> *ecx 0/r32/eax
    # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
    8d/copy-address *(ecx+eax-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
    # var min/ecx: (addr handle var) = vars->data
    8d/copy-address *(ecx+8) 1/r32/ecx
    # edx = depth
    8b/-> *(ebp+0x10) 2/r32/edx
    {
$emit-unconditional-jump-to-depth:loop:
      # if (curr < min) break
      39/compare %esi 1/r32/ecx
      0f 82/jump-if-addr< break/disp32
      # var v/ebx: (addr var) = lookup(*curr)
      (lookup *esi *(esi+4))  # => eax
      89/<- %ebx 0/r32/eax
      # if (v->block-depth < until-block-depth) break
      39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
      0f 8c/jump-if-< break/disp32
      {
$emit-unconditional-jump-to-depth:check:
        # if v->block-depth != until-block-depth, continue
        39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
        0f 85/jump-if-!= break/disp32
$emit-unconditional-jump-to-depth:depth-found:
        # if v is not a literal, continue
        (size-of %ebx)  # => eax
        3d/compare-eax-and 0/imm32
        0f 85/jump-if-!= break/disp32
$emit-unconditional-jump-to-depth:label-found:
        # emit unconditional jump, then return
        (emit-indent *(ebp+8) *Curr-block-depth)
        (write-buffered *(ebp+8) "e9/jump ")
        (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
        (write-buffered *(ebp+8) %eax)
        (write-buffered *(ebp+8) ":")
        (write-buffered *(ebp+8) *(ebp+0x14))
        (write-buffered *(ebp+8) "/disp32\n")
        eb/jump $emit-unconditional-jump-to-depth:end/disp8
      }
      # curr -= 12
      81 5/subop/subtract %esi 0xc/imm32
      e9/jump loop/disp32
    }
    # TODO: error if no label at 'depth' was found
$emit-unconditional-jump-to-depth:end:
    # . restore registers
    5e/pop-to-esi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# emit clean-up code for 'vars' until some block depth
# doesn't actually modify 'vars' so we need traverse manually inside the stack
emit-cleanup-code-until-depth:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-depth: int
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    56/push-esi
#?     (write-buffered Stderr "--- cleanup\n")
#?     (flush Stderr)
    # ecx = vars
    8b/-> *(ebp+0xc) 1/r32/ecx
    # var esi: int = vars->top
    8b/-> *ecx 6/r32/esi
    # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
    8d/copy-address *(ecx+esi-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
    # var min/ecx: (addr handle var) = vars->data
    81 0/subop/add %ecx 8/imm32
    # edx = until-block-depth
    8b/-> *(ebp+0x10) 2/r32/edx
    {
$emit-cleanup-code-until-depth:loop:
      # if (curr < min) break
      39/compare %esi 1/r32/ecx
      0f 82/jump-if-addr< break/disp32
      # var v/ebx: (addr var) = lookup(*curr)
      (lookup *esi *(esi+4))  # => eax
      89/<- %ebx 0/r32/eax
#?       (lookup *ebx *(ebx+4))  # Var-name
#?       (write-buffered Stderr "var ")
#?       (write-buffered Stderr %eax)
#?       (write-buffered Stderr Newline)
#?       (flush Stderr)
      # if (v->block-depth < until-block-depth) break
      39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
      0f 8c/jump-if-< break/disp32
      # if v is in a register
      81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
      {
        0f 84/jump-if-= break/disp32
        {
$emit-cleanup-code-until-depth:check-for-previous-spill:
          8b/-> *(esi+8) 0/r32/eax  # Live-var-register-spilled
          3d/compare-eax-and 0/imm32/false
          74/jump-if-= break/disp8
$emit-cleanup-code-until-depth:reclaim-var-in-register:
          (emit-indent *(ebp+8) *Curr-block-depth)
          (write-buffered *(ebp+8) "8f 0/subop/pop %")
          (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
          (write-buffered *(ebp+8) %eax)
          (write-buffered *(ebp+8) Newline)
        }
        eb/jump $emit-cleanup-code-until-depth:continue/disp8
      }
      # otherwise v is on the stack
      {
        75/jump-if-!= break/disp8
$emit-cleanup-code-until-depth:var-on-stack:
        (size-of %ebx)  # => eax
        # don't emit code for labels
        3d/compare-eax-and 0/imm32
        74/jump-if-= break/disp8
$emit-cleanup-code-until-depth:reclaim-var-on-stack:
        (emit-indent *(ebp+8) *Curr-block-depth)
        (write-buffered *(ebp+8) "81 0/subop/add %esp ")
        (write-int32-hex-buffered *(ebp+8) %eax)
        (write-buffered *(ebp+8) "/imm32\n")
      }
$emit-cleanup-code-until-depth:continue:
      # curr -= 12
      81 5/subop/subtract %esi 0xc/imm32
      e9/jump loop/disp32
    }
$emit-cleanup-code-until-depth:end:
    # . restore registers
    5e/pop-to-esi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# emit clean-up code for 'vars' until a given label is encountered
# doesn't actually modify 'vars' so we need traverse manually inside the stack
emit-cleanup-code-until-target:  # out: (addr buffered-file), vars: (addr stack live-var), until-block-label: (addr array byte)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    # ecx = vars
    8b/-> *(ebp+0xc) 1/r32/ecx
    # var eax: int = vars->top
    8b/-> *ecx 0/r32/eax
    # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
    8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
    # var min/ecx: (addr handle var) = vars->data
    81 0/subop/add %ecx 8/imm32
    {
$emit-cleanup-code-until-target:loop:
      # if (curr < min) break
      39/compare %edx 1/r32/ecx
      0f 82/jump-if-addr< break/disp32
      # var v/ebx: (handle var) = lookup(*curr)
      (lookup *edx *(edx+4))  # => eax
      89/<- %ebx 0/r32/eax
      # if (v->name == until-block-label) break
      (lookup *ebx *(ebx+4))  # Var-name Var-name => eax
      (string-equal? %eax *(ebp+0x10))  # => eax
      3d/compare-eax-and 0/imm32/false
      0f 85/jump-if-!= break/disp32
      # if v is in a register
      81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
      {
        0f 84/jump-if-= break/disp32
        {
$emit-cleanup-code-until-target:check-for-previous-spill:
          8b/-> *(edx+8) 0/r32/eax  # Live-var-register-spilled
          3d/compare-eax-and 0/imm32/false
          74/jump-if-= break/disp8
$emit-cleanup-code-until-target:reclaim-var-in-register:
          (emit-indent *(ebp+8) *Curr-block-depth)
          (write-buffered *(ebp+8) "8f 0/subop/pop %")
          (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
          (write-buffered *(ebp+8) %eax)
          (write-buffered *(ebp+8) Newline)
        }
        eb/jump $emit-cleanup-code-until-target:continue/disp8
      }
      # otherwise v is on the stack
      {
        75/jump-if-!= break/disp8
$emit-cleanup-code-until-target:reclaim-var-on-stack:
        (size-of %ebx)  # => eax
        # don't emit code for labels
        3d/compare-eax-and 0/imm32
        74/jump-if-= break/disp8
        #
        (emit-indent *(ebp+8) *Curr-block-depth)
        (write-buffered *(ebp+8) "81 0/subop/add %esp ")
        (write-int32-hex-buffered *(ebp+8) %eax)
        (write-buffered *(ebp+8) "/imm32\n")
      }
$emit-cleanup-code-until-target:continue:
      # curr -= 12
      81 5/subop/subtract %edx 0xc/imm32
      e9/jump loop/disp32
    }
$emit-cleanup-code-until-target:end:
    # . restore registers
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# update Curr-local-stack-offset assuming vars until some block depth are popped
# doesn't actually modify 'vars', so we need traverse manually inside the stack
clean-up-stack-offset-state:  # vars: (addr stack live-var), until-block-depth: int
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    56/push-esi
    # ecx = vars
    8b/-> *(ebp+8) 1/r32/ecx
    # var esi: int = vars->top
    8b/-> *ecx 6/r32/esi
    # var curr/esi: (addr handle var) = &vars->data[vars->top - 12]
    8d/copy-address *(ecx+esi-4) 6/r32/esi  # vars + 8 + vars->top - 12/Live-var-size
    # var min/ecx: (addr handle var) = vars->data
    81 0/subop/add %ecx 8/imm32
    # edx = until-block-depth
    8b/-> *(ebp+0xc) 2/r32/edx
    {
$clean-up-stack-offset-state:loop:
      # if (curr < min) break
      39/compare %esi 1/r32/ecx
      0f 82/jump-if-addr< break/disp32
      # var v/ebx: (addr var) = lookup(*curr)
      (lookup *esi *(esi+4))  # => eax
      89/<- %ebx 0/r32/eax
      # if (v->block-depth < until-block-depth) break
      39/compare *(ebx+0x10) 2/r32/edx  # Var-block-depth
      0f 8c/jump-if-< break/disp32
      # if v is in a register
      81 7/subop/compare *(ebx+0x18) 0/imm32  # Var-register
      {
        0f 84/jump-if-= break/disp32
        {
$clean-up-stack-offset-state:check-for-previous-spill:
          8b/-> *(esi+8) 0/r32/eax  # Live-var-register-spilled
          3d/compare-eax-and 0/imm32/false
          74/jump-if-= break/disp8
$clean-up-stack-offset-state:reclaim-var-in-register:
          81 0/subop/add *Curr-local-stack-offset 4/imm32
        }
        eb/jump $clean-up-stack-offset-state:continue/disp8
      }
      # otherwise v is on the stack
      {
        75/jump-if-!= break/disp8
$clean-up-stack-offset-state:var-on-stack:
        (size-of %ebx)  # => eax
        01/add-to *Curr-local-stack-offset 0/r32/eax
      }
$clean-up-stack-offset-state:continue:
      # curr -= 12
      81 5/subop/subtract %esi 0xc/imm32
      e9/jump loop/disp32
    }
$clean-up-stack-offset-state:end:
    # . restore registers
    5e/pop-to-esi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# Return true if there isn't a variable in 'vars' with the same block-depth
# and register as 'v'.
# 'v' is guaranteed not to be within 'vars'.
not-yet-spilled-this-block?:  # v: (addr var), vars: (addr stack live-var) -> result/eax: boolean
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    52/push-edx
    53/push-ebx
    56/push-esi
    57/push-edi
    # ecx = vars
    8b/-> *(ebp+0xc) 1/r32/ecx
    # var eax: int = vars->top
    8b/-> *ecx 0/r32/eax
    # var curr/edx: (addr handle var) = &vars->data[vars->top - 12]
    8d/copy-address *(ecx+eax-4) 2/r32/edx  # vars + 8 + vars->top - 12/Live-var-size
    # var min/ecx: (addr handle var) = vars->data
    8d/copy-address *(ecx+8) 1/r32/ecx
    # var depth/ebx: int = v->block-depth
    8b/-> *(ebp+8) 3/r32/ebx
    8b/-> *(ebx+0x10) 3/r32/ebx  # Var-block-depth
    # var needle/esi: (addr array byte) = v->register
    8b/-> *(ebp+8) 6/r32/esi
    (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
    89/<- %esi 0/r32/eax
    {
$not-yet-spilled-this-block?:loop:
      # if (curr < min) break
      39/compare %edx 1/r32/ecx
      0f 82/jump-if-addr< break/disp32
      # var cand/edi: (addr var) = lookup(*curr)
      (lookup *edx *(edx+4))  # => eax
      89/<- %edi 0/r32/eax
      # if (cand->block-depth < depth) break
      39/compare *(edi+0x10) 3/r32/ebx  # Var-block-depth
      0f 8c/jump-if-< break/disp32
      # var cand-reg/edi: (array array byte) = cand->reg
      (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
      89/<- %edi 0/r32/eax
      # if (cand-reg == null) continue
      {
$not-yet-spilled-this-block?:check-reg:
        81 7/subop/compare %edi 0/imm32
        0f 84/jump-if-= break/disp32
        # if (cand-reg == needle) return true
        (string-equal? %esi %edi)  # => eax
        3d/compare-eax-and 0/imm32/false
        74/jump-if-= break/disp8
$not-yet-spilled-this-block?:return-false:
        b8/copy-to-eax 0/imm32/false
        eb/jump $not-yet-spilled-this-block?:end/disp8
      }
$not-yet-spilled-this-block?:continue:
      # curr -= 12
      81 5/subop/subtract %edx 0xc/imm32
      e9/jump loop/disp32
    }
$not-yet-spilled-this-block?:return-true:
    # return true
    b8/copy-to-eax 1/imm32/true
$not-yet-spilled-this-block?:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# could the register of 'v' ever be written to by one of the vars in fn-outputs?
will-not-write-some-register?:  # v: (addr var), stmts: (addr list stmt), fn: (addr function) -> result/eax: boolean
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # eax = v
    8b/-> *(ebp+8) 0/r32/eax
    # var reg/eax: (addr array byte) = lookup(v->register)
    (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
    # var target/eax: (addr var) = find-register(fn-outputs, reg)
    (find-register *(ebp+0x10) %eax)  # => eax
    # if (target == 0) return true
    {
      3d/compare-eax-and 0/imm32
      75/jump-if-!= break/disp8
      b8/copy-to-eax 1/imm32/true
      eb/jump $will-not-write-some-register?:end/disp8
    }
    # return !assigns-in-stmts?(stmts, target)
    (assigns-in-stmts? *(ebp+0xc) %eax)  # => eax
    3d/compare-eax-and 0/imm32/false
    # assume: true = 1, so no need to mask with 0x000000ff
    0f 94/set-if-= %al
$will-not-write-some-register?:end:
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# return fn output with matching register
# always returns false if 'reg' is null
find-register:  # fn: (addr function), reg: (addr array byte) -> result/eax: (addr var)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    # var curr/ecx: (addr list var) = lookup(fn->outputs)
    8b/-> *(ebp+8) 1/r32/ecx
    (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
    89/<- %ecx 0/r32/eax
    {
$find-register:loop:
      # if (curr == 0) break
      81 7/subop/compare %ecx 0/imm32
      74/jump-if-= break/disp8
      # eax = curr->value->register
      (lookup *ecx *(ecx+4))  # List-value List-value => eax
      (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
      # if (eax == reg) return curr->value
$find-register:compare:
      (string-equal? *(ebp+0xc) %eax)  # => eax
      {
        3d/compare-eax-and 0/imm32/false
        74/jump-if-= break/disp8
$find-register:found:
        (lookup *ecx *(ecx+4))  # List-value List-value => eax
        eb/jump $find-register:end/disp8
      }
      # curr = lookup(curr->next)
      (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
      89/<- %ecx 0/r32/eax
      #
      eb/jump loop/disp8
    }
$find-register:end:
    # . restore registers
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

assigns-in-stmts?:  # stmts: (addr list stmt), v: (addr var) -> result/eax: boolean
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    # var curr/ecx: (addr list stmt) = stmts
    8b/-> *(ebp+8) 1/r32/ecx
    {
      # if (curr == 0) break
      81 7/subop/compare %ecx 0/imm32
      74/jump-if-= break/disp8
      # if assigns-in-stmt?(curr->value, v) return true
      (lookup *ecx *(ecx+4))  # List-value List-value => eax
      (assigns-in-stmt? %eax *(ebp+0xc))  # => eax
      3d/compare-eax-and 0/imm32/false
      75/jump-if-!= break/disp8
      # curr = lookup(curr->next)
      (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
      89/<- %ecx 0/r32/eax
      #
      eb/jump loop/disp8
    }
$assigns-in-stmts?:end:
    # . restore registers
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

assigns-in-stmt?:  # stmt: (addr stmt), v: (addr var) -> result/eax: boolean
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    # ecx = stmt
    8b/-> *(ebp+8) 1/r32/ecx
    # if stmt is a stmt1, return assigns-in-stmt-vars?(stmt->outputs, v)
    {
      81 7/subop/compare *ecx 1/imm32/stmt1  # Stmt-tag
      75/jump-if-!= break/disp8
      (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
      (assigns-in-stmt-vars? %eax *(ebp+0xc))  # => eax
      eb/jump $assigns-in-stmt?:end/disp8
    }
    # if stmt is a block, return assigns-in-stmts?(stmt->stmts, v)
    {
      81 7/subop/compare *ecx 0/imm32/block  # Stmt-tag
      75/jump-if-!= break/disp8
      (lookup *(ecx+4) *(ecx+8))  # Block-stmts Block-stmts => eax
      (assigns-in-stmts? %eax *(ebp+0xc))  # => eax
      eb/jump $assigns-in-stmt?:end/disp8
    }
    # otherwise return false
    b8/copy 0/imm32/false
$assigns-in-stmt?:end:
    # . restore registers
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

assigns-in-stmt-vars?:  # stmt-var: (addr stmt-var), v: (addr var) -> result/eax: boolean
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    # var curr/ecx: (addr stmt-var) = stmt-var
    8b/-> *(ebp+8) 1/r32/ecx
    {
      # if (curr == 0) break
      81 7/subop/compare %ecx 0/imm32
      74/jump-if-= break/disp8
      # eax = lookup(curr->value)
      (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
      # if (eax == v  &&  curr->is-deref? == false) return true
      {
        39/compare *(ebp+0xc) 0/r32/eax
        75/jump-if-!= break/disp8
        81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
        75/jump-if-!= break/disp8
        b8/copy-to-eax 1/imm32/true
        eb/jump $assigns-in-stmt-vars?:end/disp8
      }
      # curr = lookup(curr->next)
      (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
      89/<- %ecx 0/r32/eax
      #
      eb/jump loop/disp8
    }
$assigns-in-stmt-vars?:end:
    # . restore registers
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# is there a var before 'v' with the same block-depth and register on the 'vars' stack?
# v is guaranteed to be within vars
# 'start' is provided as an optimization, a pointer within vars
# *start == v
same-register-spilled-before?:  # v: (addr var), vars: (addr stack (handle var)), start: (addr var) -> result/eax: boolean
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    52/push-edx
    53/push-ebx
    56/push-esi
    57/push-edi
    # ecx = v
    8b/-> *(ebp+8) 1/r32/ecx
    # var reg/edx: (addr array byte) = lookup(v->register)
    (lookup *(ecx+0x18) *(ecx+0x1c))  # Var-register Var-register => eax
    89/<- %edx 0/r32/eax
    # var depth/ebx: int = v->block-depth
    8b/-> *(ecx+0x10) 3/r32/ebx  # Var-block-depth
    # var min/ecx: (addr handle var) = vars->data
    8b/-> *(ebp+0xc) 1/r32/ecx
    81 0/subop/add %ecx 8/imm32
    # TODO: check that start >= min and start < &vars->data[top]
    # TODO: check that *start == v
    # var curr/esi: (addr handle var) = start
    8b/-> *(ebp+0x10) 6/r32/esi
    # curr -= 8
    81 5/subop/subtract %esi 8/imm32
    {
$same-register-spilled-before?:loop:
      # if (curr < min) break
      39/compare %esi 1/r32/ecx
      0f 82/jump-if-addr< break/disp32
      # var x/eax: (addr var) = lookup(*curr)
      (lookup *esi *(esi+4))  # => eax
      # if (x->block-depth < depth) break
      39/compare *(eax+0x10) 3/r32/ebx  # Var-block-depth
      0f 8c/jump-if-< break/disp32
      # if (x->register == 0) continue
      81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
      74/jump-if-= $same-register-spilled-before?:continue/disp8
      # if (x->register == reg) return true
      (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
      (string-equal? %eax %edx)  # => eax
      3d/compare-eax-and 0/imm32/false
      b8/copy-to-eax 1/imm32/true
      75/jump-if-!= $same-register-spilled-before?:end/disp8
$same-register-spilled-before?:continue:
      # curr -= 8
      81 5/subop/subtract %esi 8/imm32
      e9/jump loop/disp32
    }
$same-register-spilled-before?:false:
    b8/copy-to-eax 0/imm32/false
$same-register-spilled-before?:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# Clean up global state for 'vars' until some block depth (inclusive).
#
# This would be a simple series of pops, if it wasn't for fn outputs, which
# can occur anywhere in the stack.
# So we have to _compact_ the entire array underlying the stack.
#
# We want to allow a fn output register to be written to by locals before the
# output is set.
# So fn outputs can't just be pushed at the start of the function.
#
# We want to allow other locals to shadow a fn output register after the
# output is set.
# So the output can't just always override anything in the stack. Sequence matters.
clean-up-blocks:  # vars: (addr stack live-var), until-block-depth: int, fn: (addr function)
    # pseudocode:
    #   to = vars->top  (which points outside the stack)
    #   while true
    #     if to <= 0
    #       break
    #     var v = vars->data[to-1]
    #     if v.depth < until and !in-function-outputs?(fn, v)
    #       break
    #     --to
    #   from = to
    #   while true
    #     if from >= vars->top
    #       break
    #     assert(from >= to)
    #     v = vars->data[from]
    #     if in-function-outputs?(fn, v)
    #       if from > to
    #         vars->data[to] = vars->data[from]
    #       ++to
    #     ++from
    #   vars->top = to
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    52/push-edx
    53/push-ebx
    56/push-esi
    57/push-edi
    # ebx = vars
    8b/-> *(ebp+8) 3/r32/ebx
    # edx = until-block-depth
    8b/-> *(ebp+0xc) 2/r32/edx
$clean-up-blocks:phase1:
    # var to/edi: int = vars->top
    8b/-> *ebx 7/r32/edi
    {
$clean-up-blocks:loop1:
      # if (to <= 0) break
      81 7/subop/compare %edi 0/imm32
      7e/jump-if-<= break/disp8
      # var v/eax: (addr var) = lookup(vars->data[to-1]->var)
      8d/copy-address *(ebx+edi-4) 0/r32/eax  # vars + 8 + to - 12
      (lookup *eax *(eax+4))  # => eax
      # if (v->block-depth >= until-block-depth) continue
      39/compare *(eax+0x10) 2/r32/edx  # Var-block-depth
      {
        7d/jump-if->= break/disp8
        # if (!in-function-outputs?(fn, v)) break
        (in-function-outputs? *(ebp+0x10) %eax)  # => eax
        3d/compare-eax-and 0/imm32/false
        74/jump-if-= $clean-up-blocks:phase2/disp8
      }
$clean-up-blocks:loop1-continue:
      # --to
      81 5/subop/subtract %edi 0xc/imm32
      #
      eb/jump loop/disp8
    }
$clean-up-blocks:phase2:
    # var from/esi: int = to
    89/<- %esi 7/r32/edi
    {
$clean-up-blocks:loop2:
      # if (from >= vars->top) break
      3b/compare 6/r32/esi *ebx
      7d/jump-if->= break/disp8
      # var v/eax: (addr var) = lookup(vars->data[from]->var)
      8d/copy-address *(ebx+esi+8) 0/r32/eax
      (lookup *eax *(eax+4))  # => eax
      # if !in-function-outputs?(fn, v) continue
      (in-function-outputs? *(ebp+0x10) %eax)  # => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= $clean-up-blocks:loop2-continue/disp8
      # invariant: from >= to
      # if (from > to) vars->data[to] = vars->data[from]
      {
        39/compare %esi 7/r32/edi
        7e/jump-if-<= break/disp8
        56/push-esi
        57/push-edi
        # . var from/esi: (addr byte) = &vars->data[from]
        8d/copy-address *(ebx+esi+8) 6/r32/esi
        # . var to/edi: (addr byte) = &vars->data[to]
        8d/copy-address *(ebx+edi+8) 7/r32/edi
        # .
        8b/-> *esi 0/r32/eax
        89/<- *edi 0/r32/eax
        8b/-> *(esi+4) 0/r32/eax
        89/<- *(edi+4) 0/r32/eax
        8b/-> *(esi+8) 0/r32/eax
        89/<- *(edi+8) 0/r32/eax
        5f/pop-to-edi
        5e/pop-to-esi
      }
      # ++to
      81 0/subop/add %edi 0xc/imm32
$clean-up-blocks:loop2-continue:
      # ++from
      81 0/subop/add %esi 0xc/imm32
      #
      eb/jump loop/disp8
    }
    89/<- *ebx 7/r32/edi
$clean-up-blocks:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    5b/pop-to-ebx
    5a/pop-to-edx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

in-function-outputs?:  # fn: (addr function), target: (addr var) -> result/eax: boolean
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    # var curr/ecx: (addr list var) = lookup(fn->outputs)
    8b/-> *(ebp+8) 1/r32/ecx
    (lookup *(ecx+0x10) *(ecx+0x14))  # Function-outputs Function-outputs => eax
    89/<- %ecx 0/r32/eax
    # while curr != null
    {
      81 7/subop/compare %ecx 0/imm32
      74/jump-if-= break/disp8
      # var v/eax: (addr var) = lookup(curr->value)
      (lookup *ecx *(ecx+4))  # List-value List-value => eax
      # if (v == target) return true
      39/compare *(ebp+0xc) 0/r32/eax
      b8/copy-to-eax 1/imm32/true
      74/jump-if-= $in-function-outputs?:end/disp8
      # curr = curr->next
      (lookup *(ecx+8) *(ecx+0xc))  # List-next List-next => eax
      89/<- %ecx 0/r32/eax
      #
      eb/jump loop/disp8
    }
    b8/copy-to-eax 0/imm32
$in-function-outputs?:end:
    # . restore registers
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

emit-subx-var-def:  # out: (addr buffered-file), stmt: (addr stmt)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    # eax = stmt
    8b/-> *(ebp+0xc) 0/r32/eax
    # var v/ecx: (addr var)
    (lookup *(eax+4) *(eax+8))  # Vardef-var Vardef-var => eax
    89/<- %ecx 0/r32/eax
    # v->block-depth = *Curr-block-depth
    8b/-> *Curr-block-depth 0/r32/eax
    89/<- *(ecx+0x10) 0/r32/eax  # Var-block-depth
    # var n/edx: int = size-of(stmt->var)
    (size-of %ecx)  # => eax
    89/<- %edx 0/r32/eax
    # *Curr-local-stack-offset -= n
    29/subtract-from *Curr-local-stack-offset 2/r32/edx
    # v->offset = *Curr-local-stack-offset
    8b/-> *Curr-local-stack-offset 0/r32/eax
    89/<- *(ecx+0x14) 0/r32/eax  # Var-offset
    # if v is an array, do something special to initialize it
    {
      (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
      (is-mu-array? %eax)  # => eax
      3d/compare-eax-and 0/imm32/false
      0f 84/jump-if-= break/disp32
      # var array-size-without-size/edx: int = n-4
      81 5/subop/subtract %edx 4/imm32
      #
      (emit-array-data-initialization *(ebp+8) %edx)
      e9/jump $emit-subx-var-def:end/disp32
    }
    # another special-case for initializing streams
    # a stream is an array with 2 extra pointers
    {
      (lookup *(ecx+8) *(ecx+0xc))  # Var-type Var-type => eax
      (is-mu-stream? %eax)  # => eax
      3d/compare-eax-and 0/imm32/false
      0f 84/jump-if-= break/disp32
      # var array-size-without-size/edx: int = n-12
      81 5/subop/subtract %edx 0xc/imm32
      (emit-array-data-initialization *(ebp+8) %edx)
      # emit read and write pointers
      (emit-indent *(ebp+8) *Curr-block-depth)
      (write-buffered *(ebp+8) "68/push 0/imm32\n")
      (emit-indent *(ebp+8) *Curr-block-depth)
      (write-buffered *(ebp+8) "68/push 0/imm32\n")
      #
      eb/jump $emit-subx-var-def:end/disp8
    }
    # while n > 0
    {
      81 7/subop/compare %edx 0/imm32
      7e/jump-if-<= break/disp8
      (emit-indent *(ebp+8) *Curr-block-depth)
      (write-buffered *(ebp+8) "68/push 0/imm32\n")
      # n -= 4
      81 5/subop/subtract %edx 4/imm32
      #
      eb/jump loop/disp8
    }
$emit-subx-var-def:end:
    # . restore registers
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

emit-array-data-initialization:  # out: (addr buffered-file), n: int
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    #
    (emit-indent *(ebp+8) *Curr-block-depth)
    (write-buffered *(ebp+8) "(push-n-zero-bytes ")
    (write-int32-hex-buffered *(ebp+8) *(ebp+0xc))
    (write-buffered *(ebp+8) ")\n")
    (emit-indent *(ebp+8) *Curr-block-depth)
    (write-buffered *(ebp+8) "68/push ")
    (write-int32-hex-buffered *(ebp+8) *(ebp+0xc))
    (write-buffered *(ebp+8) "/imm32\n")
$emit-array-data-initialization:end:
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

emit-subx-stmt:  # out: (addr buffered-file), stmt: (addr stmt), primitives: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    # - some special-case primitives that don't actually use the 'primitives' data structure
    # var op/ecx: (addr array byte) = lookup(stmt->operation)
    8b/-> *(ebp+0xc) 1/r32/ecx
    (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
    89/<- %ecx 0/r32/eax
    # array size
    {
      # if (!string-equal?(stmt->operation, "length")) break
      (string-equal? %ecx "length")  # => eax
      3d/compare-eax-and 0/imm32
      0f 84/jump-if-= break/disp32
      (translate-mu-length-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
      e9/jump $emit-subx-stmt:end/disp32
    }
    # index into array
    {
      # if (!string-equal?(stmt->operation, "index")) break
      (string-equal? %ecx "index")  # => eax
      3d/compare-eax-and 0/imm32
      0f 84/jump-if-= break/disp32
      (translate-mu-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
      e9/jump $emit-subx-stmt:end/disp32
    }
    # compute-offset for index into array
    {
      # if (!string-equal?(stmt->operation, "compute-offset")) break
      (string-equal? %ecx "compute-offset")  # => eax
      3d/compare-eax-and 0/imm32
      0f 84/jump-if-= break/disp32
      (translate-mu-compute-index-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
      e9/jump $emit-subx-stmt:end/disp32
    }
    # get field from record
    {
      # if (!string-equal?(stmt->operation, "get")) break
      (string-equal? %ecx "get")  # => eax
      3d/compare-eax-and 0/imm32
      0f 84/jump-if-= break/disp32
      (translate-mu-get-stmt *(ebp+8) *(ebp+0xc))
      e9/jump $emit-subx-stmt:end/disp32
    }
    # allocate scalar
    {
      # if (!string-equal?(stmt->operation, "allocate")) break
      (string-equal? %ecx "allocate")  # => eax
      3d/compare-eax-and 0/imm32
      0f 84/jump-if-= break/disp32
      (translate-mu-allocate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
      e9/jump $emit-subx-stmt:end/disp32
    }
    # copy-object
    {
      # if (!string-equal?(stmt->operation, "copy-object")) break
      (string-equal? %ecx "copy-object")  # => eax
      3d/compare-eax-and 0/imm32
      0f 84/jump-if-= break/disp32
      (translate-mu-copy-object-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
      e9/jump $emit-subx-stmt:end/disp32
    }
    # allocate array
    {
      # if (!string-equal?(stmt->operation, "populate")) break
      (string-equal? %ecx "populate")  # => eax
      3d/compare-eax-and 0/imm32
      0f 84/jump-if-= break/disp32
      (translate-mu-populate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
      e9/jump $emit-subx-stmt:end/disp32
    }
    # allocate stream
    {
      # if (!string-equal?(stmt->operation, "populate-stream")) break
      (string-equal? %ecx "populate-stream")  # => eax
      3d/compare-eax-and 0/imm32
      0f 84/jump-if-= break/disp32
      (translate-mu-populate-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
      e9/jump $emit-subx-stmt:end/disp32
    }
    # read from stream
    {
      # if (!string-equal?(stmt->operation, "read-from-stream")) break
      (string-equal? %ecx "read-from-stream")  # => eax
      3d/compare-eax-and 0/imm32
      0f 84/jump-if-= break/disp32
      (translate-mu-read-from-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
      e9/jump $emit-subx-stmt:end/disp32
    }
    # write to stream
    {
      # if (!string-equal?(stmt->operation, "write-to-stream")) break
      (string-equal? %ecx "write-to-stream")  # => eax
      3d/compare-eax-and 0/imm32
      0f 84/jump-if-= break/disp32
      (translate-mu-write-to-stream-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))
      e9/jump $emit-subx-stmt:end/disp32
    }
    # - if stmt matches a primitive, emit it
    {
$emit-subx-stmt:check-for-primitive:
      # var curr/eax: (addr primitive)
      (find-matching-primitive *(ebp+0x10) *(ebp+0xc))  # primitives, stmt => eax
      3d/compare-eax-and 0/imm32
      74/jump-if-= break/disp8
$emit-subx-stmt:primitive:
      (emit-subx-primitive *(ebp+8) *(ebp+0xc) %eax)  # out, stmt, curr
      e9/jump $emit-subx-stmt:end/disp32
    }
    # - otherwise emit a call
    # TODO: type-checking
$emit-subx-stmt:call:
    (emit-call *(ebp+8) *(ebp+0xc))
$emit-subx-stmt:end:
    # . restore registers
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

translate-mu-length-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    56/push-esi
    # esi = stmt
    8b/-> *(ebp+0xc) 6/r32/esi
    # var base/ebx: (addr var) = stmt->inouts[0]->value
    (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    89/<- %ebx 0/r32/eax
    # var elemsize/ecx: int = array-element-size(base)
    (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
    89/<- %ecx 0/r32/eax
    # var outreg/edx: (addr array byte) = stmt->outputs[0]->value->register
    (lookup *(esi+0x14) *(esi+0x18))  # Stmt1-outputs Stmt1-outputs => eax
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
    89/<- %edx 0/r32/eax
    # if elemsize == 1
    {
      81 7/subop/compare %ecx 1/imm32
      75/jump-if-!= break/disp8
$translate-mu-length-stmt:size-1:
      (emit-save-size-to *(ebp+8) %ebx %edx)
      e9/jump $translate-mu-length-stmt:end/disp32
    }
    # if elemsize is a power of 2 less than 256
    {
      (power-of-2? %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
      81 7/subop/compare %ecx 0xff/imm32
      7f/jump-if-> break/disp8
$translate-mu-length-stmt:size-power-of-2:
      (emit-save-size-to *(ebp+8) %ebx %edx)
      (emit-divide-by-shift-right *(ebp+8) %edx %ecx)
      e9/jump $translate-mu-length-stmt:end/disp32
    }
    # otherwise, the complex case
    # . emit register spills
    {
$translate-mu-length-stmt:complex:
      (string-equal? %edx "eax")  # => eax
      3d/compare-eax-and 0/imm32/false
      75/break-if-!= break/disp8
      (emit-indent *(ebp+8) *Curr-block-depth)
      (write-buffered *(ebp+8) "50/push-eax\n")
    }
    {
      (string-equal? %edx "ecx")  # => eax
      3d/compare-eax-and 0/imm32/false
      75/break-if-!= break/disp8
      (emit-indent *(ebp+8) *Curr-block-depth)
      (write-buffered *(ebp+8) "51/push-ecx\n")
    }
    {
      (string-equal? %edx "edx")  # => eax
      3d/compare-eax-and 0/imm32/false
      75/break-if-!= break/disp8
      (emit-indent *(ebp+8) *Curr-block-depth)
      (write-buffered *(ebp+8) "52/push-edx\n")
    }
    # .
    (emit-save-size-to *(ebp+8) %ebx "eax")
    (emit-indent *(ebp+8) *Curr-block-depth)
    (write-buffered *(ebp+8) "31/xor %edx 2/r32/edx\n")
    (emit-indent *(ebp+8) *Curr-block-depth)
    (write-buffered *(ebp+8) "b9/copy-to-ecx ")
    (write-int32-hex-buffered *(ebp+8) %ecx)
    (write-buffered *(ebp+8) "/imm32\n")
    (emit-indent *(ebp+8) *Curr-block-depth)
    (write-buffered *(ebp+8) "f7 7/subop/idiv-eax-edx-by %ecx\n")
    {
      (string-equal? %edx "eax")  # => eax
      3d/compare-eax-and 0/imm32/false
      75/break-if-!= break/disp8
      (emit-indent *(ebp+8) *Curr-block-depth)
      (write-buffered *(ebp+8) "89/<- %")
      (write-buffered *(ebp+8) %edx)
      (write-buffered *(ebp+8) " 0/r32/eax\n")
    }
    # . emit register restores
    {
      (string-equal? %edx "edx")  # => eax
      3d/compare-eax-and 0/imm32/false
      75/break-if-!= break/disp8
      (emit-indent *(ebp+8) *Curr-block-depth)
      (write-buffered *(ebp+8) "5a/pop-to-edx\n")
    }
    {
      (string-equal? %edx "ecx")  # => eax
      3d/compare-eax-and 0/imm32/false
      75/break-if-!= break/disp8
      (emit-indent *(ebp+8) *Curr-block-depth)
      (write-buffered *(ebp+8) "59/pop-to-ecx\n")
    }
    {
      (string-equal? %edx "eax")  # => eax
      3d/compare-eax-and 0/imm32/false
      75/break-if-!= break/disp8
      (emit-indent *(ebp+8) *Curr-block-depth)
      (write-buffered *(ebp+8) "58/pop-to-eax\n")
    }
$translate-mu-length-stmt:end:
    # . restore registers
    5e/pop-to-esi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

array-element-size:  # arr: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    #
    (array-element-type-id *(ebp+8) *(ebp+0xc) *(ebp+0x10))  # => eax
    (size-of-type-id-as-array-element %eax)  # => eax
$array-element-size:end:
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

array-element-type-id:  # v: (addr var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: type-id
    # precondition: n is positive
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    #
    8b/-> *(ebp+8) 0/r32/eax
    # var t/eax: (addr type-tree)
    (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
    # if t == 0 abort
    3d/compare-eax-with 0/imm32
    0f 84/jump-if-== $array-element-type-id:error0/disp32
    # if t->is-atom? abort
    81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
    0f 85/jump-if-!= $array-element-type-id:error1/disp32
    # if (t->left == addr) t = t->right
    {
      50/push-eax
      (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
      (is-simple-mu-type? %eax 2)  # addr => eax
      3d/compare-eax-with 0/imm32/false
      58/pop-to-eax
      74/jump-if-= break/disp8
$array-element-type-id:skip-addr:
      (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
    }
    # if t == 0 abort
    3d/compare-eax-with 0/imm32
    0f 84/jump-if-= $array-element-type-id:error2/disp32
    # if t->is-atom? abort
    81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
    0f 85/jump-if-!= $array-element-type-id:error2/disp32
    # if t->left != array abort
    {
      50/push-eax
      (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
      (is-simple-mu-type? %eax 3)  # array => eax
      3d/compare-eax-with 0/imm32/false
      58/pop-to-eax
$array-element-type-id:no-array:
      0f 84/jump-if-= $array-element-type-id:error2/disp32
    }
$array-element-type-id:skip-array:
    # t = t->right
    (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
    # if t == 0 abort
    3d/compare-eax-with 0/imm32
    0f 84/jump-if-= $array-element-type-id:error2/disp32
    # if t->is-atom? abort
    81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
    0f 85/jump-if-!= $array-element-type-id:error2/disp32
    # return t->left->value
    (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
    8b/-> *(eax+4) 0/r32/eax  # Type-tree-value
$array-element-type-id:end:
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$array-element-type-id:error0:
    (write-buffered *(ebp+0xc) "array-element-type-id: var '")
    50/push-eax
    8b/-> *(ebp+8) 0/r32/eax
    (lookup *eax *(eax+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+0xc) %eax)
    58/pop-to-eax
    (write-buffered *(ebp+0xc) "' has no type\n")
    (flush *(ebp+0xc))
    (stop *(ebp+0x10) 1)
    # never gets here

$array-element-type-id:error1:
    (write-buffered *(ebp+0xc) "array-element-type-id: var '")
    50/push-eax
    8b/-> *(ebp+8) 0/r32/eax
    (lookup *eax *(eax+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+0xc) %eax)
    58/pop-to-eax
    (write-buffered *(ebp+0xc) "' has atomic type ")
    (write-int32-hex-buffered *(ebp+0xc) *(eax+4))  # Type-tree-value
    (write-buffered *(ebp+0xc) Newline)
    (flush *(ebp+0xc))
    (stop *(ebp+0x10) 1)
    # never gets here

$array-element-type-id:error2:
    (write-buffered *(ebp+0xc) "array-element-type-id: var '")
    50/push-eax
    8b/-> *(ebp+8) 0/r32/eax
    (lookup *eax *(eax+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+0xc) %eax)
    58/pop-to-eax
    (write-buffered *(ebp+0xc) "' has non-array type\n")
    (flush *(ebp+0xc))
    (stop *(ebp+0x10) 1)
    # never gets here

size-of-type-id-as-array-element:  # t: type-id -> result/eax: int
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # eax = t
    8b/-> *(ebp+8) 0/r32/eax
    # if t is 'byte', size is 1
    3d/compare-eax-and 8/imm32/byte
    {
      75/jump-if-!= break/disp8
      b8/copy-to-eax 1/imm32
      eb/jump $size-of-type-id-as-array-element:end/disp8
    }
    # otherwise proceed as usual
    (size-of-type-id %eax)  # => eax
$size-of-type-id-as-array-element:end:
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

emit-save-size-to:  # out: (addr buffered-file), base: (addr var), outreg: (addr array byte)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    53/push-ebx
    # ebx = base
    8b/-> *(ebp+0xc) 3/r32/ebx
    (emit-indent *(ebp+8) *Curr-block-depth)
    (write-buffered *(ebp+8) "8b/-> *")
    # if base is an (addr array ...) in a register
    {
      81 7/subop/compare *(ebx+0x18)) 0/imm32  # Var-register
      74/jump-if-= break/disp8
$emit-save-size-to:emit-base-from-register:
      (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
      (write-buffered *(ebp+8) %eax)
      eb/jump $emit-save-size-to:emit-output/disp8
    }
    # otherwise if base is an (array ...) on the stack
    {
      81 7/subop/compare *(ebx+0x14)) 0/imm32  # Var-offset
      74/jump-if-= break/disp8
$emit-save-size-to:emit-base-from-stack:
      (write-buffered *(ebp+8) "(ebp+")
      (write-int32-hex-buffered *(ebp+8) *(ebx+0x14))  # Var-offset
      (write-buffered *(ebp+8) ")")
    }
$emit-save-size-to:emit-output:
    (write-buffered *(ebp+8) " ")
    (get Mu-registers *(ebp+0x10) 0xc "Mu-registers")  # => eax
    (write-int32-hex-buffered *(ebp+8) *eax)
    (write-buffered *(ebp+8) "/r32\n")
$emit-save-size-to:end:
    # . restore registers
    5b/pop-to-ebx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

emit-divide-by-shift-right:  # out: (addr buffered-file), reg: (addr array byte), size: int
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    #
    (emit-indent *(ebp+8) *Curr-block-depth)
    (write-buffered *(ebp+8) "c1/shift 5/subop/>> %")
    (write-buffered *(ebp+8) *(ebp+0xc))
    (write-buffered *(ebp+8) Space)
    (num-shift-rights *(ebp+0x10))  # => eax
    (write-int32-hex-buffered *(ebp+8) %eax)
    (write-buffered *(ebp+8) "/imm8\n")
$emit-divide-by-shift-right:end:
    # . restore registers
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

translate-mu-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    # ecx = stmt
    8b/-> *(ebp+0xc) 1/r32/ecx
    # var base/ecx: (addr var) = stmt->inouts[0]
    (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    89/<- %ecx 0/r32/eax
    # if (var->register) do one thing
    {
      81 7/subop/compare *(ecx+0x18) 0/imm32  # Var-register
      74/jump-if-= break/disp8
      # TODO: ensure there's no dereference
      (translate-mu-index-stmt-with-array-in-register *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
      eb/jump $translate-mu-index-stmt:end/disp8
    }
    # if (var->offset) do a different thing
    {
      81 7/subop/compare *(ecx+0x14) 0/imm32  # Var-offset
      74/jump-if-= break/disp8
      # TODO: ensure there's no dereference
      (translate-mu-index-stmt-with-array-on-stack *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14))
      eb/jump $translate-mu-index-stmt:end/disp8
    }
$translate-mu-index-stmt:end:
    # . restore registers
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$translate-mu-index-stmt-with-array:error1:
    (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input must either lie in a register or be a literal\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

$translate-mu-index-stmt-with-array:error2:
    (write-buffered *(ebp+0x10) "couldn't translate an index instruction. second (index) input when in a register must be an int or offset\n")
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

translate-mu-index-stmt-with-array-in-register:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    #
    (emit-indent *(ebp+8) *Curr-block-depth)
    (write-buffered *(ebp+8) "8d/copy-address *(")
    # TODO: ensure inouts[0] is in a register and not dereferenced
$translate-mu-index-stmt-with-array-in-register:emit-base:
    # ecx = stmt
    8b/-> *(ebp+0xc) 1/r32/ecx
    # var base/ebx: (addr var) = inouts[0]
    (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    89/<- %ebx 0/r32/eax
    # print base->register " + "
    (lookup *(ebx+0x18) *(ebx+0x1c))  # Var-register Var-register => eax
    (write-buffered *(ebp+8) %eax)
    (write-buffered *(ebp+8) " + ")
    # var index/edx: (addr var) = inouts[1]
    (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    89/<- %edx 0/r32/eax
    # if index->register
    81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
    {
      0f 84/jump-if-= break/disp32
$translate-mu-index-stmt-with-array-in-register:emit-register-index:
      # if index is an int
      (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
      (is-simple-mu-type? %eax 1)  # int => eax
      3d/compare-eax-and 0/imm32/false
      {
        0f 84/jump-if-= break/disp32
$translate-mu-index-stmt-with-array-in-register:emit-int-register-index:
        # print index->register "<<" log2(array-element-size(base)) " + 4) "
        # . index->register "<<"
        (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
        (write-buffered *(ebp+8) %eax)
        (write-buffered *(ebp+8) "<<")
        # . log2(array-element-size(base->type))
        # TODO: ensure size is a power of 2
        (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
        (num-shift-rights %eax)  # => eax
        (write-int32-hex-buffered *(ebp+8) %eax)
        e9/jump $translate-mu-index-stmt-with-array-in-register:emit-register-index-done/disp32
      }
      # if index->type is any other atom, abort
      (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
      81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
      0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
      # if index has type (offset ...)
      (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
      (is-simple-mu-type? %eax 7)  # => eax
      3d/compare-eax-and 0/imm32/false
      {
        0f 84/jump-if-= break/disp32
        # print index->register
$translate-mu-index-stmt-with-array-in-register:emit-offset-register-index:
        (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
        (write-buffered *(ebp+8) %eax)
      }
$translate-mu-index-stmt-with-array-in-register:emit-register-index-done:
      (write-buffered *(ebp+8) " + 4) ")
      e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
    }
    # otherwise if index is a literal
    (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
    (is-simple-mu-type? %eax 0)  # => eax
    3d/compare-eax-and 0/imm32/false
    {
      0f 84/jump-if-= break/disp32
$translate-mu-index-stmt-with-array-in-register:emit-literal-index:
      # var index-value/edx: int = parse-hex-int(index->name)
      (lookup *edx *(edx+4))  # Var-name Var-name => eax
      (parse-hex-int %eax)  # => eax
      89/<- %edx 0/r32/eax
      # offset = idx-value * array-element-size(base->type)
      (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
      f7 4/subop/multiply-into-edx-eax %edx  # clobbers edx
      # offset += 4 for array size
      05/add-to-eax 4/imm32
      # TODO: check edx for overflow
      # print offset
      (write-int32-hex-buffered *(ebp+8) %eax)
      (write-buffered *(ebp+8) ") ")
      e9/jump $translate-mu-index-stmt-with-array-in-register:emit-output/disp32
    }
    # otherwise abort
    e9/jump $translate-mu-index-stmt-with-array:error1/disp32
$translate-mu-index-stmt-with-array-in-register:emit-output:
    # outputs[0] "/r32"
    8b/-> *(ebp+0xc) 1/r32/ecx
    (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
    (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
    (write-int32-hex-buffered *(ebp+8) *eax)
    (write-buffered *(ebp+8) "/r32\n")
$translate-mu-index-stmt-with-array-in-register:end:
    # . restore registers
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

translate-mu-index-stmt-with-array-on-stack:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    #
    (emit-indent *(ebp+8) *Curr-block-depth)
    (write-buffered *(ebp+8) "8d/copy-address *(ebp + ")
    # var curr/edx: (addr stmt-var) = lookup(stmt->inouts)
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    89/<- %edx 0/r32/eax
    # var base/ecx: (addr var) = lookup(curr->value)
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    89/<- %ecx 0/r32/eax
    # var curr2/eax: (addr stmt-var) = lookup(curr->next)
    (lookup *(edx+8) *(edx+0xc))  # Stmt-var-next Stmt-var-next => eax
    # var index/edx: (handle var) = curr2->value
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    89/<- %edx 0/r32/eax
    # if index->register
    81 7/subop/compare *(edx+0x18) 0/imm32  # Var-register
    {
      0f 84/jump-if-= break/disp32
$translate-mu-index-stmt-with-array-on-stack:emit-register-index:
      # if index is an int
      (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
      (is-simple-mu-type? %eax 1)  # int => eax
      3d/compare-eax-and 0/imm32/false
      {
        0f 84/jump-if-= break/disp32
$translate-mu-index-stmt-with-array-on-stack:emit-int-register-index:
        # print index->register "<<" log2(array-element-size(base)) " + " base->offset+4
        # . inouts[1]->register "<<"
        (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
        (write-buffered *(ebp+8) %eax)
        (write-buffered *(ebp+8) "<<")
        # . log2(array-element-size(base))
        # TODO: ensure size is a power of 2
        (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
        (num-shift-rights %eax)  # => eax
        (write-int32-hex-buffered *(ebp+8) %eax)
        #
        (write-buffered *(ebp+8) " + ")
        #
        8b/-> *(ecx+0x14) 0/r32/eax  # Var-offset
        05/add-to-eax 4/imm32  # for array length
        (write-int32-hex-buffered *(ebp+8) %eax)
        e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-register-index-done/disp32
      }
      # if index->type is any other atom, abort
      (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
      81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
      0f 85/jump-if-!= $translate-mu-index-stmt-with-array:error2/disp32
      # if index has type (offset ...)
      (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
      (is-simple-mu-type? %eax 7)  # => eax
      3d/compare-eax-and 0/imm32/false
      {
        0f 84/jump-if-= break/disp32
        # print index->register
$translate-mu-index-stmt-with-array-on-stack:emit-offset-register-index:
        (lookup *(edx+0x18) *(edx+0x1c))  # Var-register Var-register => eax
        (write-buffered *(ebp+8) %eax)
      }
$translate-mu-index-stmt-with-array-on-stack:emit-register-index-done:
      (write-buffered *(ebp+8) ") ")
      e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
    }
    # otherwise if index is a literal
    (lookup *(edx+8) *(edx+0xc))  # Var-type Var-type => eax
    (is-simple-mu-type? %eax 0)  # => eax
    3d/compare-eax-and 0/imm32/false
    {
      0f 84/jump-if-= break/disp32
$translate-mu-index-stmt-with-array-on-stack:emit-literal-index:
      # var idx-value/edx: int = parse-hex-int(index->name)
      (lookup *edx *(edx+4))  # Var-name Var-name => eax
      (parse-hex-int %eax)  # Var-name => eax
      89/<- %edx 0/r32/eax
      # offset = idx-value * array-element-size(base)
      (array-element-size %ecx *(ebp+0x10) *(ebp+0x14))  # => eax
      f7 4/subop/multiply-into-edx-eax %edx  # clobbers edx
      # offset += base->offset
      03/add *(ecx+0x14) 0/r32/eax  # Var-offset
      # offset += 4 for array size
      05/add-to-eax 4/imm32
      # TODO: check edx for overflow
      # print offset
      (write-int32-hex-buffered *(ebp+8) %eax)
      (write-buffered *(ebp+8) ") ")
      e9/jump $translate-mu-index-stmt-with-array-on-stack:emit-output/disp32
    }
    # otherwise abort
    e9/jump $translate-mu-index-stmt-with-array:error1/disp32
$translate-mu-index-stmt-with-array-on-stack:emit-output:
    # outputs[0] "/r32"
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *(eax+0x14) *(eax+0x18))  # Stmt1-outputs Stmt1-outputs => eax
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
    (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
    (write-int32-hex-buffered *(ebp+8) *eax)
    (write-buffered *(ebp+8) "/r32\n")
$translate-mu-index-stmt-with-array-on-stack:end:
    # . restore registers
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

translate-mu-compute-index-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    53/push-ebx
    #
    (emit-indent *(ebp+8) *Curr-block-depth)
    (write-buffered *(ebp+8) "69/multiply")
    # ecx = stmt
    8b/-> *(ebp+0xc) 1/r32/ecx
    # var first-inout/ebx: (addr stmt-var) = stmt->inouts[0]
    (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    89/<- %ebx 0/r32/eax
$translate-mu-compute-index-stmt:emit-index:
    (lookup *(ebx+8) *(ebx+0xc))  # Stmt-var-next Stmt-var-next => eax
    (emit-subx-var-as-rm32 *(ebp+8) %eax)
    (write-buffered *(ebp+8) Space)
$translate-mu-compute-index-stmt:emit-elem-size:
    # var base/ebx: (addr var)
    (lookup *ebx *(ebx+4))  # Stmt-var-value Stmt-var-value => eax
    89/<- %ebx 0/r32/eax
    # print array-element-size(base)
    (array-element-size %ebx *(ebp+0x10) *(ebp+0x14))  # => eax
    (write-int32-hex-buffered *(ebp+8) %eax)
    (write-buffered *(ebp+8) "/imm32 ")
$translate-mu-compute-index-stmt:emit-output:
    # outputs[0] "/r32"
    (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
    (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
    (write-int32-hex-buffered *(ebp+8) *eax)
    (write-buffered *(ebp+8) "/r32\n")
$translate-mu-compute-index-stmt:end:
    # . restore registers
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

translate-mu-get-stmt:  # out: (addr buffered-file), stmt: (addr stmt)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    52/push-edx
    #
    (emit-indent *(ebp+8) *Curr-block-depth)
    (write-buffered *(ebp+8) "8d/copy-address ")
    # ecx = stmt
    8b/-> *(ebp+0xc) 1/r32/ecx
    # var offset/edx: int = get offset of stmt
    (mu-get-offset %ecx)  # => eax
    89/<- %edx 0/r32/eax
    # var base/eax: (addr var) = stmt->inouts->value
    (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    # if base is in a register
    81 7/subop/compare *(eax+0x18) 0/imm32  # Var-register
    {
      0f 84/jump-if-= break/disp32
$translate-mu-get-stmt:emit-register-input:
      # emit "*(" base->register " + " offset ") "
      (write-buffered *(ebp+8) "*(")
      (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
      (write-buffered *(ebp+8) %eax)
      (write-buffered *(ebp+8) " + ")
      (write-int32-hex-buffered *(ebp+8) %edx)
      (write-buffered *(ebp+8) ") ")
      e9/jump $translate-mu-get-stmt:emit-output/disp32
    }
    # otherwise base is on the stack
    {
$translate-mu-get-stmt:emit-stack-input:
      # emit "*(ebp + " inouts[0]->stack-offset + offset ") "
      (write-buffered *(ebp+8) "*(ebp+")
      03/add *(eax+0x14) 2/r32/edx  # Var-offset
      (write-int32-hex-buffered *(ebp+8) %edx)
      (write-buffered *(ebp+8) ") ")
      eb/jump $translate-mu-get-stmt:emit-output/disp8
    }
$translate-mu-get-stmt:emit-output:
    # var output/eax: (addr var) = stmt->outputs->value
    (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    # emit offset->register "/r32"
    (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
    (get Mu-registers %eax 0xc "Mu-registers")  # => eax: (addr int)
    (write-int32-hex-buffered *(ebp+8) *eax)
    (write-buffered *(ebp+8) "/r32\n")
$translate-mu-get-stmt:end:
    # . restore registers
    5a/pop-to-edx
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

translate-mu-copy-object-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    #
    (emit-indent *(ebp+8) *Curr-block-depth)
    (write-buffered *(ebp+8) "(copy-bytes")
    # eax = stmt
    8b/-> *(ebp+0xc) 0/r32/eax
    # var first-inout/eax: (addr stmt-var) = stmt->inouts[0]
    (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    (emit-subx-call-operand *(ebp+8) %eax)
    (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
    (emit-subx-call-operand *(ebp+8) %eax)
    (write-buffered *(ebp+8) Space)
    (addr-payload-size %eax *(ebp+0x10) *(ebp+0x14))  # => eax
    (write-int32-hex-buffered *(ebp+8) %eax)
    (write-buffered *(ebp+8) ")\n")
$translate-mu-copy-object-stmt:end:
    # . restore registers
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

translate-mu-allocate-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    56/push-esi
    57/push-edi
    # esi = stmt
    8b/-> *(ebp+0xc) 6/r32/esi
    # var target/edi: (addr stmt-var) = stmt->inouts[0]
    (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    89/<- %edi 0/r32/eax
    #
    (emit-indent *(ebp+8) *Curr-block-depth)
    (write-buffered *(ebp+8) "(allocate Heap ")
    (addr-handle-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
    (write-int32-hex-buffered *(ebp+8) %eax)
    (emit-subx-call-operand *(ebp+8) %edi)
    (write-buffered *(ebp+8) ")\n")
$translate-mu-allocate-stmt:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

addr-handle-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # var t/eax: (addr type-tree) = s->value->type
    8b/-> *(ebp+8) 0/r32/eax
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
    # TODO: check eax != 0
    # TODO: check !t->is-atom?
    # TODO: check t->left == addr
    # t = t->right
$addr-handle-payload-size:skip-addr:
    (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
    # TODO: check eax != 0
    # TODO: check !t->is-atom?
    # TODO: check t->left == handle
    # t = t->right
$addr-handle-payload-size:skip-handle:
    (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
    # TODO: check eax != 0
    # if !t->is-atom? t = t->left
    81 7/subop/compare *eax 0/imm32/false
    {
      75/jump-if-!= break/disp8
      (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
    }
    # TODO: check t->is-atom?
    # return size(t->value)
    (size-of-type-id *(eax+4))  # Type-tree-value => eax
$addr-handle-payload-size:end:
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

addr-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # var t/eax: (addr type-tree) = s->value->type
    8b/-> *(ebp+8) 0/r32/eax
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
    # TODO: check eax != 0
    # TODO: check !t->is-atom?
    # TODO: check t->left == addr
    # t = t->right
$addr-payload-size:skip-addr:
    (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
    # TODO: check eax != 0
    # if !t->is-atom? t = t->left
    81 7/subop/compare *eax 0/imm32/false
    {
      75/jump-if-!= break/disp8
      (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
    }
    # TODO: check t->is-atom?
    # return size(t->value)
    (size-of-type-id *(eax+4))  # Type-tree-value => eax
$addr-payload-size:end:
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

translate-mu-populate-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    56/push-esi
    57/push-edi
    # esi = stmt
    8b/-> *(ebp+0xc) 6/r32/esi
    # var target/edi: (addr stmt-var) = stmt->inouts[0]
    (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    89/<- %edi 0/r32/eax
    # var len/ecx: (addr stmt-var) = stmt->inouts[1]
    (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
    89/<- %ecx 0/r32/eax
    #
    (emit-indent *(ebp+8) *Curr-block-depth)
    (write-buffered *(ebp+8) "(allocate-array2 Heap ")
    (addr-handle-array-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
    (write-int32-hex-buffered *(ebp+8) %eax)
    (emit-subx-call-operand *(ebp+8) %ecx)
    (emit-subx-call-operand *(ebp+8) %edi)
    (write-buffered *(ebp+8) ")\n")
$translate-mu-populate-stmt:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

translate-mu-populate-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    56/push-esi
    57/push-edi
    # esi = stmt
    8b/-> *(ebp+0xc) 6/r32/esi
    # var target/edi: (addr stmt-var) = stmt->inouts[0]
    (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    89/<- %edi 0/r32/eax
    # var len/ecx: (addr stmt-var) = stmt->inouts[1]
    (lookup *(edi+8) *(edi+0xc))  # Stmt-var-next Stmt-var-next => eax
    89/<- %ecx 0/r32/eax
    #
    (emit-indent *(ebp+8) *Curr-block-depth)
    (write-buffered *(ebp+8) "(new-stream Heap ")
    (addr-handle-stream-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
    (write-int32-hex-buffered *(ebp+8) %eax)
    (emit-subx-call-operand *(ebp+8) %ecx)
    (emit-subx-call-operand *(ebp+8) %edi)
    (write-buffered *(ebp+8) ")\n")
$translate-mu-populate-stream-stmt:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

translate-mu-read-from-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    56/push-esi
    57/push-edi
    # esi = stmt
    8b/-> *(ebp+0xc) 6/r32/esi
    # var stream/ecx: (addr stmt-var) = stmt->inouts[0]
    (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    89/<- %ecx 0/r32/eax
    # var target/edi: (addr stmt-var) = stmt->inouts[1]
    (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
    89/<- %edi 0/r32/eax
    #
    (emit-indent *(ebp+8) *Curr-block-depth)
    (write-buffered *(ebp+8) "(read-from-stream")
    (emit-subx-call-operand *(ebp+8) %ecx)
    (emit-subx-call-operand *(ebp+8) %edi)
    (write-buffered *(ebp+8) Space)
    (addr-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
    (write-int32-hex-buffered *(ebp+8) %eax)
    (write-buffered *(ebp+8) ")\n")
$translate-mu-read-from-stream-stmt:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

translate-mu-write-to-stream-stmt:  # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    56/push-esi
    57/push-edi
    # esi = stmt
    8b/-> *(ebp+0xc) 6/r32/esi
    # var stream/ecx: (addr stmt-var) = stmt->inouts[0]
    (lookup *(esi+0xc) *(esi+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    89/<- %ecx 0/r32/eax
    # var target/edi: (addr stmt-var) = stmt->inouts[1]
    (lookup *(ecx+8) *(ecx+0xc))  # Stmt-var-next Stmt-var-next => eax
    89/<- %edi 0/r32/eax
    #
    (emit-indent *(ebp+8) *Curr-block-depth)
    (write-buffered *(ebp+8) "(write-to-stream")
    (emit-subx-call-operand *(ebp+8) %ecx)
    (flush *(ebp+8))
    (emit-subx-call-operand *(ebp+8) %edi)
    (flush *(ebp+8))
    (write-buffered *(ebp+8) Space)
    (flush *(ebp+8))
    (addr-payload-size %edi *(ebp+0x10) *(ebp+0x14))  # => eax
    (write-int32-hex-buffered *(ebp+8) %eax)
    (write-buffered *(ebp+8) ")\n")
$translate-mu-write-to-stream-stmt:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

addr-handle-array-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # var t/eax: (addr type-tree) = s->value->type
    8b/-> *(ebp+8) 0/r32/eax
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
    # TODO: check eax != 0
    # TODO: check !t->is-atom?
    # TODO: check t->left == addr
    # t = t->right
$addr-handle-array-payload-size:skip-addr:
    (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
    # TODO: check eax != 0
    # TODO: check !t->is-atom?
    # TODO: check t->left == handle
    # t = t->right
$addr-handle-array-payload-size:skip-handle:
    (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
    # TODO: check eax != 0
    # TODO: check !t->is-atom?
    # TODO: check t->left == array
    # t = t->right
$addr-handle-array-payload-size:skip-array:
    (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
    # TODO: check eax != 0
    # if !t->is-atom? t = t->left
    81 7/subop/compare *eax 0/imm32/false
    {
      75/jump-if-!= break/disp8
      (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
    }
$addr-handle-array-payload-size:compute-size:
    # TODO: check t->is-atom?
    # return size(t->value)
    (size-of-type-id-as-array-element *(eax+4))  # Type-tree-value => eax
$addr-handle-array-payload-size:end:
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

addr-handle-stream-payload-size:  # s: (addr stmt-var), err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: int
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # var t/eax: (addr type-tree) = s->value->type
    8b/-> *(ebp+8) 0/r32/eax
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    (lookup *(eax+8) *(eax+0xc))  # Var-type Var-type => eax
    # TODO: check eax != 0
    # TODO: check !t->is-atom?
    # TODO: check t->left == addr
    # t = t->right
$addr-handle-stream-payload-size:skip-addr:
    (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
    # TODO: check eax != 0
    # TODO: check !t->is-atom?
    # TODO: check t->left == handle
    # t = t->right
$addr-handle-stream-payload-size:skip-handle:
    (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
    # TODO: check eax != 0
    # TODO: check !t->is-atom?
    # TODO: check t->left == stream
    # t = t->right
$addr-handle-stream-payload-size:skip-stream:
    (lookup *(eax+0xc) *(eax+0x10))  # Type-tree-right Type-tree-right => eax
    # TODO: check eax != 0
    # if !t->is-atom? t = t->left
    81 7/subop/compare *eax 0/imm32/false
    {
      75/jump-if-!= break/disp8
      (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
    }
$addr-handle-stream-payload-size:compute-size:
    # TODO: check t->is-atom?
    # return size(t->value)
    (size-of-type-id-as-array-element *(eax+4))  # Type-tree-value => eax
$addr-handle-stream-payload-size:end:
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

power-of-2?:  # n: int, err: (addr buffered-file), ed: (addr exit-descriptor) -> result/eax: boolean
    # precondition: n is positive
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # eax = n
    8b/-> *(ebp+8) 0/r32/eax
    # if (n < 0) abort
    3d/compare-eax-with 0/imm32
    0f 8c/jump-if-< $power-of-2?:abort/disp32
    # var tmp/eax: int = n-1
    48/decrement-eax
    # var tmp2/eax: int = n & tmp
    23/and-> *(ebp+8) 0/r32/eax
    # return (tmp2 == 0)
    3d/compare-eax-and 0/imm32
    0f 94/set-byte-if-= %al
    81 4/subop/and %eax 0xff/imm32
$power-of-2?:end:
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$power-of-2?:abort:
    (write-buffered *(ebp+0xc) "power-of-2?: negative number\n")
    (flush *(ebp+0xc))
    (stop *(ebp+0x10) 1)
    # never gets here

num-shift-rights:  # n: int -> result/eax: int
    # precondition: n is a positive power of 2
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    # var curr/ecx: int = n
    8b/-> *(ebp+8) 1/r32/ecx
    # result = 0
    b8/copy-to-eax 0/imm32
    {
      # if (curr <= 1) break
      81 7/subop/compare %ecx 1/imm32
      7e/jump-if-<= break/disp8
      40/increment-eax
      c1/shift 5/subop/arithmetic-right %ecx 1/imm8
      eb/jump loop/disp8
    }
$num-shift-rights:end:
    # . restore registers
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

mu-get-offset:  # stmt: (addr stmt) -> result/eax: int
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # var second-inout/eax: (addr stmt-var) = stmt->inouts->next
    8b/-> *(ebp+8) 0/r32/eax
    (lookup *(eax+0xc) *(eax+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
    # var output-var/eax: (addr var) = second-inout->value
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
#?     (write-buffered Stderr "mu-get-offset: ")
#?     (write-int32-hex-buffered Stderr %eax)
#?     (write-buffered Stderr " name: ")
#?     50/push-eax
#?     (lookup *eax *(eax+4))  # Var-name
#?     (write-buffered Stderr %eax)
#?     58/pop-to-eax
#?     (write-buffered Stderr Newline)
#?     (flush Stderr)
    # return output-var->stack-offset
    8b/-> *(eax+0x14) 0/r32/eax  # Var-offset
#?     (write-buffered Stderr "=> ")
#?     (write-int32-hex-buffered Stderr %eax)
#?     (write-buffered Stderr Newline)
#?     (flush Stderr)
$emit-get-offset:end:
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

emit-subx-block:  # out: (addr buffered-file), block: (addr block), vars: (addr stack live-var), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    56/push-esi
    # esi = block
    8b/-> *(ebp+0xc) 6/r32/esi
    # block->var->block-depth = *Curr-block-depth
    (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
    8b/-> *Curr-block-depth 1/r32/ecx
    89/<- *(eax+0x10) 1/r32/ecx  # Var-block-depth
    # var stmts/eax: (addr list stmt) = lookup(block->statements)
    (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
    #
    {
$emit-subx-block:check-empty:
      3d/compare-eax-and 0/imm32
      0f 84/jump-if-= break/disp32
      (emit-indent *(ebp+8) *Curr-block-depth)
      (write-buffered *(ebp+8) "{\n")
      # var v/ecx: (addr var) = lookup(block->var)
      (lookup *(esi+0xc) *(esi+0x10))  # Block-var Block-var => eax
      89/<- %ecx 0/r32/eax
      #
      (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
      (write-buffered *(ebp+8) %eax)
      (write-buffered *(ebp+8) ":loop:\n")
      ff 0/subop/increment *Curr-block-depth
      (push *(ebp+0x10) *(esi+0xc))  # Block-var
      (push *(ebp+0x10) *(esi+0x10))  # Block-var
      (push *(ebp+0x10) 0)  # false
      # emit block->statements
      (lookup *(esi+4) *(esi+8))  # Block-stmts Block-stmts => eax
      (emit-subx-stmt-list *(ebp+8) %eax *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c))
      (pop *(ebp+0x10))  # => eax
      (pop *(ebp+0x10))  # => eax
      (pop *(ebp+0x10))  # => eax
      ff 1/subop/decrement *Curr-block-depth
      (emit-indent *(ebp+8) *Curr-block-depth)
      (write-buffered *(ebp+8) "}\n")
      (lookup *ecx *(ecx+4))  # Var-name Var-name => eax
      (write-buffered *(ebp+8) %eax)
      (write-buffered *(ebp+8) ":break:\n")
    }
$emit-subx-block:end:
    # . restore registers
    5e/pop-to-esi
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# Primitives supported
# See mu_instructions for a summary of this linked-list data structure.
#
# For each operation, put variants with hard-coded registers before flexible ones.
#
# Unfortunately, our restrictions on addresses require that various fields in
# primitives be handles, which complicates these definitions.
#   - we need to insert dummy fields all over the place for fake alloc-ids
#   - we can't use our syntax sugar of quoted literals for string fields
#
# Fake alloc-ids are needed because our type definitions up top require
# handles but it's clearer to statically allocate these long-lived objects.
# Fake alloc-ids are perfectly safe, but they can't be reclaimed.
#
# Every 'object' below starts with a fake alloc-id. It may also contain other
# fake alloc-ids for various handle fields.
#
# I think of objects starting with a fake alloc-id as having type 'payload'.
# It's not really intended to be created dynamically; for that use `allocate`
# as usual.
#
# Idea for a notation to simplify such definitions:
#   _Primitive-increment-eax:  # (payload primitive)
#     0x11/alloc-id:fake:payload
#     0x11 @(0x11 "increment")  # name
#     0 0                       # inouts
#     0x11 @(0x11/payload
#            0x11 @(0x11/payload  # List-value
#                   0 0             # Var-name
#                   0x11 @(0x11     # Var-type
#                          1/is-atom
#                          1/value 0/unused   # Type-tree-left
#                          0 0                # Type-tree-right
#                         )
#                   1               # block-depth
#                   0               # stack-offset
#                   0x11 @(0x11 "eax")  # Var-register
#                  )
#            0 0)                 # List-next
#     ...
#     _Primitive-increment-ecx/imm32/next
#   ...
# Awfully complex and non-obvious. But also clearly signals there's something
# to learn here, so may be worth trying.
#
# '@' is just an initial thought. Punctuation used so far in Mu: () * % # / "
#
# For now we'll continue to just use comments and manually ensure they stay up
# to date.
== data
Primitives:  # (addr primitive)
# - increment/decrement
_Primitive-increment-eax:  # (addr primitive)
    # var/eax <- increment => 40/increment-eax
    0x11/imm32/alloc-id:fake
    _string-increment/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-eax/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_40_increment_eax/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-increment-ecx/imm32/next
_Primitive-increment-ecx:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var/ecx <- increment => 41/increment-ecx
    0x11/imm32/alloc-id:fake
    _string-increment/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-ecx/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_41_increment_ecx/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-increment-edx/imm32/next
_Primitive-increment-edx:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var/edx <- increment => 42/increment-edx
    0x11/imm32/alloc-id:fake
    _string-increment/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-edx/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_42_increment_edx/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-increment-ebx/imm32/next
_Primitive-increment-ebx:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var/ebx <- increment => 43/increment-ebx
    0x11/imm32/alloc-id:fake
    _string-increment/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-ebx/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_43_increment_ebx/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-increment-esi/imm32/next
_Primitive-increment-esi:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var/esi <- increment => 46/increment-esi
    0x11/imm32/alloc-id:fake
    _string-increment/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-esi/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_46_increment_esi/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-increment-edi/imm32/next
_Primitive-increment-edi:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var/edi <- increment => 47/increment-edi
    0x11/imm32/alloc-id:fake
    _string-increment/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-edi/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_47_increment_edi/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-decrement-eax/imm32/next
_Primitive-decrement-eax:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var/eax <- decrement => 48/decrement-eax
    0x11/imm32/alloc-id:fake
    _string-decrement/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-eax/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_48_decrement_eax/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-decrement-ecx/imm32/next
_Primitive-decrement-ecx:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var/ecx <- decrement => 49/decrement-ecx
    0x11/imm32/alloc-id:fake
    _string-decrement/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-ecx/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_49_decrement_ecx/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-decrement-edx/imm32/next
_Primitive-decrement-edx:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var/edx <- decrement => 4a/decrement-edx
    0x11/imm32/alloc-id:fake
    _string-decrement/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-edx/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_4a_decrement_edx/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-decrement-ebx/imm32/next
_Primitive-decrement-ebx:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var/ebx <- decrement => 4b/decrement-ebx
    0x11/imm32/alloc-id:fake
    _string-decrement/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-ebx/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_4b_decrement_ebx/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-decrement-esi/imm32/next
_Primitive-decrement-esi:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var/esi <- decrement => 4e/decrement-esi
    0x11/imm32/alloc-id:fake
    _string-decrement/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-esi/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_4e_decrement_esi/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-decrement-edi/imm32/next
_Primitive-decrement-edi:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var/edi <- decrement => 4f/decrement-edi
    0x11/imm32/alloc-id:fake
    _string-decrement/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-edi/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_4f_decrement_edi/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-increment-mem/imm32/next
_Primitive-increment-mem:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # increment var => ff 0/subop/increment *(ebp+__)
    0x11/imm32/alloc-id:fake
    _string-increment/imm32/name
    0x11/imm32/alloc-id:fake
    Single-int-var-in-mem/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_ff_subop_increment/imm32/subx-name
    1/imm32/rm32-is-first-inout
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-increment-reg/imm32/next
_Primitive-increment-reg:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var/reg <- increment => ff 0/subop/increment %__
    0x11/imm32/alloc-id:fake
    _string-increment/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_ff_subop_increment/imm32/subx-name
    3/imm32/rm32-is-first-output
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-decrement-mem/imm32/next
_Primitive-decrement-mem:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # decrement var => ff 1/subop/decrement *(ebp+__)
    0x11/imm32/alloc-id:fake
    _string-decrement/imm32/name
    0x11/imm32/alloc-id:fake
    Single-int-var-in-mem/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_ff_subop_decrement/imm32/subx-name
    1/imm32/rm32-is-first-inout
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-decrement-reg/imm32/next
_Primitive-decrement-reg:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var/reg <- decrement => ff 1/subop/decrement %__
    0x11/imm32/alloc-id:fake
    _string-decrement/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_ff_subop_decrement/imm32/subx-name
    3/imm32/rm32-is-first-output
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-add-to-eax/imm32/next
# - add
_Primitive-add-to-eax:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var/eax <- add lit => 05/add-to-eax lit/imm32
    0x11/imm32/alloc-id:fake
    _string-add/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-eax/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_05_add_to_eax/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    1/imm32/imm32-is-first-inout
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-add-reg-to-reg/imm32/next
_Primitive-add-reg-to-reg:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var1/reg <- add var2/reg => 01/add-to var1/rm32 var2/r32
    0x11/imm32/alloc-id:fake
    _string-add/imm32/name
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_01_add_to/imm32/subx-name
    3/imm32/rm32-is-first-output
    1/imm32/r32-is-first-inout
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-add-reg-to-mem/imm32/next
_Primitive-add-reg-to-mem:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # add-to var1 var2/reg => 01/add-to var1 var2/r32
    0x11/imm32/alloc-id:fake
    _string-add-to/imm32/name
    0x11/imm32/alloc-id:fake
    Two-args-int-stack-int-reg/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_01_add_to/imm32/subx-name
    1/imm32/rm32-is-first-inout
    2/imm32/r32-is-second-inout
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-add-mem-to-reg/imm32/next
_Primitive-add-mem-to-reg:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var1/reg <- add var2 => 03/add var2/rm32 var1/r32
    0x11/imm32/alloc-id:fake
    _string-add/imm32/name
    0x11/imm32/alloc-id:fake
    Single-int-var-in-mem/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_03_add/imm32/subx-name
    1/imm32/rm32-is-first-inout
    3/imm32/r32-is-first-output
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-add-lit-to-reg/imm32/next
_Primitive-add-lit-to-reg:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var1/reg <- add lit => 81 0/subop/add var1/rm32 lit/imm32
    0x11/imm32/alloc-id:fake
    _string-add/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_81_subop_add/imm32/subx-name
    3/imm32/rm32-is-first-output
    0/imm32/no-r32
    1/imm32/imm32-is-first-inout
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-add-lit-to-mem/imm32/next
_Primitive-add-lit-to-mem:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # add-to var1, lit => 81 0/subop/add var1/rm32 lit/imm32
    0x11/imm32/alloc-id:fake
    _string-add-to/imm32/name
    0x11/imm32/alloc-id:fake
    Int-var-and-literal/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_81_subop_add/imm32/subx-name
    1/imm32/rm32-is-first-inout
    0/imm32/no-r32
    2/imm32/imm32-is-second-inout
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-subtract-from-eax/imm32/next
# - subtract
_Primitive-subtract-from-eax:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var/eax <- subtract lit => 2d/subtract-from-eax lit/imm32
    0x11/imm32/alloc-id:fake
    _string-subtract/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-eax/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_2d_subtract_from_eax/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    1/imm32/imm32-is-first-inout
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-subtract-reg-from-reg/imm32/next
_Primitive-subtract-reg-from-reg:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var1/reg <- subtract var2/reg => 29/subtract-from var1/rm32 var2/r32
    0x11/imm32/alloc-id:fake
    _string-subtract/imm32/name
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_29_subtract_from/imm32/subx-name
    3/imm32/rm32-is-first-output
    1/imm32/r32-is-first-inout
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-subtract-reg-from-mem/imm32/next
_Primitive-subtract-reg-from-mem:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # subtract-from var1 var2/reg => 29/subtract-from var1 var2/r32
    0x11/imm32/alloc-id:fake
    _string-subtract-from/imm32/name
    0x11/imm32/alloc-id:fake
    Two-args-int-stack-int-reg/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_29_subtract_from/imm32/subx-name
    1/imm32/rm32-is-first-inout
    2/imm32/r32-is-second-inout
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-subtract-mem-from-reg/imm32/next
_Primitive-subtract-mem-from-reg:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var1/reg <- subtract var2 => 2b/subtract var2/rm32 var1/r32
    0x11/imm32/alloc-id:fake
    _string-subtract/imm32/name
    0x11/imm32/alloc-id:fake
    Single-int-var-in-mem/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_2b_subtract/imm32/subx-name
    1/imm32/rm32-is-first-inout
    3/imm32/r32-is-first-output
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-subtract-lit-from-reg/imm32/next
_Primitive-subtract-lit-from-reg:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var1/reg <- subtract lit => 81 5/subop/subtract var1/rm32 lit/imm32
    0x11/imm32/alloc-id:fake
    _string-subtract/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_81_subop_subtract/imm32/subx-name
    3/imm32/rm32-is-first-output
    0/imm32/no-r32
    1/imm32/imm32-is-first-inout
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-subtract-lit-from-mem/imm32/next
_Primitive-subtract-lit-from-mem:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # subtract-from var1, lit => 81 5/subop/subtract var1/rm32 lit/imm32
    0x11/imm32/alloc-id:fake
    _string-subtract-from/imm32/name
    0x11/imm32/alloc-id:fake
    Int-var-and-literal/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_81_subop_subtract/imm32/subx-name
    1/imm32/rm32-is-first-inout
    0/imm32/no-r32
    2/imm32/imm32-is-second-inout
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-and-with-eax/imm32/next
# - and
_Primitive-and-with-eax:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var/eax <- and lit => 25/and-with-eax lit/imm32
    0x11/imm32/alloc-id:fake
    _string-and/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-eax/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_25_and_with_eax/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    1/imm32/imm32-is-first-inout
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-and-reg-with-reg/imm32/next
_Primitive-and-reg-with-reg:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var1/reg <- and var2/reg => 21/and-with var1/rm32 var2/r32
    0x11/imm32/alloc-id:fake
    _string-and/imm32/name
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_21_and_with/imm32/subx-name
    3/imm32/rm32-is-first-output
    1/imm32/r32-is-first-inout
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-and-reg-with-mem/imm32/next
_Primitive-and-reg-with-mem:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # and-with var1 var2/reg => 21/and-with var1 var2/r32
    0x11/imm32/alloc-id:fake
    _string-and-with/imm32/name
    0x11/imm32/alloc-id:fake
    Two-args-int-stack-int-reg/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_21_and_with/imm32/subx-name
    1/imm32/rm32-is-first-inout
    2/imm32/r32-is-second-inout
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-and-mem-with-reg/imm32/next
_Primitive-and-mem-with-reg:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var1/reg <- and var2 => 23/and var2/rm32 var1/r32
    0x11/imm32/alloc-id:fake
    _string-and/imm32/name
    0x11/imm32/alloc-id:fake
    Single-int-var-in-mem/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_23_and/imm32/subx-name
    1/imm32/rm32-is-first-inout
    3/imm32/r32-is-first-output
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-and-lit-with-reg/imm32/next
_Primitive-and-lit-with-reg:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var1/reg <- and lit => 81 4/subop/and var1/rm32 lit/imm32
    0x11/imm32/alloc-id:fake
    _string-and/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_81_subop_and/imm32/subx-name
    3/imm32/rm32-is-first-output
    0/imm32/no-r32
    1/imm32/imm32-is-first-inout
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-and-lit-with-mem/imm32/next
_Primitive-and-lit-with-mem:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # and-with var1, lit => 81 4/subop/and var1/rm32 lit/imm32
    0x11/imm32/alloc-id:fake
    _string-and-with/imm32/name
    0x11/imm32/alloc-id:fake
    Int-var-and-literal/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_81_subop_and/imm32/subx-name
    1/imm32/rm32-is-first-inout
    0/imm32/no-r32
    2/imm32/imm32-is-second-inout
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-or-with-eax/imm32/next
# - or
_Primitive-or-with-eax:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var/eax <- or lit => 0d/or-with-eax lit/imm32
    0x11/imm32/alloc-id:fake
    _string-or/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-eax/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_0d_or_with_eax/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    1/imm32/imm32-is-first-inout
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-or-reg-with-reg/imm32/next
_Primitive-or-reg-with-reg:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var1/reg <- or var2/reg => 09/or-with var1/rm32 var2/r32
    0x11/imm32/alloc-id:fake
    _string-or/imm32/name
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_09_or_with/imm32/subx-name
    3/imm32/rm32-is-first-output
    1/imm32/r32-is-first-inout
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-or-reg-with-mem/imm32/next
_Primitive-or-reg-with-mem:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # or-with var1 var2/reg => 09/or-with var1 var2/r32
    0x11/imm32/alloc-id:fake
    _string-or-with/imm32/name
    0x11/imm32/alloc-id:fake
    Two-args-int-stack-int-reg/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_09_or_with/imm32/subx-name
    1/imm32/rm32-is-first-inout
    2/imm32/r32-is-second-inout
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-or-mem-with-reg/imm32/next
_Primitive-or-mem-with-reg:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var1/reg <- or var2 => 0b/or var2/rm32 var1/r32
    0x11/imm32/alloc-id:fake
    _string-or/imm32/name
    0x11/imm32/alloc-id:fake
    Single-int-var-in-mem/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_0b_or/imm32/subx-name
    1/imm32/rm32-is-first-inout
    3/imm32/r32-is-first-output
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-or-lit-with-reg/imm32/next
_Primitive-or-lit-with-reg:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var1/reg <- or lit => 81 1/subop/or var1/rm32 lit/imm32
    0x11/imm32/alloc-id:fake
    _string-or/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_81_subop_or/imm32/subx-name
    3/imm32/rm32-is-first-output
    0/imm32/no-r32
    1/imm32/imm32-is-first-inout
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-or-lit-with-mem/imm32/next
_Primitive-or-lit-with-mem:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # or-with var1, lit => 81 1/subop/or var1/rm32 lit/imm32
    0x11/imm32/alloc-id:fake
    _string-or-with/imm32/name
    0x11/imm32/alloc-id:fake
    Int-var-and-literal/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_81_subop_or/imm32/subx-name
    1/imm32/rm32-is-first-inout
    0/imm32/no-r32
    2/imm32/imm32-is-second-inout
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-xor-with-eax/imm32/next
# - xor
_Primitive-xor-with-eax:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var/eax <- xor lit => 35/xor-with-eax lit/imm32
    0x11/imm32/alloc-id:fake
    _string-xor/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-eax/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_35_xor_with_eax/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    1/imm32/imm32-is-first-inout
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-xor-reg-with-reg/imm32/next
_Primitive-xor-reg-with-reg:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var1/reg <- xor var2/reg => 31/xor-with var1/rm32 var2/r32
    0x11/imm32/alloc-id:fake
    _string-xor/imm32/name
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_31_xor_with/imm32/subx-name
    3/imm32/rm32-is-first-output
    1/imm32/r32-is-first-inout
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-xor-reg-with-mem/imm32/next
_Primitive-xor-reg-with-mem:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # xor-with var1 var2/reg => 31/xor-with var1 var2/r32
    0x11/imm32/alloc-id:fake
    _string-xor-with/imm32/name
    0x11/imm32/alloc-id:fake
    Two-args-int-stack-int-reg/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_31_xor_with/imm32/subx-name
    1/imm32/rm32-is-first-inout
    2/imm32/r32-is-second-inout
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-xor-mem-with-reg/imm32/next
_Primitive-xor-mem-with-reg:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var1/reg <- xor var2 => 33/xor var2/rm32 var1/r32
    0x11/imm32/alloc-id:fake
    _string-xor/imm32/name
    0x11/imm32/alloc-id:fake
    Single-int-var-in-mem/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_33_xor/imm32/subx-name
    1/imm32/rm32-is-first-inout
    3/imm32/r32-is-first-output
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-xor-lit-with-reg/imm32/next
_Primitive-xor-lit-with-reg:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var1/reg <- xor lit => 81 6/subop/xor var1/rm32 lit/imm32
    0x11/imm32/alloc-id:fake
    _string-xor/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_81_subop_xor/imm32/subx-name
    3/imm32/rm32-is-first-output
    0/imm32/no-r32
    1/imm32/imm32-is-first-inout
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-xor-lit-with-mem/imm32/next
_Primitive-xor-lit-with-mem:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # xor-with var1, lit => 81 6/subop/xor var1/rm32 lit/imm32
    0x11/imm32/alloc-id:fake
    _string-xor-with/imm32/name
    0x11/imm32/alloc-id:fake
    Int-var-and-literal/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_81_subop_xor/imm32/subx-name
    1/imm32/rm32-is-first-inout
    0/imm32/no-r32
    2/imm32/imm32-is-second-inout
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-shift-reg-left-by-lit/imm32/next
_Primitive-shift-reg-left-by-lit:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var1/reg <- shift-left lit => c1/shift 4/subop/left var1/rm32 lit/imm32
    0x11/imm32/alloc-id:fake
    _string-shift-left/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_c1_subop_shift_left/imm32/subx-name
    3/imm32/rm32-is-first-output
    0/imm32/no-r32
    0/imm32/no-imm32
    1/imm32/imm8-is-first-inout
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-shift-reg-right-by-lit/imm32/next
_Primitive-shift-reg-right-by-lit:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var1/reg <- shift-right lit => c1/shift 5/subop/right var1/rm32 lit/imm32
    0x11/imm32/alloc-id:fake
    _string-shift-right/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_c1_subop_shift_right_padding_zeroes/imm32/subx-name
    3/imm32/rm32-is-first-output
    0/imm32/no-r32
    0/imm32/no-imm32
    1/imm32/imm8-is-first-inout
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-shift-reg-right-signed-by-lit/imm32/next
_Primitive-shift-reg-right-signed-by-lit:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var1/reg <- shift-right-signed lit => c1/shift 7/subop/right-preserving-sign var1/rm32 lit/imm32
    0x11/imm32/alloc-id:fake
    _string-shift-right-signed/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_c1_subop_shift_right_preserving_sign/imm32/subx-name
    3/imm32/rm32-is-first-output
    0/imm32/no-r32
    0/imm32/no-imm32
    1/imm32/imm8-is-first-inout
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-shift-mem-left-by-lit/imm32/next
_Primitive-shift-mem-left-by-lit:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # shift-left var1, lit => c1/shift 4/subop/left var1/rm32 lit/imm32
    0x11/imm32/alloc-id:fake
    _string-shift-left/imm32/name
    0x11/imm32/alloc-id:fake
    Int-var-and-literal/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_c1_subop_shift_left/imm32/subx-name
    1/imm32/rm32-is-first-inout
    0/imm32/no-r32
    0/imm32/no-imm32
    2/imm32/imm8-is-second-inout
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-shift-mem-right-by-lit/imm32/next
_Primitive-shift-mem-right-by-lit:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # shift-right var1, lit => c1/shift 5/subop/right var1/rm32 lit/imm32
    0x11/imm32/alloc-id:fake
    _string-shift-right/imm32/name
    0x11/imm32/alloc-id:fake
    Int-var-and-literal/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_c1_subop_shift_right_padding_zeroes/imm32/subx-name
    1/imm32/rm32-is-first-inout
    0/imm32/no-r32
    0/imm32/no-imm32
    2/imm32/imm8-is-second-inout
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-shift-mem-right-signed-by-lit/imm32/next
_Primitive-shift-mem-right-signed-by-lit:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # shift-right-signed var1, lit => c1/shift 7/subop/right-preserving-sign var1/rm32 lit/imm32
    0x11/imm32/alloc-id:fake
    _string-shift-right-signed/imm32/name
    0x11/imm32/alloc-id:fake
    Int-var-and-literal/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_c1_subop_shift_right_preserving_sign/imm32/subx-name
    1/imm32/rm32-is-first-inout
    0/imm32/no-r32
    0/imm32/no-imm32
    2/imm32/imm8-is-second-inout
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-copy-to-eax/imm32/next
# - copy
_Primitive-copy-to-eax:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var/eax <- copy lit => b8/copy-to-eax lit/imm32
    0x11/imm32/alloc-id:fake
    _string-copy/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-eax/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_b8_copy_to_eax/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    1/imm32/imm32-is-first-inout
    0/imm32/no-imm8
    0/imm32/no-disp32
    1/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-copy-to-ecx/imm32/next
_Primitive-copy-to-ecx:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var/ecx <- copy lit => b9/copy-to-ecx lit/imm32
    0x11/imm32/alloc-id:fake
    _string-copy/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-ecx/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_b9_copy_to_ecx/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    1/imm32/imm32-is-first-inout
    0/imm32/no-imm8
    0/imm32/no-disp32
    1/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-copy-to-edx/imm32/next
_Primitive-copy-to-edx:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var/edx <- copy lit => ba/copy-to-edx lit/imm32
    0x11/imm32/alloc-id:fake
    _string-copy/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-edx/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_ba_copy_to_edx/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    1/imm32/imm32-is-first-inout
    0/imm32/no-imm8
    0/imm32/no-disp32
    1/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-copy-to-ebx/imm32/next
_Primitive-copy-to-ebx:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var/ebx <- copy lit => bb/copy-to-ebx lit/imm32
    0x11/imm32/alloc-id:fake
    _string-copy/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-ebx/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_bb_copy_to_ebx/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    1/imm32/imm32-is-first-inout
    0/imm32/no-imm8
    0/imm32/no-disp32
    1/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-copy-to-esi/imm32/next
_Primitive-copy-to-esi:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var/esi <- copy lit => be/copy-to-esi lit/imm32
    0x11/imm32/alloc-id:fake
    _string-copy/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-esi/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_be_copy_to_esi/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    1/imm32/imm32-is-first-inout
    0/imm32/no-imm8
    0/imm32/no-disp32
    1/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-copy-to-edi/imm32/next
_Primitive-copy-to-edi:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var/edi <- copy lit => bf/copy-to-edi lit/imm32
    0x11/imm32/alloc-id:fake
    _string-copy/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-edi/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_bf_copy_to_edi/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    1/imm32/imm32-is-first-inout
    0/imm32/no-imm8
    0/imm32/no-disp32
    1/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-copy-reg-to-reg/imm32/next
_Primitive-copy-reg-to-reg:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var1/reg <- copy var2/reg => 89/<- var1/rm32 var2/r32
    0x11/imm32/alloc-id:fake
    _string-copy/imm32/name
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_89_<-/imm32/subx-name
    3/imm32/rm32-is-first-output
    1/imm32/r32-is-first-inout
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    1/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-copy-reg-to-mem/imm32/next
_Primitive-copy-reg-to-mem:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # copy-to var1 var2/reg => 89/<- var1 var2/r32
    0x11/imm32/alloc-id:fake
    _string-copy-to/imm32/name
    0x11/imm32/alloc-id:fake
    Two-args-int-stack-int-reg/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_89_<-/imm32/subx-name
    1/imm32/rm32-is-first-inout
    2/imm32/r32-is-second-inout
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    1/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-copy-mem-to-reg/imm32/next
_Primitive-copy-mem-to-reg:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var1/reg <- copy var2 => 8b/-> var2/rm32 var1/r32
    0x11/imm32/alloc-id:fake
    _string-copy/imm32/name
    0x11/imm32/alloc-id:fake
    Single-int-var-in-mem/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_8b_->/imm32/subx-name
    1/imm32/rm32-is-first-inout
    3/imm32/r32-is-first-output
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    1/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-copy-lit-to-reg/imm32/next
_Primitive-copy-lit-to-reg:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var1/reg <- copy lit => c7 0/subop/copy var1/rm32 lit/imm32
    0x11/imm32/alloc-id:fake
    _string-copy/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_c7_subop_copy/imm32/subx-name
    3/imm32/rm32-is-first-output
    0/imm32/no-r32
    1/imm32/imm32-is-first-inout
    0/imm32/no-imm8
    0/imm32/no-disp32
    1/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-copy-lit-to-mem/imm32/next
_Primitive-copy-lit-to-mem:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # copy-to var1, lit => c7 0/subop/copy var1/rm32 lit/imm32
    0x11/imm32/alloc-id:fake
    _string-copy-to/imm32/name
    0x11/imm32/alloc-id:fake
    Int-var-and-literal/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_c7_subop_copy/imm32/subx-name
    1/imm32/rm32-is-first-inout
    0/imm32/no-r32
    2/imm32/imm32-is-second-inout
    0/imm32/no-imm8
    0/imm32/no-disp32
    1/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-copy-byte-from-reg/imm32/next
# - copy byte
_Primitive-copy-byte-from-reg:
    0x11/imm32/alloc-id:fake:payload
    # var/reg <- copy-byte var2/reg2 => 8a/byte-> %var2 var/r32
    0x11/imm32/alloc-id:fake
    _string-copy-byte/imm32/name
    0x11/imm32/alloc-id:fake
    Single-byte-var-in-some-register/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-byte-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_8a_copy_byte/imm32/subx-name
    1/imm32/rm32-is-first-inout
    3/imm32/r32-is-first-output
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    1/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-copy-byte-from-mem/imm32/next
_Primitive-copy-byte-from-mem:
    0x11/imm32/alloc-id:fake:payload
    # var/reg <- copy-byte *var2/reg2 => 8a/byte-> *var2 var/r32
    0x11/imm32/alloc-id:fake
    _string-copy-byte/imm32/name
    0x11/imm32/alloc-id:fake
    Single-byte-var-in-mem/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-byte-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_8a_copy_byte/imm32/subx-name
    1/imm32/rm32-is-first-inout
    3/imm32/r32-is-first-output
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    1/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-copy-byte-to-mem/imm32/next
_Primitive-copy-byte-to-mem:
    0x11/imm32/alloc-id:fake:payload
    # copy-byte-to *var1/reg1, var2/reg2 => 88/byte<- *reg1 reg2/r32
    0x11/imm32/alloc-id:fake
    _string-copy-byte-to/imm32/name
    0x11/imm32/alloc-id:fake
    Two-args-byte-stack-byte-reg/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_88_copy_byte/imm32/subx-name
    1/imm32/rm32-is-first-inout
    2/imm32/r32-is-second-inout
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-address/imm32/next
# - address
_Primitive-address:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var1/reg <- address var2 => 8d/copy-address var2/rm32 var1/r32
    0x11/imm32/alloc-id:fake
    _string-address/imm32/name
    0x11/imm32/alloc-id:fake
    Single-int-var-in-mem/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-addr-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_8d_copy_address/imm32/subx-name
    1/imm32/rm32-is-first-inout
    3/imm32/r32-is-first-output
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    1/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-compare-reg-with-reg/imm32/next
# - compare
_Primitive-compare-reg-with-reg:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # compare var1/reg1 var2/reg2 => 39/compare var1/rm32 var2/r32
    0x11/imm32/alloc-id:fake
    _string-compare/imm32/name
    0x11/imm32/alloc-id:fake
    Two-int-args-in-regs/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_39_compare->/imm32/subx-name
    1/imm32/rm32-is-first-inout
    2/imm32/r32-is-second-inout
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-compare-mem-with-reg/imm32/next
_Primitive-compare-mem-with-reg:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # compare var1 var2/reg => 39/compare var1/rm32 var2/r32
    0x11/imm32/alloc-id:fake
    _string-compare/imm32/name
    0x11/imm32/alloc-id:fake
    Two-args-int-stack-int-reg/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_39_compare->/imm32/subx-name
    1/imm32/rm32-is-first-inout
    2/imm32/r32-is-second-inout
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-compare-reg-with-mem/imm32/next
_Primitive-compare-reg-with-mem:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # compare var1/reg var2 => 3b/compare<- var2/rm32 var1/r32
    0x11/imm32/alloc-id:fake
    _string-compare/imm32/name
    0x11/imm32/alloc-id:fake
    Two-args-int-reg-int-stack/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_3b_compare<-/imm32/subx-name
    2/imm32/rm32-is-second-inout
    1/imm32/r32-is-first-inout
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-compare-eax-with-literal/imm32/next
_Primitive-compare-eax-with-literal:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # compare var1/eax n => 3d/compare-eax-with n/imm32
    0x11/imm32/alloc-id:fake
    _string-compare/imm32/name
    0x11/imm32/alloc-id:fake
    Two-args-int-eax-int-literal/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_3d_compare_eax_with/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    2/imm32/imm32-is-second-inout
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-compare-reg-with-literal/imm32/next
_Primitive-compare-reg-with-literal:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # compare var1/reg n => 81 7/subop/compare %reg n/imm32
    0x11/imm32/alloc-id:fake
    _string-compare/imm32/name
    0x11/imm32/alloc-id:fake
    Int-var-in-register-and-literal/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_81_subop_compare/imm32/subx-name
    1/imm32/rm32-is-first-inout
    0/imm32/no-r32
    2/imm32/imm32-is-second-inout
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-compare-mem-with-literal/imm32/next
_Primitive-compare-mem-with-literal:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # compare var1 n => 81 7/subop/compare *(ebp+___) n/imm32
    0x11/imm32/alloc-id:fake
    _string-compare/imm32/name
    0x11/imm32/alloc-id:fake
    Int-var-and-literal/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_81_subop_compare/imm32/subx-name
    1/imm32/rm32-is-first-inout
    0/imm32/no-r32
    2/imm32/imm32-is-second-inout
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-multiply-reg-by-reg/imm32/next
# - multiply
_Primitive-multiply-reg-by-reg:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
    0x11/imm32/alloc-id:fake
    _string-multiply/imm32/name
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_0f_af_multiply/imm32/subx-name
    1/imm32/rm32-is-first-inout
    3/imm32/r32-is-first-output
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-multiply-reg-by-mem/imm32/next
_Primitive-multiply-reg-by-mem:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    # var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
    0x11/imm32/alloc-id:fake
    _string-multiply/imm32/name
    0x11/imm32/alloc-id:fake
    Single-int-var-in-mem/imm32/inouts
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/outputs
    0x11/imm32/alloc-id:fake
    _string_0f_af_multiply/imm32/subx-name
    1/imm32/rm32-is-first-inout
    3/imm32/r32-is-first-output
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/output-is-write-only
    0x11/imm32/alloc-id:fake
    _Primitive-break-if-addr</imm32/next
# - branches
_Primitive-break-if-addr<:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-break-if-addr</imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_82_jump_break/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-break-if-addr>=/imm32/next
_Primitive-break-if-addr>=:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-break-if-addr>=/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_83_jump_break/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-break-if-=/imm32/next
_Primitive-break-if-=:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-break-if-=/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_84_jump_break/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-break-if-!=/imm32/next
_Primitive-break-if-!=:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-break-if-!=/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_85_jump_break/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-break-if-addr<=/imm32/next
_Primitive-break-if-addr<=:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-break-if-addr<=/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_86_jump_break/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-break-if-addr>/imm32/next
_Primitive-break-if-addr>:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-break-if-addr>/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_87_jump_break/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-break-if-</imm32/next
_Primitive-break-if-<:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-break-if-</imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_8c_jump_break/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-break-if->=/imm32/next
_Primitive-break-if->=:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-break-if->=/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_8d_jump_break/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-break-if-<=/imm32/next
_Primitive-break-if-<=:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-break-if-<=/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_8e_jump_break/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-break-if->/imm32/next
_Primitive-break-if->:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-break-if->/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_8f_jump_break/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-break/imm32/next
_Primitive-break:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-break/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_e9_jump_break/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-loop-if-addr</imm32/next
_Primitive-loop-if-addr<:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-loop-if-addr</imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_82_jump_loop/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-loop-if-addr>=/imm32/next
_Primitive-loop-if-addr>=:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-loop-if-addr>=/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_83_jump_loop/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-loop-if-=/imm32/next
_Primitive-loop-if-=:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-loop-if-=/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_84_jump_loop/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-loop-if-!=/imm32/next
_Primitive-loop-if-!=:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-loop-if-!=/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_85_jump_loop/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-loop-if-addr<=/imm32/next
_Primitive-loop-if-addr<=:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-loop-if-addr<=/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_86_jump_loop/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-loop-if-addr>/imm32/next
_Primitive-loop-if-addr>:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-loop-if-addr>/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_87_jump_loop/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-loop-if-</imm32/next
_Primitive-loop-if-<:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-loop-if-</imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_8c_jump_loop/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-loop-if->=/imm32/next
_Primitive-loop-if->=:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-loop-if->=/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_8d_jump_loop/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-loop-if-<=/imm32/next
_Primitive-loop-if-<=:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-loop-if-<=/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_8e_jump_loop/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-loop-if->/imm32/next
_Primitive-loop-if->:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-loop-if->/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_8f_jump_loop/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-loop/imm32/next  # we probably don't need an unconditional break
_Primitive-loop:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-loop/imm32/name
    0/imm32/no-inouts
    0/imm32/no-inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_e9_jump_loop/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    0/imm32/no-disp32
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-break-if-addr<-named/imm32/next
# - branches to named blocks
_Primitive-break-if-addr<-named:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-break-if-addr</imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_82_jump_label/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    1/imm32/disp32-is-first-inout
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-break-if-addr>=-named/imm32/next
_Primitive-break-if-addr>=-named:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-break-if-addr>=/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_83_jump_label/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    1/imm32/disp32-is-first-inout
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-break-if-=-named/imm32/next
_Primitive-break-if-=-named:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-break-if-=/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_84_jump_label/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    1/imm32/disp32-is-first-inout
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-break-if-!=-named/imm32/next
_Primitive-break-if-!=-named:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-break-if-!=/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_85_jump_label/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    1/imm32/disp32-is-first-inout
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-break-if-addr<=-named/imm32/next
_Primitive-break-if-addr<=-named:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-break-if-addr<=/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_86_jump_label/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    1/imm32/disp32-is-first-inout
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-break-if-addr>-named/imm32/next
_Primitive-break-if-addr>-named:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-break-if-addr>/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_87_jump_label/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    1/imm32/disp32-is-first-inout
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-break-if-<-named/imm32/next
_Primitive-break-if-<-named:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-break-if-</imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_8c_jump_label/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    1/imm32/disp32-is-first-inout
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-break-if->=-named/imm32/next
_Primitive-break-if->=-named:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-break-if->=/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_8d_jump_label/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    1/imm32/disp32-is-first-inout
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-break-if-<=-named/imm32/next
_Primitive-break-if-<=-named:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-break-if-<=/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_8e_jump_label/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    1/imm32/disp32-is-first-inout
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-break-if->-named/imm32/next
_Primitive-break-if->-named:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-break-if->/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_8f_jump_label/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    1/imm32/disp32-is-first-inout
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-break-named/imm32/next
_Primitive-break-named:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-break/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_e9_jump_label/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    1/imm32/disp32-is-first-inout
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-loop-if-addr<-named/imm32/next
_Primitive-loop-if-addr<-named:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-loop-if-addr</imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_82_jump_label/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    1/imm32/disp32-is-first-inout
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-loop-if-addr>=-named/imm32/next
_Primitive-loop-if-addr>=-named:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-loop-if-addr>=/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_83_jump_label/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    1/imm32/disp32-is-first-inout
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-loop-if-=-named/imm32/next
_Primitive-loop-if-=-named:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-loop-if-=/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_84_jump_label/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    1/imm32/disp32-is-first-inout
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-loop-if-!=-named/imm32/next
_Primitive-loop-if-!=-named:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-loop-if-!=/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_85_jump_label/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    1/imm32/disp32-is-first-inout
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-loop-if-addr<=-named/imm32/next
_Primitive-loop-if-addr<=-named:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-loop-if-addr<=/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_86_jump_label/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    1/imm32/disp32-is-first-inout
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-loop-if-addr>-named/imm32/next
_Primitive-loop-if-addr>-named:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-loop-if-addr>/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_87_jump_label/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    1/imm32/disp32-is-first-inout
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-loop-if-<-named/imm32/next
_Primitive-loop-if-<-named:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-loop-if-</imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_8c_jump_label/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    1/imm32/disp32-is-first-inout
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-loop-if->=-named/imm32/next
_Primitive-loop-if->=-named:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-loop-if->=/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_8d_jump_label/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    1/imm32/disp32-is-first-inout
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-loop-if-<=-named/imm32/next
_Primitive-loop-if-<=-named:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-loop-if-<=/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_8e_jump_label/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    1/imm32/disp32-is-first-inout
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-loop-if->-named/imm32/next
_Primitive-loop-if->-named:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-loop-if->/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_0f_8f_jump_label/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    1/imm32/disp32-is-first-inout
    0/imm32/no-output
    0x11/imm32/alloc-id:fake
    _Primitive-loop-named/imm32/next  # we probably don't need an unconditional break
_Primitive-loop-named:  # (payload primitive)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    _string-loop/imm32/name
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/inouts
    0/imm32/no-outputs
    0/imm32/no-outputs
    0x11/imm32/alloc-id:fake
    _string_e9_jump_label/imm32/subx-name
    0/imm32/no-rm32
    0/imm32/no-r32
    0/imm32/no-imm32
    0/imm32/no-imm8
    1/imm32/disp32-is-first-inout
    0/imm32/no-output
    0/imm32/next
    0/imm32/next

# string literals for Mu instructions
_string-add:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "add"
    0x3/imm32/size
    0x61/a 0x64/d 0x64/d
_string-address:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "address"
    0x7/imm32/size
    0x61/a 0x64/d 0x64/d 0x72/r 0x65/e 0x73/s 0x73/s
_string-add-to:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "add-to"
    0x6/imm32/size
    0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
_string-and:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "and"
    0x3/imm32/size
    0x61/a 0x6e/n 0x64/d
_string-and-with:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "and-with"
    0x8/imm32/size
    0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
_string-break:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "break"
    0x5/imm32/size
    0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k
_string-break-if-<:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "break-if-<"
    0xa/imm32/size
    0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
_string-break-if-<=:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "break-if-<="
    0xb/imm32/size
    0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
_string-break-if-=:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "break-if-="
    0xa/imm32/size
    0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
_string-break-if->:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "break-if->"
    0xa/imm32/size
    0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
_string-break-if->=:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "break-if->="
    0xb/imm32/size
    0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
_string-break-if-!=:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "break-if-!="
    0xb/imm32/size
    0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
_string-break-if-addr<:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "break-if-addr<"
    0xe/imm32/size
    0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/<
_string-break-if-addr<=:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "break-if-addr<="
    0xf/imm32/size
    0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x3d/=
_string-break-if-addr>:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "break-if-addr>"
    0xe/imm32/size
    0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/>
_string-break-if-addr>=:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "break-if-addr>="
    0xf/imm32/size
    0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x3d/=
_string-compare:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "compare"
    0x7/imm32/size
    0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e
_string-copy:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "copy"
    0x4/imm32/size
    0x63/c 0x6f/o 0x70/p 0x79/y
_string-copy-to:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "copy-to"
    0x7/imm32/size
    0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o
_string-copy-byte:
    0x11/imm32/alloc-id:fake:payload
    # "copy-byte"
    0x9/imm32/size
    0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e
_string-copy-byte-to:
    0x11/imm32/alloc-id:fake:payload
    # "copy-byte-to"
    0xc/imm32/size
    0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/- 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x74/t 0x6f/o
_string-decrement:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "decrement"
    0x9/imm32/size
    0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
_string-increment:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "increment"
    0x9/imm32/size
    0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
_string-loop:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "loop"
    0x4/imm32/size
    0x6c/l 0x6f/o 0x6f/o 0x70/p
_string-loop-if-<:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "loop-if-<"
    0x9/imm32/size
    0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
_string-loop-if-<=:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "loop-if-<="
    0xa/imm32/size
    0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
_string-loop-if-=:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "loop-if-="
    0x9/imm32/size
    0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
_string-loop-if->:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "loop-if->"
    0x9/imm32/size
    0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
_string-loop-if->=:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "loop-if->="
    0xa/imm32/size
    0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
_string-loop-if-!=:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "loop-if-!="
    0xa/imm32/size
    0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
_string-loop-if-addr<:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "loop-if-addr<"
    0xd/imm32/size
    0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/<
_string-loop-if-addr<=:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "loop-if-addr<="
    0xe/imm32/size
    0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x3d/=
_string-loop-if-addr>:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "loop-if-addr>"
    0xd/imm32/size
    0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/>
_string-loop-if-addr>=:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "loop-if-addr>="
    0xe/imm32/size
    0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x3d/=
_string-multiply:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "multiply"
    0x8/imm32/size
    0x6d/m 0x75/u 0x6c/l 0x74/t 0x69/i 0x70/p 0x6c/l 0x79/y
_string-or:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "or"
    0x2/imm32/size
    0x6f/o 0x72/r
_string-or-with:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "or-with"
    0x7/imm32/size
    0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
_string-subtract:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "subtract"
    0x8/imm32/size
    0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
_string-subtract-from:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "subtract-from"
    0xd/imm32/size
    0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t 0x2d/dash 0x66/f 0x72/r 0x6f/o 0x6d/m
_string-xor:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "xor"
    0x3/imm32/size
    0x78/x 0x6f/o 0x72/r
_string-xor-with:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "xor-with"
    0x8/imm32/size
    0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
_string-shift-left:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "shift-left"
    0xa/imm32/size
    0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x2d/dash 0x6c/l 0x65/e 0x66/f 0x74/t
_string-shift-right:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "shift-right"
    0xb/imm32/size
    0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x2d/dash 0x72/r 0x69/i 0x67/g 0x68/h 0x74/t
_string-shift-right-signed:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "shift-right-signed"
    0x12/imm32/size
    0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x2d/dash 0x72/r 0x69/i 0x67/g 0x68/h 0x74/t 0x2d/dash 0x73/s 0x69/i 0x67/g 0x6e/n 0x65/e 0x64/d

# string literals for SubX instructions
_string_01_add_to:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "01/add-to"
    0x9/imm32/size
    0x30/0 0x31/1 0x2f/slash 0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o
_string_03_add:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "03/add"
    0x6/imm32/size
    0x30/0 0x33/3 0x2f/slash 0x61/a 0x64/d 0x64/d
_string_05_add_to_eax:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "05/add-to-eax"
    0xd/imm32/size
    0x30/0 0x35/5 0x2f/slash 0x61/a 0x64/d 0x64/d 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x61/a 0x78/x
_string_09_or_with:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "09/or-with"
    0xa/imm32/size
    0x30/0 0x39/9 0x2f/slash 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
_string_0b_or:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0b/or"
    0x5/imm32/size
    0x30/0 0x62/b 0x2f/slash 0x6f/o 0x72/r
_string_0d_or_with_eax:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0d/or-with-eax"
    0xe/imm32/size
    0x30/0 0x64/d 0x2f/slash 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h 0x2d/dash 0x65/e 0x61/a 0x78/x
_string_0f_82_jump_label:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 82/jump-if-addr<"
    0x13/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x32/2 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/<
_string_0f_82_jump_break:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 82/jump-if-addr< break/disp32"
    0x20/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x32/2 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
_string_0f_82_jump_loop:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 82/jump-if-addr< loop/disp32"
    0x1f/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x32/2 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
_string_0f_83_jump_label:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 83/jump-if-addr>="
    0x14/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x33/3 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x3d/=
_string_0f_83_jump_break:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 83/jump-if-addr>= break/disp32"
    0x21/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x33/3 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x3d/= 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
_string_0f_83_jump_loop:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 83/jump-if-addr>= loop/disp32"
    0x20/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x33/3 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x3d/= 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
_string_0f_84_jump_label:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 84/jump-if-="
    0xf/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x34/4 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/=
_string_0f_84_jump_break:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 84/jump-if-= break/disp32"
    0x1c/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x34/4 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/= 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
_string_0f_84_jump_loop:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 84/jump-if-= loop/disp32"
    0x1b/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x34/4 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3d/= 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
_string_0f_85_jump_label:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 85/jump-if-!="
    0x10/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x35/5 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/=
_string_0f_85_jump_break:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 85/jump-if-!= break/disp32"
    0x1d/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x35/5 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/= 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
_string_0f_85_jump_loop:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 85/jump-if-!= loop/disp32"
    0x1c/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x35/5 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x21/! 0x3d/= 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
_string_0f_86_jump_label:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 86/jump-if-addr<="
    0x14/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x36/6 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x3d/=
_string_0f_86_jump_break:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 86/jump-if-addr<= break/disp32"
    0x21/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x36/6 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x3d/= 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
_string_0f_86_jump_loop:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 86/jump-if-addr<= loop/disp32"
    0x20/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x36/6 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3c/< 0x3d/= 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
_string_0f_87_jump_label:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 87/jump-if-addr>"
    0x13/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x37/7 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/>
_string_0f_87_jump_break:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 87/jump-if-addr> break/disp32"
    0x20/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x37/7 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
_string_0f_87_jump_loop:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 87/jump-if-addr> loop/disp32"
    0x1f/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x37/7 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x3e/> 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
_string_0f_8c_jump_label:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 8c/jump-if-<"
    0xf/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x63/c 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/<
_string_0f_8c_jump_break:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 8c/jump-if-< break/disp32"
    0x1c/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x63/c 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
_string_0f_8c_jump_loop:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 8c/jump-if-< loop/disp32"
    0x1b/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x63/c 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
_string_0f_8d_jump_label:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 8d/jump-if->="
    0x10/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x64/d 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/=
_string_0f_8d_jump_break:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 8d/jump-if->= break/disp32"
    0x1d/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x64/d 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/= 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
_string_0f_8d_jump_loop:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 8d/jump-if->= loop/disp32"
    0x1c/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x64/d 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x3d/= 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
_string_0f_8e_jump_label:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 8e/jump-if-<="
    0x10/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x65/e 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/=
_string_0f_8e_jump_break:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 8e/jump-if-<= break/disp32"
    0x1d/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x65/e 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/= 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
_string_0f_8e_jump_loop:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 8e/jump-if-<= loop/disp32"
    0x1c/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x65/e 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3c/< 0x3d/= 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
_string_0f_8f_jump_label:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 8f/jump-if->"
    0xf/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x66/f 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/>
_string_0f_8f_jump_break:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 8f/jump-if-> break/disp32"
    0x1c/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x66/f 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
_string_0f_8f_jump_loop:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f 8f/jump-if-> loop/disp32"
    0x1b/imm32/size
    0x30/0 0x66/f 0x20/space 0x38/8 0x66/f 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x2d/dash 0x69/i 0x66/f 0x2d/dash 0x3e/> 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
_string_0f_af_multiply:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "0f af/multiply"
    0xe/imm32/size
    0x30/0 0x66/f 0x20/space 0x61/a 0x66/f 0x2f/slash 0x6d/m 0x75/u 0x6c/l 0x74/t 0x69/i 0x70/p 0x6c/l 0x79/y
_string_21_and_with:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "21/and-with"
    0xb/imm32/size
    0x32/2 0x31/1 0x2f/slash 0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
_string_23_and:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "23/and"
    0x6/imm32/size
    0x32/2 0x33/3 0x2f/slash 0x61/a 0x6e/n 0x64/d
_string_25_and_with_eax:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "25/and-with-eax"
    0xf/imm32/size
    0x32/2 0x35/5 0x2f/slash 0x61/a 0x6e/n 0x64/d 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h 0x2d/dash 0x65/e 0x61/a 0x78/x
_string_29_subtract_from:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "29/subtract-from"
    0x10/imm32/size
    0x32/2 0x39/9 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t 0x2d/dash 0x66/f 0x72/r 0x6f/o 0x6d/m
_string_2b_subtract:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "2b/subtract"
    0xb/imm32/size
    0x32/2 0x62/b 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
_string_2d_subtract_from_eax:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "2d/subtract-from-eax"
    0x14/imm32/size
    0x32/2 0x64/d 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t 0x2d/dash 0x66/f 0x72/r 0x6f/o 0x6d/m 0x2d/dash 0x65/e 0x61/a 0x78/x
_string_31_xor_with:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "31/xor-with"
    0xb/imm32/size
    0x33/3 0x31/1 0x2f/slash 0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
_string_33_xor:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "33/xor"
    0x6/imm32/size
    0x33/3 0x33/3 0x2f/slash 0x78/x 0x6f/o 0x72/r
_string_35_xor_with_eax:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "35/xor-with-eax"
    0xf/imm32/size
    0x33/3 0x35/5 0x2f/slash 0x78/x 0x6f/o 0x72/r 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h 0x2d/dash 0x65/e 0x61/a 0x78/x
_string_39_compare->:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "39/compare->"
    0xc/imm32/size
    0x33/3 0x39/9 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x2d/dash 0x3e/>
_string_3b_compare<-:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "3b/compare<-"
    0xc/imm32/size
    0x33/3 0x62/b 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x3c/< 0x2d/dash
_string_3d_compare_eax_with:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "3d/compare-eax-with"
    0x13/imm32/size
    0x33/3 0x64/d 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e 0x2d/dash 0x65/e 0x61/a 0x78/x 0x2d/dash 0x77/w 0x69/i 0x74/t 0x68/h
_string_40_increment_eax:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "40/increment-eax"
    0x10/imm32/size
    0x34/4 0x30/0 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x61/a 0x78/x
_string_41_increment_ecx:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "41/increment-ecx"
    0x10/imm32/size
    0x34/4 0x31/1 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x63/c 0x78/x
_string_42_increment_edx:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "42/increment-edx"
    0x10/imm32/size
    0x34/4 0x32/2 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x64/d 0x78/x
_string_43_increment_ebx:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "43/increment-ebx"
    0x10/imm32/size
    0x34/4 0x33/3 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x62/b 0x78/x
_string_46_increment_esi:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "46/increment-esi"
    0x10/imm32/size
    0x34/4 0x36/6 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x73/s 0x69/i
_string_47_increment_edi:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "47/increment-edi"
    0x10/imm32/size
    0x34/4 0x37/7 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x64/d 0x69/i
_string_48_decrement_eax:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "48/decrement-eax"
    0x10/imm32/size
    0x34/4 0x38/8 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x61/a 0x78/x
_string_49_decrement_ecx:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "49/decrement-ecx"
    0x10/imm32/size
    0x34/4 0x39/9 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x63/c 0x78/x
_string_4a_decrement_edx:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "4a/decrement-edx"
    0x10/imm32/size
    0x34/4 0x61/a 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x64/d 0x78/x
_string_4b_decrement_ebx:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "4b/decrement-ebx"
    0x10/imm32/size
    0x34/4 0x62/b 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x62/b 0x78/x
_string_4e_decrement_esi:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "4e/decrement-esi"
    0x10/imm32/size
    0x34/4 0x65/e 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x73/s 0x69/i
_string_4f_decrement_edi:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "4f/decrement-edi"
    0x10/imm32/size
    0x34/4 0x66/f 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t 0x2d/dash 0x65/e 0x64/d 0x69/i
_string_81_subop_add:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "81 0/subop/add"
    0xe/imm32/size
    0x38/8 0x31/1 0x20/space 0x30/0 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x61/a 0x64/d 0x64/d
_string_81_subop_or:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "81 1/subop/or"
    0xd/imm32/size
    0x38/8 0x31/1 0x20/space 0x31/1 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x6f/o 0x72/r
_string_81_subop_and:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "81 4/subop/and"
    0xe/imm32/size
    0x38/8 0x31/1 0x20/space 0x34/4 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x61/a 0x6e/n 0x64/d
_string_81_subop_subtract:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "81 5/subop/subtract"
    0x13/imm32/size
    0x38/8 0x31/1 0x20/space 0x35/5 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x73/s 0x75/u 0x62/b 0x74/t 0x72/r 0x61/a 0x63/c 0x74/t
_string_81_subop_xor:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "81 6/subop/xor"
    0xe/imm32/size
    0x38/8 0x31/1 0x20/space 0x36/6 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x78/x 0x6f/o 0x72/r
_string_81_subop_compare:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "81 7/subop/compare"
    0x12/imm32/size
    0x38/8 0x31/1 0x20/space 0x37/7 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x63/c 0x6f/o 0x6d/m 0x70/p 0x61/a 0x72/r 0x65/e
_string_89_<-:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "89/<-"
    0x5/imm32/size
    0x38/8 0x39/9 0x2f/slash 0x3c/< 0x2d/dash
_string_8b_->:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "8b/->"
    0x5/imm32/size
    0x38/8 0x62/b 0x2f/slash 0x2d/dash 0x3e/>
_string_8a_copy_byte:
    0x11/imm32/alloc-id:fake:payload
    # "8a/byte->"
    0x9/imm32/size
    0x38/8 0x61/a 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x2d/- 0x3e/>
_string_88_copy_byte:
    0x11/imm32/alloc-id:fake:payload
    # "88/byte<-"
    0x9/imm32/size
    0x38/8 0x38/8 0x2f// 0x62/b 0x79/y 0x74/t 0x65/e 0x3c/< 0x2d/-
_string_8d_copy_address:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "8d/copy-address"
    0xf/imm32/size
    0x38/8 0x64/d 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x61/a 0x64/d 0x64/d 0x72/r 0x65/e 0x73/s 0x73/s
_string_b8_copy_to_eax:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "b8/copy-to-eax"
    0xe/imm32/size
    0x62/b 0x38/8 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x61/a 0x78/x
_string_b9_copy_to_ecx:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "b9/copy-to-ecx"
    0xe/imm32/size
    0x62/b 0x39/9 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x63/c 0x78/x
_string_ba_copy_to_edx:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "ba/copy-to-edx"
    0xe/imm32/size
    0x62/b 0x61/a 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x64/d 0x78/x
_string_bb_copy_to_ebx:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "bb/copy-to-ebx"
    0xe/imm32/size
    0x62/b 0x62/b 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x62/b 0x78/x
_string_be_copy_to_esi:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "be/copy-to-esi"
    0xe/imm32/size
    0x62/b 0x65/e 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x73/s 0x69/i
_string_bf_copy_to_edi:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "bf/copy-to-edi"
    0xe/imm32/size
    0x62/b 0x66/f 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y 0x2d/dash 0x74/t 0x6f/o 0x2d/dash 0x65/e 0x64/d 0x69/i
_string_c7_subop_copy:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "c7 0/subop/copy"
    0xf/imm32/size
    0x63/c 0x37/7 0x20/space 0x30/0 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x63/c 0x6f/o 0x70/p 0x79/y
_string_e9_jump_label:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "e9/jump"
    0x7/imm32/size
    0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p
_string_e9_jump_break:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "e9/jump break/disp32"
    0x14/imm32/size
    0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x20/space 0x62/b 0x72/r 0x65/e 0x61/a 0x6b/k 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
_string_e9_jump_loop:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "e9/jump loop/disp32"
    0x13/imm32/size
    0x65/e 0x39/9 0x2f/slash 0x6a/j 0x75/u 0x6d/m 0x70/p 0x20/space 0x6c/l 0x6f/o 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x69/i 0x73/s 0x70/p 0x33/3 0x32/2
_string_ff_subop_increment:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "ff 0/subop/increment"
    0x14/imm32/size
    0x66/f 0x66/f 0x20/space 0x30/0 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x69/i 0x6e/n 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
_string_ff_subop_decrement:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "ff 1/subop/decrement"
    0x14/imm32/size
    0x66/f 0x66/f 0x20/space 0x31/1 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x64/d 0x65/e 0x63/c 0x72/r 0x65/e 0x6d/m 0x65/e 0x6e/n 0x74/t
_string_c1_subop_shift_left:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "c1/shift 4/subop/left"
    0x15/imm32/size
    0x63/c 0x31/1 0x2f/slash 0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x20/space 0x34/4 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x6c/l 0x65/e 0x66/f 0x74/t
_string_c1_subop_shift_right_padding_zeroes:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "c1/shift 5/subop/right-padding-zeroes"
    0x25/imm32/size
    0x63/c 0x31/1 0x2f/slash 0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x20/space 0x35/5 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x72/r 0x69/i 0x67/g 0x68/h 0x74/t 0x2d/dash 0x70/p 0x61/a 0x64/d 0x64/d 0x69/i 0x6e/n 0x67/g 0x2d/dash 0x7a/z 0x65/e 0x72/r 0x6f/o 0x65/e 0x73/s
_string_c1_subop_shift_right_preserving_sign:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    # "c1/shift 7/subop/right-preserving-sign"
    0x26/imm32/size
    0x63/c 0x31/1 0x2f/slash 0x73/s 0x68/h 0x69/i 0x66/f 0x74/t 0x20/space 0x37/7 0x2f/slash 0x73/s 0x75/u 0x62/b 0x6f/o 0x70/p 0x2f/slash 0x72/r 0x69/i 0x67/g 0x68/h 0x74/t 0x2d/dash 0x70/p 0x72/r 0x65/e 0x73/s 0x65/e 0x72/r 0x76/v 0x69/i 0x6e/n 0x67/g 0x2d/dash 0x73/s 0x69/i 0x67/g 0x6e/n

Single-int-var-in-mem:  # (payload list var)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    Int-var-in-mem/imm32
    0/imm32/next
    0/imm32/next

Int-var-in-mem:  # (payload var)
    0x11/imm32/alloc-id:fake:payload
    0/imm32/name
    0/imm32/name
    0x11/imm32/alloc-id:fake
    Type-int/imm32
    1/imm32/some-block-depth
    1/imm32/some-stack-offset
    0/imm32/no-register
    0/imm32/no-register

# Not really legal, but closest we can currently represent a dereference of an (addr byte)
Single-byte-var-in-mem:  # (payload list var)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    Byte-var-in-mem/imm32
    0/imm32/next
    0/imm32/next

# Not really legal, but closest we can currently represent a dereference of an (addr byte)
Byte-var-in-mem:  # (payload var)
    0x11/imm32/alloc-id:fake:payload
    0/imm32/name
    0/imm32/name
    0x11/imm32/alloc-id:fake
    Type-byte/imm32
    1/imm32/some-block-depth
    1/imm32/some-stack-offset
    0/imm32/no-register
    0/imm32/no-register

Two-args-int-stack-int-reg:  # (payload list var)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    Int-var-in-mem/imm32
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/next

Two-int-args-in-regs:  # (payload list var)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    Int-var-in-some-register/imm32
    0x11/imm32/alloc-id:fake
    Single-int-var-in-some-register/imm32/next

# Not really legal, but closest we can currently represent a dereference of an (addr byte)
Two-args-byte-stack-byte-reg:  # (payload list var)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    Byte-var-in-mem/imm32
    0x11/imm32/alloc-id:fake
    Single-byte-var-in-some-register/imm32/next

Two-args-int-reg-int-stack:  # (payload list var)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    Int-var-in-some-register/imm32
    0x11/imm32/alloc-id:fake
    Single-int-var-in-mem/imm32/next

Two-args-int-eax-int-literal:  # (payload list var)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    Int-var-in-eax/imm32
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/next

Int-var-and-literal:  # (payload list var)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    Int-var-in-mem/imm32
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/next

Int-var-in-register-and-literal:  # (payload list var)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    Int-var-in-some-register/imm32
    0x11/imm32/alloc-id:fake
    Single-lit-var/imm32/next

Single-int-var-in-some-register:  # (payload list var)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    Int-var-in-some-register/imm32
    0/imm32/next
    0/imm32/next

Single-addr-var-in-some-register:  # (payload list var)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    Addr-var-in-some-register/imm32
    0/imm32/next
    0/imm32/next

Single-byte-var-in-some-register:  # (payload list var)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    Byte-var-in-some-register/imm32
    0/imm32/next
    0/imm32/next

Int-var-in-some-register:  # (payload var)
    0x11/imm32/alloc-id:fake:payload
    0/imm32/name
    0/imm32/name
    0x11/imm32/alloc-id:fake
    Type-int/imm32
    1/imm32/some-block-depth
    0/imm32/no-stack-offset
    0x11/imm32/alloc-id:fake
    Any-register/imm32

Any-register:  # (payload array byte)
    0x11/imm32/alloc-id:fake:payload
    1/imm32/size
    # data
    2a/asterisk

Addr-var-in-some-register:  # (payload var)
    0x11/imm32/alloc-id:fake:payload
    0/imm32/name
    0/imm32/name
    0x11/imm32/alloc-id:fake
    Type-addr/imm32
    1/imm32/some-block-depth
    0/imm32/no-stack-offset
    0x11/imm32/alloc-id:fake
    Any-register/imm32

Byte-var-in-some-register:  # (payload var)
    0x11/imm32/alloc-id:fake:payload
    0/imm32/name
    0/imm32/name
    0x11/imm32/alloc-id:fake
    Type-byte/imm32
    1/imm32/some-block-depth
    0/imm32/no-stack-offset
    0x11/imm32/alloc-id:fake
    Any-register/imm32

Single-int-var-in-eax:  # (payload list var)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    Int-var-in-eax/imm32
    0/imm32/next
    0/imm32/next

Int-var-in-eax:
    0x11/imm32/alloc-id:fake:payload
    0/imm32/name
    0/imm32/name
    0x11/imm32/alloc-id:fake
    Type-int/imm32
    1/imm32/some-block-depth
    0/imm32/no-stack-offset
    0x11/imm32/alloc-id:fake
    $Register-eax/imm32

Single-int-var-in-ecx:  # (payload list var)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    Int-var-in-ecx/imm32
    0/imm32/next
    0/imm32/next

Int-var-in-ecx:
    0x11/imm32/alloc-id:fake:payload
    0/imm32/name
    0/imm32/name
    0x11/imm32/alloc-id:fake
    Type-int/imm32
    1/imm32/some-block-depth
    0/imm32/no-stack-offset
    0x11/imm32/alloc-id:fake
    $Register-ecx/imm32/register

Single-int-var-in-edx:  # (payload list var)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    Int-var-in-edx/imm32
    0/imm32/next
    0/imm32/next

Int-var-in-edx:  # (payload list var)
    0x11/imm32/alloc-id:fake:payload
    0/imm32/name
    0/imm32/name
    0x11/imm32/alloc-id:fake
    Type-int/imm32
    1/imm32/some-block-depth
    0/imm32/no-stack-offset
    0x11/imm32/alloc-id:fake
    $Register-edx/imm32/register

Single-int-var-in-ebx:  # (payload list var)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    Int-var-in-ebx/imm32
    0/imm32/next
    0/imm32/next

Int-var-in-ebx:  # (payload list var)
    0x11/imm32/alloc-id:fake:payload
    0/imm32/name
    0/imm32/name
    0x11/imm32/alloc-id:fake
    Type-int/imm32
    1/imm32/some-block-depth
    0/imm32/no-stack-offset
    0x11/imm32/alloc-id:fake
    $Register-ebx/imm32/register

Single-int-var-in-esi:  # (payload list var)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    Int-var-in-esi/imm32
    0/imm32/next
    0/imm32/next

Int-var-in-esi:  # (payload list var)
    0x11/imm32/alloc-id:fake:payload
    0/imm32/name
    0/imm32/name
    0x11/imm32/alloc-id:fake
    Type-int/imm32
    1/imm32/some-block-depth
    0/imm32/no-stack-offset
    0x11/imm32/alloc-id:fake
    $Register-esi/imm32/register

Single-int-var-in-edi:  # (payload list var)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    Int-var-in-edi/imm32
    0/imm32/next
    0/imm32/next

Int-var-in-edi:  # (payload list var)
    0x11/imm32/alloc-id:fake:payload
    0/imm32/name
    0/imm32/name
    0x11/imm32/alloc-id:fake
    Type-int/imm32
    1/imm32/some-block-depth
    0/imm32/no-stack-offset
    0x11/imm32/alloc-id:fake
    $Register-edi/imm32/register

Single-lit-var:  # (payload list var)
    0x11/imm32/alloc-id:fake:payload
    0x11/imm32/alloc-id:fake
    Lit-var/imm32
    0/imm32/next
    0/imm32/next

Lit-var:  # (payload var)
    0x11/imm32/alloc-id:fake:payload
    0/imm32/name
    0/imm32/name
    0x11/imm32/alloc-id:fake
    Type-literal/imm32
    1/imm32/some-block-depth
    0/imm32/no-stack-offset
    0/imm32/no-register
    0/imm32/no-register

Type-int:  # (payload type-tree)
    0x11/imm32/alloc-id:fake:payload
    1/imm32/is-atom
    1/imm32/value:int
    0/imm32/left:unused
    0/imm32/right:null
    0/imm32/right:null

Type-literal:  # (payload type-tree)
    0x11/imm32/alloc-id:fake:payload
    1/imm32/is-atom
    0/imm32/value:literal
    0/imm32/left:unused
    0/imm32/right:null
    0/imm32/right:null

Type-addr:  # (payload type-tree)
    0x11/imm32/alloc-id:fake:payload
    1/imm32/is-atom
    2/imm32/value:addr
    0/imm32/left:unused
    0/imm32/right:null
    0/imm32/right:null

Type-byte:  # (payload type-tree)
    0x11/imm32/alloc-id:fake:payload
    1/imm32/is-atom
    8/imm32/value:byte
    0/imm32/left:unused
    0/imm32/right:null
    0/imm32/right:null

== code
emit-subx-primitive:  # out: (addr buffered-file), stmt: (addr stmt), primitive: (addr primitive), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    # ecx = primitive
    8b/-> *(ebp+0x10) 1/r32/ecx
    # emit primitive name
    (emit-indent *(ebp+8) *Curr-block-depth)
    (lookup *(ecx+0x18) *(ecx+0x1c))  # Primitive-subx-name Primitive-subx-name => eax
    (write-buffered *(ebp+8) %eax)
    # emit rm32 if necessary
    (emit-subx-rm32 *(ebp+8) *(ecx+0x20) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-rm32
    # emit r32 if necessary
    (emit-subx-r32 *(ebp+8) *(ecx+0x24) *(ebp+0xc))  # Primitive-subx-r32
    # emit imm32 if necessary
    (emit-subx-imm32 *(ebp+8) *(ecx+0x28) *(ebp+0xc))  # Primitive-subx-imm32
    # emit imm8 if necessary
    (emit-subx-imm8 *(ebp+8) *(ecx+0x2c) *(ebp+0xc))  # Primitive-subx-imm8
    # emit disp32 if necessary
    (emit-subx-disp32 *(ebp+8) *(ecx+0x30) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # Primitive-subx-disp32
    (write-buffered *(ebp+8) Newline)
$emit-subx-primitive:end:
    # . restore registers
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

emit-subx-rm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    # if (l == 0) return
    81 7/subop/compare *(ebp+0xc) 0/imm32
    74/jump-if-= $emit-subx-rm32:end/disp8
    # var v/eax: (addr stmt-var)
    (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
    (emit-subx-var-as-rm32 *(ebp+8) %eax)
$emit-subx-rm32:end:
    # . restore registers
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

get-stmt-operand-from-arg-location:  # stmt: (addr stmt), l: arg-location, err: (addr buffered-file), ed: (addr exit-descriptor) -> var/eax: (addr stmt-var)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    # eax = l
    8b/-> *(ebp+0xc) 0/r32/eax
    # ecx = stmt
    8b/-> *(ebp+8) 1/r32/ecx
    # if (l == 1) return stmt->inouts
    {
      3d/compare-eax-and 1/imm32
      75/jump-if-!= break/disp8
$get-stmt-operand-from-arg-location:1:
      (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
      eb/jump $get-stmt-operand-from-arg-location:end/disp8
    }
    # if (l == 2) return stmt->inouts->next
    {
      3d/compare-eax-and 2/imm32
      75/jump-if-!= break/disp8
$get-stmt-operand-from-arg-location:2:
      (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
      (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
      eb/jump $get-stmt-operand-from-arg-location:end/disp8
    }
    # if (l == 3) return stmt->outputs
    {
      3d/compare-eax-and 3/imm32
      75/jump-if-!= break/disp8
$get-stmt-operand-from-arg-location:3:
      (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
      eb/jump $get-stmt-operand-from-arg-location:end/disp8
    }
    # abort
    e9/jump $get-stmt-operand-from-arg-location:abort/disp32
$get-stmt-operand-from-arg-location:end:
    # . restore registers
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$get-stmt-operand-from-arg-location:abort:
    # error("invalid arg-location " eax)
    (write-buffered *(ebp+0x10) "invalid arg-location ")
    (write-int32-hex-buffered *(ebp+0x10) %eax)
    (write-buffered *(ebp+0x10) Newline)
    (flush *(ebp+0x10))
    (stop *(ebp+0x14) 1)
    # never gets here

emit-subx-r32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    # if (l == 0) return
    81 7/subop/compare *(ebp+0xc) 0/imm32
    0f 84/jump-if-= $emit-subx-r32:end/disp32
    # var v/eax: (addr stmt-var)
    (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    (lookup *(eax+0x18) *(eax+0x1c))  # Var-register Var-register => eax
    (maybe-get Mu-registers %eax 0xc)  # => eax: (addr register-index)
    (write-buffered *(ebp+8) Space)
    (write-int32-hex-buffered *(ebp+8) *eax)
    (write-buffered *(ebp+8) "/r32")
$emit-subx-r32:end:
    # . restore registers
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

emit-subx-imm32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    # if (l == 0) return
    81 7/subop/compare *(ebp+0xc) 0/imm32
    0f 84/jump-if-= $emit-subx-imm32:end/disp32
    # var v/eax: (handle var)
    (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    (lookup *eax *(eax+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+8) Space)
    (write-buffered *(ebp+8) %eax)
    (write-buffered *(ebp+8) "/imm32")
$emit-subx-imm32:end:
    # . restore registers
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

emit-subx-imm8:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    # if (l == 0) return
    81 7/subop/compare *(ebp+0xc) 0/imm32
    0f 84/jump-if-= $emit-subx-imm32:end/disp32
    # var v/eax: (handle var)
    (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc))  # => eax
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    (lookup *eax *(eax+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+8) Space)
    (write-buffered *(ebp+8) %eax)
    (write-buffered *(ebp+8) "/imm8")
$emit-subx-imm8:end:
    # . restore registers
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

emit-subx-disp32:  # out: (addr buffered-file), l: arg-location, stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    # if (location == 0) return
    81 7/subop/compare *(ebp+0xc) 0/imm32
    0f 84/jump-if-= $emit-subx-disp32:end/disp32
    # var v/eax: (addr stmt-var)
    (get-stmt-operand-from-arg-location *(ebp+0x10) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18))  # => eax
    (lookup *eax *(eax+4))  # Stmt-var-value Stmt-var-value => eax
    (lookup *eax *(eax+4))  # Var-name Var-name => eax
    (write-buffered *(ebp+8) Space)
    (write-buffered *(ebp+8) %eax)
    # hack: if instruction operation starts with "break", emit ":break"
    # var name/ecx: (addr array byte) = lookup(stmt->operation)
    8b/-> *(ebp+0x10) 0/r32/eax
    (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
    89/<- %ecx 0/r32/eax
    {
      (string-starts-with? %ecx "break")  # => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
      (write-buffered *(ebp+8) ":break")
    }
    # hack: if instruction operation starts with "loop", emit ":loop"
    {
      (string-starts-with? %ecx "loop")  # => eax
      3d/compare-eax-and 0/imm32/false
      74/jump-if-= break/disp8
      (write-buffered *(ebp+8) ":loop")
    }
    (write-buffered *(ebp+8) "/disp32")
$emit-subx-disp32:end:
    # . restore registers
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

emit-call:  # out: (addr buffered-file), stmt: (addr stmt)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    #
    (emit-indent *(ebp+8) *Curr-block-depth)
    (write-buffered *(ebp+8) "(")
    # ecx = stmt
    8b/-> *(ebp+0xc) 1/r32/ecx
    # - emit function name
    (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
    (write-buffered *(ebp+8) %eax)
    # - emit arguments
    # var curr/eax: (addr stmt-var) = lookup(stmt->inouts)
    (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    {
      # if (curr == null) break
      3d/compare-eax-and 0/imm32
      74/jump-if-= break/disp8
      #
      (emit-subx-call-operand *(ebp+8) %eax)
      # curr = lookup(curr->next)
      (lookup *(eax+8) *(eax+0xc))  # Stmt-var-next Stmt-var-next => eax
      eb/jump loop/disp8
    }
    #
    (write-buffered *(ebp+8) ")\n")
$emit-call:end:
    # . restore registers
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

emit-subx-call-operand:  # out: (addr buffered-file), s: (addr stmt-var)
    # shares code with emit-subx-var-as-rm32
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    56/push-esi
    # ecx = s
    8b/-> *(ebp+0xc) 1/r32/ecx
    # var operand/esi: (addr var) = lookup(s->value)
    (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
    89/<- %esi 0/r32/eax
    # if (operand->register && !s->is-deref?) emit "%__"
    {
$emit-subx-call-operand:check-for-register-direct:
      81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
      74/jump-if-= break/disp8
      81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
      75/jump-if-!= break/disp8
$emit-subx-call-operand:register-direct:
      (write-buffered *(ebp+8) " %")
      (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
      (write-buffered *(ebp+8) %eax)
      e9/jump $emit-subx-call-operand:end/disp32
    }
    # else if (operand->register && s->is-deref?) emit "*__"
    {
$emit-subx-call-operand:check-for-register-indirect:
      81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
      74/jump-if-= break/disp8
      81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
      74/jump-if-= break/disp8
$emit-subx-call-operand:register-indirect:
      (emit-subx-call-operand-register-indirect *(ebp+8) %esi)
      e9/jump $emit-subx-call-operand:end/disp32
    }
    # else if (operand->stack-offset) emit "*(ebp+__)"
    {
      81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
      74/jump-if-= break/disp8
$emit-subx-call-operand:stack:
      (emit-subx-call-operand-stack *(ebp+8) %esi)
      e9/jump $emit-subx-call-operand:end/disp32
    }
    # else if (operand->type == literal) emit "__"
    {
      (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
      81 7/subop/compare *(eax+4) 0/imm32  # Type-tree-left
      75/jump-if-!= break/disp8
$emit-subx-call-operand:literal:
      (write-buffered *(ebp+8) Space)
      (lookup *esi *(esi+4))  # Var-name Var-name => eax
      (write-buffered *(ebp+8) %eax)
    }
$emit-subx-call-operand:end:
    # . restore registers
    5e/pop-to-esi
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

emit-subx-call-operand-register-indirect:  # out: (addr buffered-file), v: (addr var)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    56/push-esi
    # esi = v
    8b/-> *(ebp+0xc) 6/r32/esi
    # var size/ecx: int = size-of-deref(v)
    (size-of-deref %esi)  # => eax
    89/<- %ecx 0/r32/eax
    # var reg-name/esi: (addr array byte) = lookup(v->register)
    (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
    89/<- %esi 0/r32/eax
    # TODO: assert size is a multiple of 4
    # var i/eax: int = 0
    b8/copy-to-eax 0/imm32
    {
$emit-subx-call-operand-register-indirect:loop:
      # if (i >= size) break
      39/compare %eax 1/r32/ecx
      7d/jump-if->= break/disp8
      # emit " *(" v->register "+" i ")"
      (write-buffered *(ebp+8) " *(")
      (write-buffered *(ebp+8) %esi)
      (write-buffered *(ebp+8) "+")
      (write-int32-hex-buffered *(ebp+8) %eax)
      (write-buffered *(ebp+8) ")")
      # i += 4
      05/add-to-eax 4/imm32
      #
      eb/jump loop/disp8
    }
$emit-subx-call-operand-register-indirect:end:
    # . restore registers
    5e/pop-to-esi
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

emit-subx-call-operand-stack:  # out: (addr buffered-file), v: (addr var)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    56/push-esi
    # esi = v
    8b/-> *(ebp+0xc) 6/r32/esi
    # var curr/ecx: int = v->offset
    8b/-> *(esi+0x14) 1/r32/ecx  # Var-offset
    # var max/eax: int = v->offset + size-of(v)
    (size-of %esi)  # => eax
    # TODO: assert size is a multiple of 4
    01/add-to %eax 1/r32/ecx
    {
$emit-subx-call-operand-stack:loop:
      # if (curr >= max) break
      39/compare %ecx 0/r32/eax
      7d/jump-if->= break/disp8
      # emit " *(ebp+" curr ")"
      (write-buffered *(ebp+8) " *(ebp+")
      (write-int32-hex-buffered *(ebp+8) %ecx)
      (write-buffered *(ebp+8) ")")
      # i += 4
      81 0/subop/add %ecx 4/imm32
      #
      eb/jump loop/disp8
    }
$emit-subx-call-operand-stack:end:
    # . restore registers
    5e/pop-to-esi
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

emit-subx-var-as-rm32:  # out: (addr buffered-file), s: (addr stmt-var)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    56/push-esi
    # ecx = s
    8b/-> *(ebp+0xc) 1/r32/ecx
    # var operand/esi: (addr var) = lookup(s->value)
    (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
    89/<- %esi 0/r32/eax
    # if (operand->register && s->is-deref?) emit "*__"
    {
$emit-subx-var-as-rm32:check-for-register-indirect:
      81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
      74/jump-if-= break/disp8
      81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
      74/jump-if-= break/disp8
$emit-subx-var-as-rm32:register-indirect:
      (write-buffered *(ebp+8) " *")
      (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
      (write-buffered *(ebp+8) %eax)
      e9/jump $emit-subx-var-as-rm32:end/disp32
    }
    # if (operand->register && !s->is-deref?) emit "%__"
    {
$emit-subx-var-as-rm32:check-for-register-direct:
      81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
      74/jump-if-= break/disp8
      81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
      75/jump-if-!= break/disp8
$emit-subx-var-as-rm32:register-direct:
      (write-buffered *(ebp+8) " %")
      (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
      (write-buffered *(ebp+8) %eax)
      e9/jump $emit-subx-var-as-rm32:end/disp32
    }
    # else if (operand->stack-offset) emit "*(ebp+__)"
    {
      81 7/subop/compare *(esi+0x14) 0/imm32  # Var-offset
      74/jump-if-= break/disp8
$emit-subx-var-as-rm32:stack:
      (write-buffered *(ebp+8) Space)
      (write-buffered *(ebp+8) "*(ebp+")
      (write-int32-hex-buffered *(ebp+8) *(esi+0x14))  # Var-offset
      (write-buffered *(ebp+8) ")")
    }
$emit-subx-var-as-rm32:end:
    # . restore registers
    5e/pop-to-esi
    59/pop-to-ecx
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

find-matching-primitive:  # primitives: (addr primitive), stmt: (addr stmt) -> result/eax: (addr primitive)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    # var curr/ecx: (addr primitive) = primitives
    8b/-> *(ebp+8) 1/r32/ecx
    {
$find-matching-primitive:loop:
      # if (curr == null) break
      81 7/subop/compare %ecx 0/imm32
      74/jump-if-= break/disp8
      # if match(curr, stmt) return curr
      {
        (mu-stmt-matches-primitive? *(ebp+0xc) %ecx)  # => eax
        3d/compare-eax-and 0/imm32/false
        74/jump-if-= break/disp8
        89/<- %eax 1/r32/ecx
        eb/jump $find-matching-primitive:end/disp8
      }
$find-matching-primitive:next-primitive:
      # curr = curr->next
      (lookup *(ecx+0x38) *(ecx+0x3c))  # Primitive-next Primitive-next => eax
      89/<- %ecx 0/r32/eax
      #
      e9/jump loop/disp32
    }
    # return null
    b8/copy-to-eax 0/imm32
$find-matching-primitive:end:
    # . restore registers
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

mu-stmt-matches-primitive?:  # stmt: (addr stmt), primitive: (addr primitive) -> result/eax: boolean
    # A mu stmt matches a primitive if the name matches, all the inout vars
    # match, and all the output vars match.
    # Vars match if types match and registers match.
    # In addition, a stmt output matches a primitive's output if types match
    # and the primitive has a wildcard register.
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    52/push-edx
    53/push-ebx
    56/push-esi
    57/push-edi
    # ecx = stmt
    8b/-> *(ebp+8) 1/r32/ecx
    # edx = primitive
    8b/-> *(ebp+0xc) 2/r32/edx
    {
$mu-stmt-matches-primitive?:check-name:
      # if (primitive->name != stmt->operation) return false
      # . var esi: (addr array byte) = lookup(stmt->operation)
      (lookup *(ecx+4) *(ecx+8))  # Stmt1-operation Stmt1-operation => eax
      89/<- %esi 0/r32/eax
      # . var edi: (addr array byte) = lookup(primitive->name)
      (lookup *edx *(edx+4))  # Primitive-name Primitive-name => eax
      89/<- %edi 0/r32/eax
      (string-equal? %esi %edi)  # => eax
      3d/compare-eax-and 0/imm32/false
      75/jump-if-!= break/disp8
      b8/copy-to-eax 0/imm32
      e9/jump $mu-stmt-matches-primitive?:end/disp32
    }
    # var curr/esi: (addr stmt-var) = lookup(stmt->inouts)
    (lookup *(ecx+0xc) *(ecx+0x10))  # Stmt1-inouts Stmt1-inouts => eax
    89/<- %esi 0/r32/eax
    # var curr2/edi: (addr list var) = lookup(primitive->inouts)
    (lookup *(edx+8) *(edx+0xc))  # Primitive-inouts Primitive-inouts => eax
    89/<- %edi 0/r32/eax
    {
$mu-stmt-matches-primitive?:inouts-loop:
      # if (curr == 0 && curr2 == 0) move on to check outputs
      {
$mu-stmt-matches-primitive?:check-both-inouts-null:
        81 7/subop/compare %esi 0/imm32
        75/jump-if-!= break/disp8
$mu-stmt-matches-primitive?:stmt-inout-null:
        81 7/subop/compare %edi 0/imm32
        0f 84/jump-if-= $mu-stmt-matches-primitive?:check-outputs/disp32
$mu-stmt-matches-primitive?:stmt-inout-null-and-prim-inout-not-null:
        # return false
        b8/copy-to-eax 0/imm32/false
        e9/jump $mu-stmt-matches-primitive?:end/disp32
      }
      # if (curr2 == 0) return false
      {
$mu-stmt-matches-primitive?:check-prim-inout-null:
        81 7/subop/compare %edi 0/imm32
        75/jump-if-!= break/disp8
$mu-stmt-matches-primitive?:prim-inout-null:
        b8/copy-to-eax 0/imm32/false
        e9/jump $mu-stmt-matches-primitive?:end/disp32
      }
      # if (curr != curr2) return false
      {
$mu-stmt-matches-primitive?:check-inouts-match:
        (lookup *edi *(edi+4))  # List-value List-value => eax
        (operand-matches-primitive? %esi %eax)  # => eax
        3d/compare-eax-and 0/imm32/false
        75/jump-if-!= break/disp8
$mu-stmt-matches-primitive?:inouts-match:
        b8/copy-to-eax 0/imm32/false
        e9/jump $mu-stmt-matches-primitive?:end/disp32
      }
$mu-stmt-matches-primitive?:next-inout:
      # curr = lookup(curr->next)
      (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
      89/<- %esi 0/r32/eax
      # curr2 = lookup(curr2->next)
      (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
      89/<- %edi 0/r32/eax
      #
      e9/jump loop/disp32
    }
$mu-stmt-matches-primitive?:check-outputs:
    # var curr/esi: (addr stmt-var) = lookup(stmt->outputs)
    (lookup *(ecx+0x14) *(ecx+0x18))  # Stmt1-outputs Stmt1-outputs => eax
    89/<- %esi 0/r32/eax
    # var curr2/edi: (addr list var) = lookup(primitive->outputs)
    (lookup *(edx+0x10) *(edx+0x14))  # Primitive-outputs Primitive-outputs => eax
    89/<- %edi 0/r32/eax
    {
$mu-stmt-matches-primitive?:outputs-loop:
      # if (curr == 0) return (curr2 == 0)
      {
$mu-stmt-matches-primitive?:check-both-outputs-null:
        81 7/subop/compare %esi 0/imm32
        75/jump-if-!= break/disp8
        {
$mu-stmt-matches-primitive?:stmt-output-null:
          81 7/subop/compare %edi 0/imm32
          75/jump-if-!= break/disp8
$mu-stmt-matches-primitive?:both-outputs-null:
          # return true
          b8/copy-to-eax 1/imm32
          e9/jump $mu-stmt-matches-primitive?:end/disp32
        }
$mu-stmt-matches-primitive?:stmt-output-null-and-prim-output-not-null:
        # return false
        b8/copy-to-eax 0/imm32
        e9/jump $mu-stmt-matches-primitive?:end/disp32
      }
      # if (curr2 == 0) return false
      {
$mu-stmt-matches-primitive?:check-prim-output-null:
        81 7/subop/compare %edi 0/imm32
        75/jump-if-!= break/disp8
$mu-stmt-matches-primitive?:prim-output-is-null:
        b8/copy-to-eax 0/imm32
        e9/jump $mu-stmt-matches-primitive?:end/disp32
      }
      # if (curr != curr2) return false
      {
$mu-stmt-matches-primitive?:check-outputs-match:
        (lookup *edi *(edi+4))  # List-value List-value => eax
        (operand-matches-primitive? %esi %eax)  # => eax
        3d/compare-eax-and 0/imm32/false
        75/jump-if-!= break/disp8
$mu-stmt-matches-primitive?:outputs-match:
        b8/copy-to-eax 0/imm32
        e9/jump $mu-stmt-matches-primitive?:end/disp32
      }
$mu-stmt-matches-primitive?:next-output:
      # curr = lookup(curr->next)
      (lookup *(esi+8) *(esi+0xc))  # Stmt-var-next Stmt-var-next => eax
      89/<- %esi 0/r32/eax
      # curr2 = lookup(curr2->next)
      (lookup *(edi+8) *(edi+0xc))  # List-next List-next => eax
      89/<- %edi 0/r32/eax
      #
      e9/jump loop/disp32
    }
$mu-stmt-matches-primitive?:return-true:
    b8/copy-to-eax 1/imm32
$mu-stmt-matches-primitive?:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

operand-matches-primitive?:  # s: (addr stmt-var), prim-var: (addr var) -> result/eax: boolean
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    52/push-edx
    53/push-ebx
    56/push-esi
    57/push-edi
    # ecx = s
    8b/-> *(ebp+8) 1/r32/ecx
    # var var/esi: (addr var) = lookup(s->value)
    (lookup *ecx *(ecx+4))  # Stmt-var-value Stmt-var-value => eax
    89/<- %esi 0/r32/eax
    # edi = prim-var
    8b/-> *(ebp+0xc) 7/r32/edi
$operand-matches-primitive?:check-type:
    # if !category-match?(var->type, prim-var->type) return false
    # . var vtype/ebx: (addr type-tree) = lookup(var->type)
    (lookup *(esi+8) *(esi+0xc))  # Var-type Var-type => eax
    89/<- %ebx 0/r32/eax
    # . var ptype/eax: (addr type-tree) = lookup(prim-var->type)
    (lookup *(edi+8) *(edi+0xc))  # Var-type Var-type => eax
    (subx-type-category-match? %ebx %eax)  # => eax
    3d/compare-eax-and 0/imm32/false
    0f 84/jump-if-= $operand-matches-primitive?:return-false/disp32
    {
$operand-matches-primitive?:check-register:
      # if prim-var is in memory and var is in register but dereference, match
      {
        81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
        0f 85/jump-if-!= break/disp32
        81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
        74/jump-if-= break/disp8
        81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
        74/jump-if-= break/disp8
$operand-matches-primitive?:var-deref-match:
        e9/jump $operand-matches-primitive?:return-true/disp32
      }
      # if prim-var is in register and var is in register but dereference, no match
      {
        81 7/subop/compare *(edi+0x18) 0/imm32  # Var-register
        0f 84/jump-if-= break/disp32
        81 7/subop/compare *(esi+0x18) 0/imm32  # Var-register
        0f 84/jump-if-= break/disp32
        81 7/subop/compare *(ecx+0x10) 0/imm32/false  # Stmt-var-is-deref
        74/jump-if-= break/disp8
$operand-matches-primitive?:var-deref-no-match:
        e9/jump $operand-matches-primitive?:return-false/disp32
      }
      # return false if var->register doesn't match prim-var->register
      {
        # if register addresses are equal, it's a match
        # var vreg/ebx: (addr array byte) = lookup(var->register)
        (lookup *(esi+0x18) *(esi+0x1c))  # Var-register Var-register => eax
        89/<- %ebx 0/r32/eax
        # var preg/ecx: (addr array byte) = lookup(prim-var->register)
        (lookup *(edi+0x18) *(edi+0x1c))  # Var-register Var-register => eax
        89/<- %ecx 0/r32/eax
        # if (vreg == preg) break
        39/compare %ecx 3/r32/ebx
        74/jump-if-= break/disp8
$operand-matches-primitive?:var-register-no-match:
        # if either address is 0, return false
        81 7/subop/compare %ebx 0/imm32
        74/jump-if-=  $operand-matches-primitive?:return-false/disp8
        81 7/subop/compare %ecx 0/imm32
        74/jump-if-=  $operand-matches-primitive?:return-false/disp8
        # if prim-var->register is wildcard, it's a match
        (string-equal? %ecx "*")  # Any-register => eax
        3d/compare-eax-and 0/imm32/false
        75/jump-if-!= break/disp8
$operand-matches-primitive?:wildcard-no-match:
        # if string contents aren't equal, return false
        (string-equal? %ecx %ebx)  # => eax
        3d/compare-eax-and 0/imm32/false
        74/jump-if-= $operand-matches-primitive?:return-false/disp8
      }
    }
$operand-matches-primitive?:return-true:
    b8/copy-to-eax 1/imm32/true
    eb/jump $operand-matches-primitive?:end/disp8
$operand-matches-primitive?:return-false:
    b8/copy-to-eax 0/imm32/false
$operand-matches-primitive?:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    5b/pop-to-ebx
    5a/pop-to-edx
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

find-matching-function:  # functions: (addr function), stmt: (addr stmt) -> result/eax: (addr function)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    # var curr/ecx: (handle function) = functions
    8b/-> *(ebp+8) 1/r32/ecx
    {
      # if (curr == null) break
      81 7/subop/compare %ecx 0/imm32
      74/jump-if-= break/disp8
#?       (write-buffered Stderr "iter\n")
#?       (flush Stderr)
      # if match(stmt, curr) return curr
      {
        (mu-stmt-matches-function? *(ebp+0xc) %ecx)  # => eax
        3d/compare-eax-and 0/imm32/false
        74/jump-if-= break/disp8
        89/<- %eax 1/r32/ecx
        eb/jump $find-matching-function:end/disp8
      }
      # curr = curr->next
      (lookup *(ecx+0x20) *(ecx+0x24))  # Function-next Function-next => eax
      89/<- %ecx 0/r32/eax
      #
      eb/jump loop/disp8
    }
    # return null
    b8/copy-to-eax 0/imm32
$find-matching-function:end:
    # . restore registers
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# Just compare names; user-defined functions don't support overloading yet.
mu-stmt-matches-function?:  # stmt: (addr stmt1), function: (addr function) -> result/eax: boolean
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    # return function->name == stmt->operation
    # ecx = lookup(stmt->operation)
    8b/-> *(ebp+8) 0/r32/eax
    (lookup *(eax+4) *(eax+8))  # Stmt1-operation Stmt1-operation => eax
    89/<- %ecx 0/r32/eax
    # eax = lookup(function->name)
    8b/-> *(ebp+0xc) 0/r32/eax
    (lookup *eax *(eax+4))  # Function-name Function-name => eax
    (string-equal? %eax %ecx)  # => eax
$mu-stmt-matches-function?:end:
    # . restore registers
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# Type-checking happens elsewhere. This method is for selecting between
# primitives.
subx-type-category-match?:  # a: (addr type-tree), b: (addr type-tree) -> result/eax: boolean
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    # var alit/ecx: boolean = is-literal-type?(a)
    (is-simple-mu-type? *(ebp+8) 0)  # => eax
    89/<- %ecx 0/r32/eax
    # var blit/eax: boolean = is-literal-type?(b)
    (is-simple-mu-type? *(ebp+0xc) 0)  # => eax
    # return alit == blit
    39/compare %eax 1/r32/ecx
    0f 94/set-byte-if-= %al
    81 4/subop/and %eax 0xff/imm32
$subx-type-category-match?:end:
    # . restore registers
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

is-simple-mu-type?:  # a: (addr type-tree), n: type-id -> result/eax: boolean
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    51/push-ecx
    # ecx = n
    8b/-> *(ebp+0xc) 1/r32/ecx
    # return (a->value == n)
    8b/-> *(ebp+8) 0/r32/eax
    39/compare *(eax+4) 1/r32/ecx  # Type-tree-value
    0f 94/set-byte-if-= %al
    81 4/subop/and %eax 0xff/imm32
$is-simple-mu-type?:end:
    # . restore registers
    59/pop-to-ecx
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

is-mu-addr-type?:  # a: (addr type-tree) -> result/eax: boolean
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # eax = a
    8b/-> *(ebp+8) 0/r32/eax
    # if (!a->is-atom?) a = a->left
    81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
    {
      75/jump-if-!= break/disp8
      (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
    }
    # return (a->value == addr)
    81 7/subop/compare *(eax+4) 2/imm32/addr  # Type-tree-value
    0f 94/set-byte-if-= %al
    81 4/subop/and %eax 0xff/imm32
$is-mu-addr-type?:end:
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

is-mu-array-type?:  # a: (addr type-tree) -> result/eax: boolean
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # eax = a
    8b/-> *(ebp+8) 0/r32/eax
    # if (!a->is-atom?) a = a->left
    81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
    {
      75/jump-if-!= break/disp8
      (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
    }
    # return (a->value == array)
    81 7/subop/compare *(eax+4) 3/imm32/array  # Type-tree-value
    0f 94/set-byte-if-= %al
    81 4/subop/and %eax 0xff/imm32
$is-mu-array-type?:end:
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

is-mu-stream-type?:  # a: (addr type-tree) -> result/eax: boolean
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # eax = a
    8b/-> *(ebp+8) 0/r32/eax
    # if (!a->is-atom?) a = a->left
    81 7/subop/compare *eax 0/imm32/false  # Type-tree-is-atom
    {
      75/jump-if-!= break/disp8
      (lookup *(eax+4) *(eax+8))  # Type-tree-left Type-tree-left => eax
    }
    # return (a->value == stream)
    81 7/subop/compare *(eax+4) 0xb/imm32/stream  # Type-tree-value
    0f 94/set-byte-if-= %al
    81 4/subop/and %eax 0xff/imm32
$is-mu-stream-type?:end:
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-emit-subx-stmt-primitive:
    # Primitive operation on a variable on the stack.
    #   increment foo
    # =>
    #   ff 0/subop/increment *(ebp-8)
    #
    # There's a variable on the var stack as follows:
    #   name: 'foo'
    #   type: int
    #   stack-offset: -8
    #
    # There's a primitive with this info:
    #   name: 'increment'
    #   inouts: int/mem
    #   value: 'ff 0/subop/increment'
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
    # simulate allocated payloads starting with an initial fake alloc-id (0x11)
$test-emit-subx-stmt-primitive:initialize-type:
    # var type/ecx: (payload type-tree) = int
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 1/imm32/value:int
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-emit-subx-stmt-primitive:initialize-var:
    # var var-foo/ecx: (payload var) = var(type)
    68/push 0/imm32/no-register
    68/push 0/imm32/no-register
    68/push -8/imm32/stack-offset
    68/push 1/imm32/block-depth
    51/push-ecx/type
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-emit-subx-stmt-primitive:initialize-var-name:
    # var-foo->name = "foo"
    8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "foo" %eax)
$test-emit-subx-stmt-primitive:initialize-stmt-var:
    # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
    68/push 0/imm32/is-deref:false
    68/push 0/imm32/next
    68/push 0/imm32/next
    51/push-ecx/var-foo
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ebx 4/r32/esp
$test-emit-subx-stmt-primitive:initialize-stmt:
    # var stmt/esi: (addr statement)
    68/push 0/imm32/no-outputs
    68/push 0/imm32/no-outputs
    53/push-ebx/inouts
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/operation
    68/push 0/imm32/operation
    68/push 1/imm32/tag
    89/<- %esi 4/r32/esp
$test-emit-subx-stmt-primitive:initialize-stmt-operation:
    # stmt->operation = "increment"
    8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
    (copy-array Heap "increment" %eax)
$test-emit-subx-stmt-primitive:initialize-primitive:
    # var primitives/ebx: (addr primitive)
    68/push 0/imm32/next
    68/push 0/imm32/next
    68/push 0/imm32/output-is-write-only
    68/push 0/imm32/no-disp32
    68/push 0/imm32/no-imm8
    68/push 0/imm32/no-imm32
    68/push 0/imm32/no-r32
    68/push 1/imm32/rm32-is-first-inout
    68/push 0/imm32/subx-name
    68/push 0/imm32/subx-name
    68/push 0/imm32/no-outputs
    68/push 0/imm32/no-outputs
    53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    89/<- %ebx 4/r32/esp
$test-emit-subx-stmt-primitive:initialize-primitive-name:
    # primitives->name = "increment"
    (copy-array Heap "increment" %ebx)  # Primitive-name
$test-emit-subx-stmt-primitive:initialize-primitive-subx-name:
    # primitives->subx-name = "ff 0/subop/increment"
    8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
    (copy-array Heap "ff 0/subop/increment" %eax)
    # convert
    c7 0/subop/copy *Curr-block-depth 0/imm32
    (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment *(ebp+0xfffffff8)" "F - test-emit-subx-stmt-primitive")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-emit-subx-stmt-primitive-register:
    # Primitive operation on a variable in a register.
    #   foo <- increment
    # =>
    #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
    #
    # There's a variable on the var stack as follows:
    #   name: 'foo'
    #   type: int
    #   register: 'eax'
    #
    # There's a primitive with this info:
    #   name: 'increment'
    #   out: int/reg
    #   value: 'ff 0/subop/increment'
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
$test-emit-subx-stmt-primitive-register:initialize-type:
    # var type/ecx: (payload type-tree) = int
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 1/imm32/value:int
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-emit-subx-stmt-primitive-register:initialize-var:
    # var var-foo/ecx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    51/push-ecx
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-emit-subx-stmt-primitive-register:initialize-var-name:
    # var-foo->name = "foo"
    8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "foo" %eax)
$test-emit-subx-stmt-primitive-register:initialize-var-register:
    # var-foo->register = "eax"
    8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
    (copy-array Heap "eax" %eax)
$test-emit-subx-stmt-primitive-register:initialize-stmt-var:
    # var operand/ebx: (payload stmt-var)
    68/push 0/imm32/is-deref:false
    68/push 0/imm32/next
    68/push 0/imm32/next
    51/push-ecx/var-foo
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ebx 4/r32/esp
$test-emit-subx-stmt-primitive-register:initialize-stmt:
    # var stmt/esi: (addr statement)
    53/push-ebx/outputs
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/no-inouts
    68/push 0/imm32/no-inouts
    68/push 0/imm32/operation
    68/push 0/imm32/operation
    68/push 1/imm32
    89/<- %esi 4/r32/esp
$test-emit-subx-stmt-primitive-register:initialize-stmt-operation:
    # stmt->operation = "increment"
    8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
    (copy-array Heap "increment" %eax)
$test-emit-subx-stmt-primitive-register:initialize-formal-var:
    # var formal-var/ebx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ebx 4/r32/esp
$test-emit-subx-stmt-primitive-register:initialize-formal-var-name:
    # formal-var->name = "dummy"
    8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "dummy" %eax)
$test-emit-subx-stmt-primitive-register:initialize-formal-register:
    # formal-var->register = "*"
    8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
    (copy-array Heap "*" %eax)  # Any-register
$test-emit-subx-stmt-primitive-register:initialize-var-list:
    # var formal-outputs/ebx: (payload list var)
    68/push 0/imm32/next
    68/push 0/imm32/next
    53/push-ebx/formal-var
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ebx 4/r32/esp
$test-emit-subx-stmt-primitive-register:initialize-primitive:
    # var primitives/ebx: (addr primitive)
    68/push 0/imm32/next
    68/push 0/imm32/next
    68/push 0/imm32/output-is-write-only
    68/push 0/imm32/no-disp32
    68/push 0/imm32/no-imm8
    68/push 0/imm32/no-imm32
    68/push 0/imm32/no-r32
    68/push 3/imm32/rm32-is-first-output
    68/push 0/imm32/subx-name
    68/push 0/imm32/subx-name
    53/push-ebx/outputs
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/no-inouts
    68/push 0/imm32/no-inouts
    68/push 0/imm32/name
    68/push 0/imm32/name
    89/<- %ebx 4/r32/esp
$test-emit-subx-stmt-primitive-register:initialize-primitive-name:
    # primitives->name = "increment"
    (copy-array Heap "increment" %ebx)  # Primitive-name
$test-emit-subx-stmt-primitive-register:initialize-primitive-subx-name:
    # primitives->subx-name = "ff 0/subop/increment"
    8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
    (copy-array Heap "ff 0/subop/increment" %eax)
    # convert
    c7 0/subop/copy *Curr-block-depth 0/imm32
    (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-primitive-register")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-emit-subx-stmt-select-primitive:
    # Select the right primitive between overloads.
    #   foo <- increment
    # =>
    #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
    #
    # There's a variable on the var stack as follows:
    #   name: 'foo'
    #   type: int
    #   register: 'eax'
    #
    # There's two primitives, as follows:
    #   - name: 'increment'
    #     out: int/reg
    #     value: 'ff 0/subop/increment'
    #   - name: 'increment'
    #     inout: int/mem
    #     value: 'ff 0/subop/increment'
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
$test-emit-subx-stmt-select-primitive:initialize-type:
    # var type/ecx: (payload type-tree) = int
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 1/imm32/value:int
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-emit-subx-stmt-select-primitive:initialize-var:
    # var var-foo/ecx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    51/push-ecx
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-emit-subx-stmt-select-primitive:initialize-var-name:
    # var-foo->name = "foo"
    8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "foo" %eax)
$test-emit-subx-stmt-select-primitive:initialize-var-register:
    # var-foo->register = "eax"
    8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
    (copy-array Heap "eax" %eax)
$test-emit-subx-stmt-select-primitive:initialize-stmt-var:
    # var operand/ebx: (payload stmt-var)
    68/push 0/imm32/is-deref:false
    68/push 0/imm32/next
    68/push 0/imm32/next
    51/push-ecx/var-foo
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ebx 4/r32/esp
$test-emit-subx-stmt-select-primitive:initialize-stmt:
    # var stmt/esi: (addr statement)
    53/push-ebx/outputs
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/no-inouts
    68/push 0/imm32/no-inouts
    68/push 0/imm32/operation
    68/push 0/imm32/operation
    68/push 1/imm32
    89/<- %esi 4/r32/esp
$test-emit-subx-stmt-select-primitive:initialize-stmt-operation:
    # stmt->operation = "increment"
    8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
    (copy-array Heap "increment" %eax)
$test-emit-subx-stmt-select-primitive:initialize-formal-var:
    # var formal-var/ebx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ebx 4/r32/esp
$test-emit-subx-stmt-select-primitive:initialize-formal-var-name:
    # formal-var->name = "dummy"
    8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "dummy" %eax)
$test-emit-subx-stmt-select-primitive:initialize-formal-register:
    # formal-var->register = "*"
    8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
    (copy-array Heap "*" %eax)  # Any-register
$test-emit-subx-stmt-select-primitive:initialize-var-list:
    # var formal-outputs/ebx: (payload list var)
    68/push 0/imm32/next
    68/push 0/imm32/next
    53/push-ebx/formal-var
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ebx 4/r32/esp
$test-emit-subx-stmt-select-primitive:initialize-primitive2:
    # var primitive2/edi: (payload primitive)
    68/push 0/imm32/next
    68/push 0/imm32/next
    68/push 0/imm32/output-is-write-only
    68/push 0/imm32/no-disp32
    68/push 0/imm32/no-imm8
    68/push 0/imm32/no-imm32
    68/push 0/imm32/no-r32
    68/push 3/imm32/rm32-is-first-output
    68/push 0/imm32/subx-name
    68/push 0/imm32/subx-name
    53/push-ebx/outputs
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/no-inouts
    68/push 0/imm32/no-inouts
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edi 4/r32/esp
$test-emit-subx-stmt-select-primitive:initialize-primitive2-name:
    # primitives->name = "increment"
    8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
    (copy-array Heap "increment" %eax)
$test-emit-subx-stmt-select-primitive:initialize-primitive2-subx-name:
    # primitives->subx-name = "ff 0/subop/increment"
    8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
    (copy-array Heap "ff 0/subop/increment" %eax)
$test-emit-subx-stmt-select-primitive:initialize-primitive:
    # var primitives/ebx: (addr primitive)
    57/push-edi
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/output-is-write-only
    68/push 0/imm32/no-disp32
    68/push 0/imm32/no-imm8
    68/push 0/imm32/no-imm32
    68/push 0/imm32/no-r32
    68/push 1/imm32/rm32-is-first-inout
    68/push 0/imm32/subx-name
    68/push 0/imm32/subx-name
    68/push 0/imm32/no-outputs
    68/push 0/imm32/no-outputs
    53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    89/<- %ebx 4/r32/esp
$test-emit-subx-stmt-select-primitive:initialize-primitive-name:
    # primitives->name = "increment"
    (copy-array Heap "increment" %ebx)  # Primitive-name
$test-emit-subx-stmt-select-primitive:initialize-primitive-subx-name:
    # primitives->subx-name = "ff 0/subop/increment"
    8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
    (copy-array Heap "ff 0/subop/increment" %eax)
    # convert
    c7 0/subop/copy *Curr-block-depth 0/imm32
    (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-emit-subx-stmt-select-primitive-2:
    # Select the right primitive between overloads.
    #   increment foo
    # =>
    #   ff 0/subop/increment %eax  # sub-optimal, but should suffice
    #
    # There's a variable on the var stack as follows:
    #   name: 'foo'
    #   type: int
    #   register: 'eax'
    #
    # There's two primitives, as follows:
    #   - name: 'increment'
    #     out: int/reg
    #     value: 'ff 0/subop/increment'
    #   - name: 'increment'
    #     inout: int/mem
    #     value: 'ff 0/subop/increment'
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
$test-emit-subx-stmt-select-primitive-2:initialize-type:
    # var type/ecx: (payload type-tree) = int
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 1/imm32/value:int
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-emit-subx-stmt-select-primitive-2:initialize-var:
    # var var-foo/ecx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    51/push-ecx
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-emit-subx-stmt-select-primitive-2:initialize-var-name:
    # var-foo->name = "foo"
    8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "foo" %eax)
$test-emit-subx-stmt-select-primitive-2:initialize-var-register:
    # var-foo->register = "eax"
    8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
    (copy-array Heap "eax" %eax)
$test-emit-subx-stmt-select-primitive-2:initialize-stmt-var:
    # var operand/ebx: (payload stmt-var)
    68/push 0/imm32/is-deref:false
    68/push 0/imm32/next
    68/push 0/imm32/next
    51/push-ecx/var-foo
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ebx 4/r32/esp
$test-emit-subx-stmt-select-primitive-2:initialize-stmt:
    # var stmt/esi: (addr statement)
    68/push 0/imm32/no-outputs
    68/push 0/imm32/no-outputs
    53/push-ebx/inouts
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/operation
    68/push 0/imm32/operation
    68/push 1/imm32
    89/<- %esi 4/r32/esp
$test-emit-subx-stmt-select-primitive-2:initialize-stmt-operation:
    # stmt->operation = "increment"
    8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
    (copy-array Heap "increment" %eax)
$test-emit-subx-stmt-select-primitive-2:initialize-formal-var:
    # var formal-var/ebx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    ff 6/subop/push *(ecx+0x10)  # Var-type + payload alloc id + handle alloc id
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ebx 4/r32/esp
$test-emit-subx-stmt-select-primitive-2:initialize-formal-var-name:
    # formal-var->name = "dummy"
    8d/copy-address *(ebx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "dummy" %eax)
$test-emit-subx-stmt-select-primitive-2:initialize-formal-register:
    # formal-var->register = "*"
    8d/copy-address *(ebx+0x1c) 0/r32/eax  # Var-register + 4
    (copy-array Heap "*" %eax)  # Any-register
$test-emit-subx-stmt-select-primitive-2:initialize-var-list:
    # var formal-outputs/ebx: (payload list stmt-var)
    68/push 0/imm32/next
    68/push 0/imm32/next
    53/push-ebx/formal-var
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ebx 4/r32/esp
$test-emit-subx-stmt-select-primitive-2:initialize-primitive2:
    # var primitive2/edi: (payload primitive)
    68/push 0/imm32/next
    68/push 0/imm32/next
    68/push 0/imm32/output-is-write-only
    68/push 0/imm32/no-disp32
    68/push 0/imm32/no-imm8
    68/push 0/imm32/no-imm32
    68/push 0/imm32/no-r32
    68/push 3/imm32/rm32-is-first-output
    68/push 0/imm32/subx-name
    68/push 0/imm32/subx-name
    53/push-ebx/outputs
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/no-inouts
    68/push 0/imm32/no-inouts
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edi 4/r32/esp
$test-emit-subx-stmt-select-primitive-2:initialize-primitive2-name:
    # primitives->name = "increment"
    8d/copy-address *(edi+4) 0/r32/eax  # Primitive-name + 4
    (copy-array Heap "increment" %eax)
$test-emit-subx-stmt-select-primitive-2:initialize-primitive2-subx-name:
    # primitives->subx-name = "ff 0/subop/increment"
    8d/copy-address *(edi+0x1c) 0/r32/eax  # Primitive-subx-name + 4
    (copy-array Heap "ff 0/subop/increment" %eax)
$test-emit-subx-stmt-select-primitive-2:initialize-primitive:
    # var primitives/ebx: (addr primitive)
    57/push-edi
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/output-is-write-only
    68/push 0/imm32/no-disp32
    68/push 0/imm32/no-imm8
    68/push 0/imm32/no-imm32
    68/push 0/imm32/no-r32
    68/push 1/imm32/rm32-is-first-inout
    68/push 0/imm32/subx-name
    68/push 0/imm32/subx-name
    68/push 0/imm32/no-outputs
    68/push 0/imm32/no-outputs
    53/push-ebx/inouts  # hack: reuse stmt-var from call stmt as (list var) in function declaration
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    89/<- %ebx 4/r32/esp
$test-emit-subx-stmt-select-primitive-2:initialize-primitive-name:
    # primitives->name = "increment"
    (copy-array Heap "increment" %ebx)  # Primitive-name
$test-emit-subx-stmt-select-primitive-2:initialize-primitive-subx-name:
    # primitives->subx-name = "ff 0/subop/increment"
    8d/copy-address *(ebx+0x18) 0/r32/eax  # Primitive-subx-name
    (copy-array Heap "ff 0/subop/increment" %eax)
    # convert
    c7 0/subop/copy *Curr-block-depth 0/imm32
    (emit-subx-stmt _test-output-buffered-file %esi %ebx Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "ff 0/subop/increment %eax" "F - test-emit-subx-stmt-select-primitive-2")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-increment-register:
    # Select the right register between overloads.
    #   foo <- increment
    # =>
    #   50/increment-eax
    #
    # There's a variable on the var stack as follows:
    #   name: 'foo'
    #   type: int
    #   register: 'eax'
    #
    # Primitives are the global definitions.
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
$test-increment-register:initialize-type:
    # var type/ecx: (payload type-tree) = int
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 1/imm32/value:int
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-increment-register:initialize-var:
    # var var-foo/ecx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    51/push-ecx
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-increment-register:initialize-var-name:
    # var-foo->name = "foo"
    8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "foo" %eax)
$test-increment-register:initialize-var-register:
    # var-foo->register = "eax"
    8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
    (copy-array Heap "eax" %eax)
$test-increment-register:initialize-stmt-var:
    # var operand/ebx: (payload stmt-var)
    68/push 0/imm32/is-deref:false
    68/push 0/imm32/next
    68/push 0/imm32/next
    51/push-ecx/var-foo
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ebx 4/r32/esp
$test-increment-register:initialize-stmt:
    # var stmt/esi: (addr statement)
    53/push-ebx/outputs
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/no-inouts
    68/push 0/imm32/no-inouts
    68/push 0/imm32/operation
    68/push 0/imm32/operation
    68/push 1/imm32
    89/<- %esi 4/r32/esp
$test-increment-register:initialize-stmt-operation:
    # stmt->operation = "increment"
    8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
    (copy-array Heap "increment" %eax)
    # convert
    c7 0/subop/copy *Curr-block-depth 0/imm32
    (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "40/increment-eax" "F - test-increment-register")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-add-reg-to-reg:
    #   var1/reg <- add var2/reg
    # =>
    #   01/add-to %var1 var2
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
$test-add-reg-to-reg:initialize-type:
    # var type/ecx: (payload type-tree) = int
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 1/imm32/value:int
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-add-reg-to-reg:initialize-var1:
    # var var1/ecx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    51/push-ecx
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-add-reg-to-reg:initialize-var1-name:
    # var1->name = "var1"
    8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "var1" %eax)
$test-add-reg-to-reg:initialize-var1-register:
    # var1->register = "eax"
    8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
    (copy-array Heap "eax" %eax)
$test-add-reg-to-reg:initialize-var2:
    # var var2/edx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    ff 6/subop/push *(ecx+0x10)
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edx 4/r32/esp
$test-add-reg-to-reg:initialize-var2-name:
    # var2->name = "var2"
    8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "var2" %eax)
$test-add-reg-to-reg:initialize-var2-register:
    # var2->register = "ecx"
    8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
    (copy-array Heap "ecx" %eax)
$test-add-reg-to-reg:initialize-inouts:
    # var inouts/esi: (payload stmt-var) = [var2]
    68/push 0/imm32/is-deref:false
    68/push 0/imm32/next
    68/push 0/imm32/next
    52/push-edx/var2
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %esi 4/r32/esp
$test-add-reg-to-reg:initialize-outputs:
    # var outputs/edi: (payload stmt-var) = [var1]
    68/push 0/imm32/is-deref:false
    68/push 0/imm32/next
    68/push 0/imm32/next
    51/push-ecx/var1
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edi 4/r32/esp
$test-add-reg-to-reg:initialize-stmt:
    # var stmt/esi: (addr statement)
    68/push 0/imm32/next
    68/push 0/imm32/next
    57/push-edi/outputs
    68/push 0x11/imm32/alloc-id:fake
    56/push-esi/inouts
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/operation
    68/push 0/imm32/operation
    68/push 1/imm32/tag:stmt1
    89/<- %esi 4/r32/esp
$test-add-reg-to-reg:initialize-stmt-operation:
    # stmt->operation = "add"
    8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
    (copy-array Heap "add" %eax)
    # convert
    c7 0/subop/copy *Curr-block-depth 0/imm32
    (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "01/add-to %eax 0x00000001/r32" "F - test-add-reg-to-reg")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-add-reg-to-mem:
    #   add-to var1 var2/reg
    # =>
    #   01/add-to *(ebp+__) var2
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
$test-add-reg-to-mem:initialize-type:
    # var type/ecx: (payload type-tree) = int
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 1/imm32/value:int
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-add-reg-to-mem:initialize-var1:
    # var var1/ecx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 8/imm32/stack-offset
    68/push 1/imm32/block-depth
    51/push-ecx
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-add-reg-to-mem:initialize-var1-name:
    # var1->name = "var1"
    8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "var1" %eax)
$test-add-reg-to-mem:initialize-var2:
    # var var2/edx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    ff 6/subop/push *(ecx+0x10)
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edx 4/r32/esp
$test-add-reg-to-mem:initialize-var2-name:
    # var2->name = "var2"
    8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "var2" %eax)
$test-add-reg-to-mem:initialize-var2-register:
    # var2->register = "ecx"
    8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
    (copy-array Heap "ecx" %eax)
$test-add-reg-to-mem:initialize-inouts:
    # var inouts/esi: (payload stmt-var) = [var2]
    68/push 0/imm32/is-deref:false
    68/push 0/imm32/next
    68/push 0/imm32/next
    52/push-edx/var2
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %esi 4/r32/esp
    # inouts = [var1, var2]
    68/push 0/imm32/is-deref:false
    56/push-esi/next
    68/push 0x11/imm32/alloc-id:fake
    51/push-ecx/var1
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %esi 4/r32/esp
$test-add-reg-to-mem:initialize-stmt:
    # var stmt/esi: (addr statement)
    68/push 0/imm32/next
    68/push 0/imm32/next
    68/push 0/imm32/outputs
    68/push 0/imm32/outputs
    56/push-esi/inouts
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/operation
    68/push 0/imm32/operation
    68/push 1/imm32/tag:stmt1
    89/<- %esi 4/r32/esp
$test-add-reg-to-mem:initialize-stmt-operation:
    # stmt->operation = "add-to"
    8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
    (copy-array Heap "add-to" %eax)
    # convert
    c7 0/subop/copy *Curr-block-depth 0/imm32
    (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "01/add-to *(ebp+0x00000008) 0x00000001/r32" "F - test-add-reg-to-mem")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-add-mem-to-reg:
    #   var1/reg <- add var2
    # =>
    #   03/add *(ebp+__) var1
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
$test-add-mem-to-reg:initialize-type:
    # var type/ecx: (payload type-tree) = int
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 1/imm32/value:int
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-add-mem-to-reg:initialize-var:
    # var var1/ecx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    51/push-ecx
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-add-mem-to-reg:initialize-var-name:
    # var1->name = "foo"
    8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "var1" %eax)
$test-add-mem-to-reg:initialize-var-register:
    # var1->register = "eax"
    8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
    (copy-array Heap "eax" %eax)
$test-add-mem-to-reg:initialize-var2:
    # var var2/edx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 8/imm32/stack-offset
    68/push 1/imm32/block-depth
    ff 6/subop/push *(ecx+0x10)
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edx 4/r32/esp
$test-add-mem-to-reg:initialize-var2-name:
    # var2->name = "var2"
    8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "var2" %eax)
$test-add-mem-to-reg:initialize-inouts:
    # var inouts/esi: (payload stmt-var) = [var2]
    68/push 0/imm32/is-deref:false
    68/push 0/imm32/next
    68/push 0/imm32/next
    52/push-edx/var2
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %esi 4/r32/esp
$test-add-mem-to-reg:initialize-outputs:
    # var outputs/edi: (payload stmt-var) = [var1]
    68/push 0/imm32/is-deref:false
    68/push 0/imm32/next
    68/push 0/imm32/next
    51/push-ecx/var1
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edi 4/r32/esp
$test-add-mem-to-reg:initialize-stmt:
    # var stmt/esi: (addr statement)
    68/push 0/imm32/next
    68/push 0/imm32/next
    57/push-edi/outputs
    68/push 0x11/imm32/alloc-id:fake
    56/push-esi/inouts
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/operation
    68/push 0/imm32/operation
    68/push 1/imm32/tag:stmt1
    89/<- %esi 4/r32/esp
$test-add-mem-to-reg:initialize-stmt-operation:
    # stmt->operation = "add"
    8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
    (copy-array Heap "add" %eax)
    # convert
    c7 0/subop/copy *Curr-block-depth 0/imm32
    (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "03/add *(ebp+0x00000008) 0x00000000/r32" "F - test-add-mem-to-reg")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-add-literal-to-eax:
    #   var1/eax <- add 0x34
    # =>
    #   05/add-to-eax 0x34/imm32
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
$test-add-literal-to-eax:initialize-var-type:
    # var type/ecx: (payload type-tree) = int
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 1/imm32/value:int
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-add-literal-to-eax:initialize-var:
    # var v/ecx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    51/push-ecx
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-add-literal-to-eax:initialize-var-name:
    # v->name = "v"
    8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "v" %eax)
$test-add-literal-to-eax:initialize-var-register:
    # v->register = "eax"
    8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
    (copy-array Heap "eax" %eax)
$test-add-literal-to-eax:initialize-literal-type:
    # var type/edx: (payload type-tree) = literal
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 0/imm32/value:literal
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edx 4/r32/esp
$test-add-literal-to-eax:initialize-literal:
    # var l/edx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    52/push-edx
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edx 4/r32/esp
$test-add-literal-to-eax:initialize-literal-value:
    # l->name = "0x34"
    8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "0x34" %eax)
$test-add-literal-to-eax:initialize-inouts:
    # var inouts/esi: (payload stmt-var) = [l]
    68/push 0/imm32/is-deref:false
    68/push 0/imm32/next
    68/push 0/imm32/next
    52/push-edx/l
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %esi 4/r32/esp
$test-add-literal-to-eax:initialize-outputs:
    # var outputs/edi: (payload stmt-var) = [v]
    68/push 0/imm32/is-deref:false
    68/push 0/imm32/next
    68/push 0/imm32/next
    51/push-ecx/v
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edi 4/r32/esp
$test-add-literal-to-eax:initialize-stmt:
    # var stmt/esi: (addr statement)
    68/push 0/imm32/next
    68/push 0/imm32/next
    57/push-edi/outputs
    68/push 0x11/imm32/alloc-id:fake
    56/push-esi/inouts
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/operation
    68/push 0/imm32/operation
    68/push 1/imm32/tag:stmt1
    89/<- %esi 4/r32/esp
$test-add-literal-to-eax:initialize-stmt-operation:
    # stmt->operation = "add"
    8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
    (copy-array Heap "add" %eax)
    # convert
    c7 0/subop/copy *Curr-block-depth 0/imm32
    (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "05/add-to-eax 0x34/imm32" "F - test-add-literal-to-eax")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-add-literal-to-reg:
    #   var1/ecx <- add 0x34
    # =>
    #   81 0/subop/add %ecx 0x34/imm32
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
$test-add-literal-to-reg:initialize-var-type:
    # var type/ecx: (payload type-tree) = int
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 1/imm32/value:int
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-add-literal-to-reg:initialize-var:
    # var v/ecx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    51/push-ecx
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-add-literal-to-reg:initialize-var-name:
    # v->name = "v"
    8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "v" %eax)
$test-add-literal-to-reg:initialize-var-register:
    # v->register = "ecx"
    8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
    (copy-array Heap "ecx" %eax)
$test-add-literal-to-reg:initialize-literal-type:
    # var type/edx: (payload type-tree) = literal
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 0/imm32/value:literal
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edx 4/r32/esp
$test-add-literal-to-reg:initialize-literal:
    # var l/edx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    52/push-edx
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edx 4/r32/esp
$test-add-literal-to-reg:initialize-literal-value:
    # l->name = "0x34"
    8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "0x34" %eax)
$test-add-literal-to-reg:initialize-inouts:
    # var inouts/esi: (payload stmt-var) = [l]
    68/push 0/imm32/is-deref:false
    68/push 0/imm32/next
    68/push 0/imm32/next
    52/push-edx/l
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %esi 4/r32/esp
$test-add-literal-to-reg:initialize-outputs:
    # var outputs/edi: (payload stmt-var) = [v]
    68/push 0/imm32/is-deref:false
    68/push 0/imm32/next
    68/push 0/imm32/next
    51/push-ecx/v
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edi 4/r32/esp
$test-add-literal-to-reg:initialize-stmt:
    # var stmt/esi: (addr statement)
    68/push 0/imm32/next
    68/push 0/imm32/next
    57/push-edi/outputs
    68/push 0x11/imm32/alloc-id:fake
    56/push-esi/inouts
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/operation
    68/push 0/imm32/operation
    68/push 1/imm32/tag:stmt1
    89/<- %esi 4/r32/esp
$test-add-literal-to-reg:initialize-stmt-operation:
    # stmt->operation = "add"
    8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
    (copy-array Heap "add" %eax)
    # convert
    c7 0/subop/copy *Curr-block-depth 0/imm32
    (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "81 0/subop/add %ecx 0x34/imm32" "F - test-add-literal-to-reg")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-add-literal-to-mem:
    #   add-to var1, 0x34
    # =>
    #   81 0/subop/add %eax 0x34/imm32
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
$test-add-literal-to-mem:initialize-type:
    # var type/ecx: (payload type-tree) = int
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 1/imm32/value:int
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-add-literal-to-mem:initialize-var1:
    # var var1/ecx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 8/imm32/stack-offset
    68/push 1/imm32/block-depth
    51/push-ecx
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-add-literal-to-mem:initialize-var1-name:
    # var1->name = "var1"
    8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "var1" %eax)
$test-add-literal-to-mem:initialize-literal-type:
    # var type/edx: (payload type-tree) = literal
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 0/imm32/value:literal
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edx 4/r32/esp
$test-add-literal-to-mem:initialize-literal:
    # var l/edx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    52/push-edx
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edx 4/r32/esp
$test-add-literal-to-mem:initialize-literal-value:
    # l->name = "0x34"
    8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "0x34" %eax)
$test-add-literal-to-mem:initialize-inouts:
    # var inouts/esi: (payload stmt-var) = [l]
    68/push 0/imm32/is-deref:false
    68/push 0/imm32/next
    68/push 0/imm32/next
    52/push-edx/l
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %esi 4/r32/esp
    # var inouts = (handle stmt-var) = [var1, var2]
    68/push 0/imm32/is-deref:false
    56/push-esi/next
    68/push 0x11/imm32/alloc-id:fake
    51/push-ecx/var1
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %esi 4/r32/esp
$test-add-literal-to-mem:initialize-stmt:
    # var stmt/esi: (addr statement)
    68/push 0/imm32/next
    68/push 0/imm32/next
    68/push 0/imm32/outputs
    68/push 0/imm32/outputs
    56/push-esi/inouts
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/operation
    68/push 0/imm32/operation
    68/push 1/imm32/tag:stmt1
    89/<- %esi 4/r32/esp
$test-add-literal-to-mem:initialize-stmt-operation:
    # stmt->operation = "add-to"
    8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
    (copy-array Heap "add-to" %eax)
    # convert
    c7 0/subop/copy *Curr-block-depth 0/imm32
    (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "81 0/subop/add *(ebp+0x00000008) 0x34/imm32" "F - test-add-literal-to-mem")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-shift-reg-by-literal:
    #   var1/ecx <- shift-left 2
    # =>
    #   c1/shift 4/subop/left %ecx 2/imm8
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
$test-shift-reg-by-literal:initialize-var-type:
    # var type/ecx: (payload type-tree) = int
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 1/imm32/value:int
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-shift-reg-by-literal:initialize-var:
    # var v/ecx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    51/push-ecx
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-shift-reg-by-literal:initialize-var-name:
    # v->name = "v"
    8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "v" %eax)
$test-shift-reg-by-literal:initialize-var-register:
    # v->register = "ecx"
    8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
    (copy-array Heap "ecx" %eax)
$test-shift-reg-by-literal:initialize-literal-type:
    # var type/edx: (payload type-tree) = literal
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 0/imm32/value:literal
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edx 4/r32/esp
$test-shift-reg-by-literal:initialize-literal:
    # var l/edx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    52/push-edx
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edx 4/r32/esp
$test-shift-reg-by-literal:initialize-literal-value:
    # l->name = "2"
    8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "2" %eax)
$test-shift-reg-by-literal:initialize-inouts:
    # var inouts/esi: (payload stmt-var) = [l]
    68/push 0/imm32/is-deref:false
    68/push 0/imm32/next
    68/push 0/imm32/next
    52/push-edx/l
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %esi 4/r32/esp
$test-shift-reg-by-literal:initialize-outputs:
    # var outputs/edi: (payload stmt-var) = [v]
    68/push 0/imm32/is-deref:false
    68/push 0/imm32/next
    68/push 0/imm32/next
    51/push-ecx/v
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edi 4/r32/esp
$test-shift-reg-by-literal:initialize-stmt:
    # var stmt/esi: (addr statement)
    68/push 0/imm32/next
    68/push 0/imm32/next
    57/push-edi/outputs
    68/push 0x11/imm32/alloc-id:fake
    56/push-esi/inouts
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/operation
    68/push 0/imm32/operation
    68/push 1/imm32/tag:stmt1
    89/<- %esi 4/r32/esp
$test-shift-reg-by-literal:initialize-stmt-operation:
    # stmt->operation = "shift-left"
    8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
    (copy-array Heap "shift-left" %eax)
    # convert
    c7 0/subop/copy *Curr-block-depth 0/imm32
    (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "c1/shift 4/subop/left %ecx 2/imm8" "F - test-shift-reg-by-literal")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-shift-mem-by-literal:
    #   shift-left var 3
    # =>
    #   c1/shift 4/subop/left *(ebp+8) 3/imm8
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
$test-shift-mem-by-literal:initialize-type:
    # var type/ecx: (payload type-tree) = int
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 1/imm32/value:int
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-shift-mem-by-literal:initialize-var1:
    # var var1/ecx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 8/imm32/stack-offset
    68/push 1/imm32/block-depth
    51/push-ecx
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-shift-mem-by-literal:initialize-var1-name:
    # var1->name = "var1"
    8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "var1" %eax)
$test-shift-mem-by-literal:initialize-literal-type:
    # var type/edx: (payload type-tree) = literal
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 0/imm32/value:literal
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edx 4/r32/esp
$test-shift-mem-by-literal:initialize-literal:
    # var l/edx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    52/push-edx
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edx 4/r32/esp
$test-shift-mem-by-literal:initialize-literal-value:
    # l->name = "3"
    8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "3" %eax)
$test-shift-mem-by-literal:initialize-inouts:
    # var inouts/esi: (payload stmt-var) = [l]
    68/push 0/imm32/is-deref:false
    68/push 0/imm32/next
    68/push 0/imm32/next
    52/push-edx/l
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %esi 4/r32/esp
    # var inouts = (handle stmt-var) = [var1, var2]
    68/push 0/imm32/is-deref:false
    56/push-esi/next
    68/push 0x11/imm32/alloc-id:fake
    51/push-ecx/var1
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %esi 4/r32/esp
$test-shift-mem-by-literal:initialize-stmt:
    # var stmt/esi: (addr statement)
    68/push 0/imm32/next
    68/push 0/imm32/next
    68/push 0/imm32/outputs
    68/push 0/imm32/outputs
    56/push-esi/inouts
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/operation
    68/push 0/imm32/operation
    68/push 1/imm32/tag:stmt1
    89/<- %esi 4/r32/esp
$test-shift-mem-by-literal:initialize-stmt-operation:
    # stmt->operation = "shift-left"
    8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
    (copy-array Heap "shift-left" %eax)
    # convert
    c7 0/subop/copy *Curr-block-depth 0/imm32
    (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "c1/shift 4/subop/left *(ebp+0x00000008) 3/imm8" "F - test-shift-mem-by-literal")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-compare-reg-with-reg:
    #   compare var1/ecx, var2/eax
    # =>
    #   39/compare %ecx 0/r32/eax
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
$test-compare-reg-with-reg:initialize-type:
    # var type/ecx: (payload type-tree) = int
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 1/imm32/value:int
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-compare-reg-with-reg:initialize-var1:
    # var var1/ecx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    51/push-ecx
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-compare-reg-with-reg:initialize-var1-name:
    # var1->name = "var1"
    8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "var1" %eax)
$test-compare-reg-with-reg:initialize-var1-register:
    # var1->register = "ecx"
    8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
    (copy-array Heap "ecx" %eax)
$test-compare-reg-with-reg:initialize-var2:
    # var var2/edx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    ff 6/subop/push *(ecx+0x10)
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edx 4/r32/esp
$test-compare-reg-with-reg:initialize-var2-name:
    # var2->name = "var2"
    8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "var2" %eax)
$test-compare-reg-with-reg:initialize-var2-register:
    # var2->register = "eax"
    8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
    (copy-array Heap "eax" %eax)
$test-compare-reg-with-reg:initialize-inouts:
    # var inouts/esi: (payload stmt-var) = [var2]
    68/push 0/imm32/is-deref:false
    68/push 0/imm32/next
    68/push 0/imm32/next
    52/push-edx/var2
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %esi 4/r32/esp
    # inouts = [var1, var2]
    68/push 0/imm32/is-deref:false
    56/push-esi/next
    68/push 0x11/imm32/alloc-id:fake
    51/push-ecx/var1
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %esi 4/r32/esp
$test-compare-reg-with-reg:initialize-stmt:
    # var stmt/esi: (addr statement)
    68/push 0/imm32/next
    68/push 0/imm32/next
    68/push 0/imm32/outputs
    68/push 0/imm32/outputs
    56/push-esi/inouts
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/operation
    68/push 0/imm32/operation
    68/push 1/imm32/tag:stmt1
    89/<- %esi 4/r32/esp
$test-compare-reg-with-reg:initialize-stmt-operation:
    # stmt->operation = "compare"
    8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
    (copy-array Heap "compare" %eax)
    # convert
    c7 0/subop/copy *Curr-block-depth 0/imm32
    (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "39/compare-> %ecx 0x00000000/r32" "F - test-compare-reg-with-reg")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-compare-mem-with-reg:
    #   compare var1, var2/eax
    # =>
    #   39/compare *(ebp+___) 0/r32/eax
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
$test-compare-mem-with-reg:initialize-type:
    # var type/ecx: (payload type-tree) = int
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 1/imm32/value:int
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-compare-mem-with-reg:initialize-var1:
    # var var1/ecx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 8/imm32/stack-offset
    68/push 1/imm32/block-depth
    51/push-ecx
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-compare-mem-with-reg:initialize-var1-name:
    # var1->name = "var1"
    8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "var1" %eax)
$test-compare-mem-with-reg:initialize-var2:
    # var var2/edx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    ff 6/subop/push *(ecx+0x10)
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edx 4/r32/esp
$test-compare-mem-with-reg:initialize-var2-name:
    # var2->name = "var2"
    8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "var2" %eax)
$test-compare-mem-with-reg:initialize-var2-register:
    # var2->register = "eax"
    8d/copy-address *(edx+0x1c) 0/r32/eax  # Var-register + 4
    (copy-array Heap "eax" %eax)
$test-compare-mem-with-reg:initialize-inouts:
    # var inouts/esi: (payload stmt-var) = [var2]
    68/push 0/imm32/is-deref:false
    68/push 0/imm32/next
    68/push 0/imm32/next
    52/push-edx/var2
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %esi 4/r32/esp
    # inouts = [var1, var2]
    68/push 0/imm32/is-deref:false
    56/push-esi/next
    68/push 0x11/imm32/alloc-id:fake
    51/push-ecx/var1
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %esi 4/r32/esp
$test-compare-mem-with-reg:initialize-stmt:
    # var stmt/esi: (addr statement)
    68/push 0/imm32/next
    68/push 0/imm32/next
    68/push 0/imm32/outputs
    68/push 0/imm32/outputs
    56/push-esi/inouts
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/operation
    68/push 0/imm32/operation
    68/push 1/imm32/tag:stmt1
    89/<- %esi 4/r32/esp
$test-compare-mem-with-reg:initialize-stmt-operation:
    # stmt->operation = "compare"
    8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
    (copy-array Heap "compare" %eax)
    # convert
    c7 0/subop/copy *Curr-block-depth 0/imm32
    (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "39/compare-> *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-mem-with-reg")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-compare-reg-with-mem:
    #   compare var1/eax, var2
    # =>
    #   3b/compare<- *(ebp+___) 0/r32/eax
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
$test-compare-reg-with-mem:initialize-type:
    # var type/ecx: (payload type-tree) = int
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 1/imm32/value:int
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-compare-reg-with-mem:initialize-var1:
    # var var1/ecx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    51/push-ecx
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-compare-reg-with-mem:initialize-var1-name:
    # var1->name = "var1"
    8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "var1" %eax)
$test-compare-reg-with-mem:initialize-var1-register:
    # var1->register = "eax"
    8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
    (copy-array Heap "eax" %eax)
$test-compare-reg-with-mem:initialize-var2:
    # var var2/edx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 8/imm32/stack-offset
    68/push 1/imm32/block-depth
    ff 6/subop/push *(ecx+0x10)
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edx 4/r32/esp
$test-compare-reg-with-mem:initialize-var2-name:
    # var2->name = "var2"
    8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "var2" %eax)
$test-compare-reg-with-mem:initialize-inouts:
    # var inouts/esi: (payload stmt-var) = [var2]
    68/push 0/imm32/is-deref:false
    68/push 0/imm32/next
    68/push 0/imm32/next
    52/push-edx/var2
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %esi 4/r32/esp
    # inouts = [var1, var2]
    68/push 0/imm32/is-deref:false
    56/push-esi/next
    68/push 0x11/imm32/alloc-id:fake
    51/push-ecx/var1
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %esi 4/r32/esp
$test-compare-reg-with-mem:initialize-stmt:
    # var stmt/esi: (addr statement)
    68/push 0/imm32/next
    68/push 0/imm32/next
    68/push 0/imm32/outputs
    68/push 0/imm32/outputs
    56/push-esi/inouts
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/operation
    68/push 0/imm32/operation
    68/push 1/imm32/tag:stmt1
    89/<- %esi 4/r32/esp
$test-compare-reg-with-mem:initialize-stmt-operation:
    # stmt->operation = "compare"
    8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
    (copy-array Heap "compare" %eax)
    # convert
    c7 0/subop/copy *Curr-block-depth 0/imm32
    (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "3b/compare<- *(ebp+0x00000008) 0x00000000/r32" "F - test-compare-reg-with-mem")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-compare-mem-with-literal:
    #   compare var1, 0x34
    # =>
    #   81 7/subop/compare *(ebp+___) 0x34/imm32
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
$test-compare-mem-with-literal:initialize-type:
    # var type/ecx: (payload type-tree) = int
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 1/imm32/value:int
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-compare-mem-with-literal:initialize-var1:
    # var var1/ecx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 8/imm32/stack-offset
    68/push 1/imm32/block-depth
    51/push-ecx
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-compare-mem-with-literal:initialize-var1-name:
    # var1->name = "var1"
    8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "var1" %eax)
$test-compare-mem-with-literal:initialize-literal-type:
    # var type/edx: (payload type-tree) = literal
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 0/imm32/value:literal
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edx 4/r32/esp
$test-compare-mem-with-literal:initialize-literal:
    # var l/edx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    52/push-edx
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edx 4/r32/esp
$test-compare-mem-with-literal:initialize-literal-value:
    # l->name = "0x34"
    8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "0x34" %eax)
$test-compare-mem-with-literal:initialize-inouts:
    # var inouts/esi: (payload stmt-var) = [l]
    68/push 0/imm32/is-deref:false
    68/push 0/imm32/next
    68/push 0/imm32/next
    52/push-edx/l
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %esi 4/r32/esp
    # var inouts = (handle stmt-var) = [var1, var2]
    68/push 0/imm32/is-deref:false
    56/push-esi/next
    68/push 0x11/imm32/alloc-id:fake
    51/push-ecx/var1
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %esi 4/r32/esp
$test-compare-mem-with-literal:initialize-stmt:
    # var stmt/esi: (addr statement)
    68/push 0/imm32/next
    68/push 0/imm32/next
    68/push 0/imm32/outputs
    68/push 0/imm32/outputs
    56/push-esi/inouts
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/operation
    68/push 0/imm32/operation
    68/push 1/imm32/tag:stmt1
    89/<- %esi 4/r32/esp
$test-compare-mem-with-literal:initialize-stmt-operation:
    # stmt->operation = "compare"
    8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
    (copy-array Heap "compare" %eax)
    # convert
    c7 0/subop/copy *Curr-block-depth 0/imm32
    (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "81 7/subop/compare *(ebp+0x00000008) 0x34/imm32" "F - test-compare-mem-with-literal")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-compare-eax-with-literal:
    #   compare var1/eax 0x34
    # =>
    #   3d/compare-eax-with 0x34/imm32
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
$test-compare-eax-with-literal:initialize-type:
    # var type/ecx: (payload type-tree) = int
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 1/imm32/value:int
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-compare-eax-with-literal:initialize-var1:
    # var var1/ecx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    51/push-ecx
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-compare-eax-with-literal:initialize-var1-name:
    # var1->name = "var1"
    8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "var1" %eax)
$test-compare-eax-with-literal:initialize-var1-register:
    # v->register = "eax"
    8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
    (copy-array Heap "eax" %eax)
$test-compare-eax-with-literal:initialize-literal-type:
    # var type/edx: (payload type-tree) = literal
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 0/imm32/value:literal
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edx 4/r32/esp
$test-compare-eax-with-literal:initialize-literal:
    # var l/edx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    52/push-edx
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edx 4/r32/esp
$test-compare-eax-with-literal:initialize-literal-value:
    # l->name = "0x34"
    8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "0x34" %eax)
$test-compare-eax-with-literal:initialize-inouts:
    # var inouts/esi: (payload stmt-var) = [l]
    68/push 0/imm32/is-deref:false
    68/push 0/imm32/next
    68/push 0/imm32/next
    52/push-edx/l
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %esi 4/r32/esp
    # var inouts = (handle stmt-var) = [var1, var2]
    68/push 0/imm32/is-deref:false
    56/push-esi/next
    68/push 0x11/imm32/alloc-id:fake
    51/push-ecx/var1
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %esi 4/r32/esp
$test-compare-eax-with-literal:initialize-stmt:
    # var stmt/esi: (addr statement)
    68/push 0/imm32/next
    68/push 0/imm32/next
    68/push 0/imm32/outputs
    68/push 0/imm32/outputs
    56/push-esi/inouts
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/operation
    68/push 0/imm32/operation
    68/push 1/imm32/tag:stmt1
    89/<- %esi 4/r32/esp
$test-compare-eax-with-literal:initialize-stmt-operation:
    # stmt->operation = "compare"
    8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
    (copy-array Heap "compare" %eax)
    # convert
    c7 0/subop/copy *Curr-block-depth 0/imm32
    (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "3d/compare-eax-with 0x34/imm32" "F - test-compare-eax-with-literal")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-compare-reg-with-literal:
    #   compare var1/ecx 0x34
    # =>
    #   81 7/subop/compare %ecx 0x34/imm32
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
$test-compare-reg-with-literal:initialize-type:
    # var type/ecx: (payload type-tree) = int
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 1/imm32/value:int
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-compare-reg-with-literal:initialize-var1:
    # var var1/ecx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    51/push-ecx
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-compare-reg-with-literal:initialize-var1-name:
    # var1->name = "var1"
    8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "var1" %eax)
$test-compare-reg-with-literal:initialize-var1-register:
    # v->register = "ecx"
    8d/copy-address *(ecx+0x1c) 0/r32/eax  # Var-register + 4
    (copy-array Heap "ecx" %eax)
$test-compare-reg-with-literal:initialize-literal-type:
    # var type/edx: (payload type-tree) = literal
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 0/imm32/value:literal
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edx 4/r32/esp
$test-compare-reg-with-literal:initialize-literal:
    # var l/edx: (payload var)
    68/push 0/imm32/register
    68/push 0/imm32/register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    52/push-edx
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %edx 4/r32/esp
$test-compare-reg-with-literal:initialize-literal-value:
    # l->name = "0x34"
    8d/copy-address *(edx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "0x34" %eax)
$test-compare-reg-with-literal:initialize-inouts:
    # var inouts/esi: (payload stmt-var) = [l]
    68/push 0/imm32/is-deref:false
    68/push 0/imm32/next
    68/push 0/imm32/next
    52/push-edx/l
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %esi 4/r32/esp
    # var inouts = (handle stmt-var) = [var1, var2]
    68/push 0/imm32/is-deref:false
    56/push-esi/next
    68/push 0x11/imm32/alloc-id:fake
    51/push-ecx/var1
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %esi 4/r32/esp
$test-compare-reg-with-literal:initialize-stmt:
    # var stmt/esi: (addr statement)
    68/push 0/imm32/next
    68/push 0/imm32/next
    68/push 0/imm32/outputs
    68/push 0/imm32/outputs
    56/push-esi/inouts
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/operation
    68/push 0/imm32/operation
    68/push 1/imm32/tag:stmt1
    89/<- %esi 4/r32/esp
$test-compare-reg-with-literal:initialize-stmt-operation:
    # stmt->operation = "compare"
    8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
    (copy-array Heap "compare" %eax)
    # convert
    c7 0/subop/copy *Curr-block-depth 0/imm32
    (emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "81 7/subop/compare %ecx 0x34/imm32" "F - test-compare-reg-with-literal")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-emit-subx-stmt-function-call:
    # Call a function on a variable on the stack.
    #   f foo
    # =>
    #   (f *(ebp-8))
    # (Changing the function name supports overloading in general, but here it
    # just serves to help disambiguate things.)
    #
    # There's a variable on the var stack as follows:
    #   name: 'foo'
    #   type: int
    #   stack-offset: -8
    #
    # There's nothing in primitives.
    #
    # We don't perform any checking here on the type of 'f'.
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
$test-emit-subx-function-call:initialize-type:
    # var type/ecx: (payload type-tree) = int
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 1/imm32/value:int
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-emit-subx-function-call:initialize-var:
    # var var-foo/ecx: (payload var) = var(type)
    68/push 0/imm32/no-register
    68/push 0/imm32/no-register
    68/push -8/imm32/stack-offset
    68/push 1/imm32/block-depth
    51/push-ecx/type
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-emit-subx-function-call:initialize-var-name:
    # var-foo->name = "foo"
    8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "foo" %eax)
$test-emit-subx-function-call:initialize-stmt-var:
    # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
    68/push 0/imm32/is-deref:false
    68/push 0/imm32/next
    68/push 0/imm32/next
    51/push-ecx/var-foo
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ebx 4/r32/esp
$test-emit-subx-function-call:initialize-stmt:
    # var stmt/esi: (addr statement)
    68/push 0/imm32/no-outputs
    68/push 0/imm32/no-outputs
    53/push-ebx/inouts
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/operation
    68/push 0/imm32/operation
    68/push 1/imm32/tag
    89/<- %esi 4/r32/esp
$test-emit-subx-function-call:initialize-stmt-operation:
    # stmt->operation = "f"
    8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
    (copy-array Heap "f" %eax)
    # convert
    c7 0/subop/copy *Curr-block-depth 0/imm32
    (emit-subx-stmt _test-output-buffered-file %esi 0 Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "(f *(ebp+0xfffffff8))" "F - test-emit-subx-stmt-function-call")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-emit-subx-stmt-function-call-with-literal-arg:
    # Call a function on a literal.
    #   f 0x34
    # =>
    #   (f2 0x34)
    #
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    (clear-stream _test-output-stream)
    (clear-stream $_test-output-buffered-file->buffer)
$test-emit-subx-function-call-with-literal-arg:initialize-type:
    # var type/ecx: (payload type-tree) = int
    68/push 0/imm32/right:null
    68/push 0/imm32/right:null
    68/push 0/imm32/left:unused
    68/push 0/imm32/value:literal
    68/push 1/imm32/is-atom?:true
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-emit-subx-function-call-with-literal-arg:initialize-var:
    # var var-foo/ecx: (payload var) = var(lit)
    68/push 0/imm32/no-register
    68/push 0/imm32/no-register
    68/push 0/imm32/no-stack-offset
    68/push 1/imm32/block-depth
    51/push-ecx/type
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/name
    68/push 0/imm32/name
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ecx 4/r32/esp
$test-emit-subx-function-call-with-literal-arg:initialize-var-name:
    # var-foo->name = "0x34"
    8d/copy-address *(ecx+4) 0/r32/eax  # Var-name + 4
    (copy-array Heap "0x34" %eax)
$test-emit-subx-function-call-with-literal-arg:initialize-stmt-var:
    # var operand/ebx: (payload stmt-var) = stmt-var(var-foo)
    68/push 0/imm32/is-deref:false
    68/push 0/imm32/next
    68/push 0/imm32/next
    51/push-ecx/var-foo
    68/push 0x11/imm32/alloc-id:fake
    68/push 0x11/imm32/alloc-id:fake:payload
    89/<- %ebx 4/r32/esp
$test-emit-subx-function-call-with-literal-arg:initialize-stmt:
    # var stmt/esi: (addr statement)
    68/push 0/imm32/no-outputs
    68/push 0/imm32/no-outputs
    53/push-ebx/inouts
    68/push 0x11/imm32/alloc-id:fake
    68/push 0/imm32/operation
    68/push 0/imm32/operation
    68/push 1/imm32/tag
    89/<- %esi 4/r32/esp
$test-emit-subx-function-call-with-literal-arg:initialize-stmt-operation:
    # stmt->operation = "f"
    8d/copy-address *(esi+4) 0/r32/eax  # Stmt1-operation
    (copy-array Heap "f" %eax)
    # convert
    c7 0/subop/copy *Curr-block-depth 0/imm32
    (emit-subx-stmt _test-output-buffered-file %esi 0 %ebx Stderr 0)
    (flush _test-output-buffered-file)
#?     # dump _test-output-stream {{{
#?     (write 2 "^")
#?     (write-stream 2 _test-output-stream)
#?     (write 2 "$\n")
#?     (rewind-stream _test-output-stream)
#?     # }}}
    # check output
    (check-next-stream-line-equal _test-output-stream "(f 0x34)" "F - test-emit-subx-stmt-function-call-with-literal-arg")
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

emit-indent:  # out: (addr buffered-file), n: int
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    # var i/eax: int = n
    8b/-> *(ebp+0xc) 0/r32/eax
    {
      # if (i <= 0) break
      3d/compare-eax-with 0/imm32
      7e/jump-if-<= break/disp8
      (write-buffered *(ebp+8) "  ")
      48/decrement-eax
      eb/jump loop/disp8
    }
$emit-indent:end:
    # . restore registers
    58/pop-to-eax
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

emit-subx-prologue:  # out: (addr buffered-file)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    #
    (write-buffered *(ebp+8) "  # . prologue\n")
    (write-buffered *(ebp+8) "  55/push-ebp\n")
    (write-buffered *(ebp+8) "  89/<- %ebp 4/r32/esp\n")
$emit-subx-prologue:end:
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

emit-subx-epilogue:  # out: (addr buffered-file)
    # . prologue
    55/push-ebp
    89/<- %ebp 4/r32/esp
    #
    (write-buffered *(ebp+8) "  # . epilogue\n")
    (write-buffered *(ebp+8) "  89/<- %esp 5/r32/ebp\n")
    (write-buffered *(ebp+8) "  5d/pop-to-ebp\n")
    (write-buffered *(ebp+8) "  c3/return\n")
$emit-subx-epilogue:end:
    # . epilogue
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return