@@ -7,7 +7,7 @@ mod returning;
77use std:: borrow:: Cow ;
88use std:: mem;
99
10- use cranelift_codegen:: ir:: { ArgumentPurpose , SigRef } ;
10+ use cranelift_codegen:: ir:: { ArgumentPurpose , BlockArg , ExceptionTableData , ExceptionTag , SigRef } ;
1111use cranelift_codegen:: isa:: CallConv ;
1212use cranelift_module:: ModuleError ;
1313use rustc_abi:: { CanonAbi , ExternAbi , X86Call } ;
@@ -20,10 +20,12 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
2020use rustc_session:: Session ;
2121use rustc_span:: source_map:: Spanned ;
2222use rustc_target:: callconv:: { FnAbi , PassMode } ;
23- use smallvec:: SmallVec ;
23+ use smallvec:: { SmallVec , smallvec } ;
2424
2525use self :: pass_mode:: * ;
2626pub ( crate ) use self :: returning:: codegen_return;
27+ use crate :: base:: codegen_unwind_terminate;
28+ use crate :: debuginfo:: EXCEPTION_HANDLER_CLEANUP ;
2729use crate :: prelude:: * ;
2830
2931fn clif_sig_from_fn_abi < ' tcx > (
@@ -380,7 +382,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
380382 args : & [ Spanned < Operand < ' tcx > > ] ,
381383 destination : Place < ' tcx > ,
382384 target : Option < BasicBlock > ,
383- _unwind : UnwindAction ,
385+ unwind : UnwindAction ,
384386) {
385387 let func = codegen_operand ( fx, func) ;
386388 let fn_sig = func. layout ( ) . ty . fn_sig ( fx. tcx ) ;
@@ -515,12 +517,6 @@ pub(crate) fn codegen_terminator_call<'tcx>(
515517 let args = args;
516518 assert_eq ! ( fn_abi. args. len( ) , args. len( ) ) ;
517519
518- #[ derive( Copy , Clone ) ]
519- enum CallTarget {
520- Direct ( FuncRef ) ,
521- Indirect ( SigRef , Value ) ,
522- }
523-
524520 let ( func_ref, first_arg_override) = match instance {
525521 // Trait object call
526522 Some ( Instance { def : InstanceKind :: Virtual ( _, idx) , .. } ) => {
@@ -582,18 +578,12 @@ pub(crate) fn codegen_terminator_call<'tcx>(
582578 adjust_call_for_c_variadic ( fx, & fn_abi, source_info, func_ref, & mut call_args) ;
583579 }
584580
585- let call_inst = match func_ref {
586- CallTarget :: Direct ( func_ref) => fx. bcx . ins ( ) . call ( func_ref, & call_args) ,
587- CallTarget :: Indirect ( sig, func_ptr) => {
588- fx. bcx . ins ( ) . call_indirect ( sig, func_ptr, & call_args)
589- }
590- } ;
591-
592581 if fx. clif_comments . enabled ( ) {
593- with_no_trimmed_paths ! ( fx. add_comment( call_inst, format!( "abi: {:?}" , fn_abi) ) ) ;
582+ let nop_inst = fx. bcx . ins ( ) . nop ( ) ;
583+ with_no_trimmed_paths ! ( fx. add_post_comment( nop_inst, format!( "abi: {:?}" , fn_abi) ) ) ;
594584 }
595585
596- fx . bcx . func . dfg . inst_results ( call_inst ) . iter ( ) . copied ( ) . collect :: < SmallVec < [ Value ; 2 ] > > ( )
586+ codegen_call_with_unwind_action ( fx , source_info . span , func_ref , unwind , & call_args , None )
597587 } ) ;
598588
599589 if let Some ( dest) = target {
@@ -703,7 +693,7 @@ pub(crate) fn codegen_drop<'tcx>(
703693 source_info : mir:: SourceInfo ,
704694 drop_place : CPlace < ' tcx > ,
705695 target : BasicBlock ,
706- _unwind : UnwindAction ,
696+ unwind : UnwindAction ,
707697) {
708698 let ty = drop_place. layout ( ) . ty ;
709699 let drop_instance = Instance :: resolve_drop_in_place ( fx. tcx , ty) ;
@@ -749,9 +739,14 @@ pub(crate) fn codegen_drop<'tcx>(
749739
750740 let sig = clif_sig_from_fn_abi ( fx. tcx , fx. target_config . default_call_conv , & fn_abi) ;
751741 let sig = fx. bcx . import_signature ( sig) ;
752- // FIXME implement cleanup on exceptions
753- fx. bcx . ins ( ) . call_indirect ( sig, drop_fn, & [ ptr] ) ;
754- fx. bcx . ins ( ) . jump ( ret_block, & [ ] ) ;
742+ codegen_call_with_unwind_action (
743+ fx,
744+ source_info. span ,
745+ CallTarget :: Indirect ( sig, drop_fn) ,
746+ unwind,
747+ & [ ptr] ,
748+ Some ( ret_block) ,
749+ ) ;
755750 }
756751 ty:: Dynamic ( _, _, ty:: DynStar ) => {
757752 // IN THIS ARM, WE HAVE:
@@ -794,9 +789,14 @@ pub(crate) fn codegen_drop<'tcx>(
794789
795790 let sig = clif_sig_from_fn_abi ( fx. tcx , fx. target_config . default_call_conv , & fn_abi) ;
796791 let sig = fx. bcx . import_signature ( sig) ;
797- fx. bcx . ins ( ) . call_indirect ( sig, drop_fn, & [ data] ) ;
798- // FIXME implement cleanup on exceptions
799- fx. bcx . ins ( ) . jump ( ret_block, & [ ] ) ;
792+ codegen_call_with_unwind_action (
793+ fx,
794+ source_info. span ,
795+ CallTarget :: Indirect ( sig, drop_fn) ,
796+ unwind,
797+ & [ data] ,
798+ Some ( ret_block) ,
799+ ) ;
800800 }
801801 _ => {
802802 assert ! ( !matches!( drop_instance. def, InstanceKind :: Virtual ( _, _) ) ) ;
@@ -821,9 +821,132 @@ pub(crate) fn codegen_drop<'tcx>(
821821 }
822822
823823 let func_ref = fx. get_function_ref ( drop_instance) ;
824- fx. bcx . ins ( ) . call ( func_ref, & call_args) ;
825- // FIXME implement cleanup on exceptions
826- fx. bcx . ins ( ) . jump ( ret_block, & [ ] ) ;
824+ codegen_call_with_unwind_action (
825+ fx,
826+ source_info. span ,
827+ CallTarget :: Direct ( func_ref) ,
828+ unwind,
829+ & call_args,
830+ Some ( ret_block) ,
831+ ) ;
832+ }
833+ }
834+ }
835+ }
836+
837+ #[ derive( Copy , Clone ) ]
838+ pub ( crate ) enum CallTarget {
839+ Direct ( FuncRef ) ,
840+ Indirect ( SigRef , Value ) ,
841+ }
842+
843+ pub ( crate ) fn codegen_call_with_unwind_action (
844+ fx : & mut FunctionCx < ' _ , ' _ , ' _ > ,
845+ span : Span ,
846+ func_ref : CallTarget ,
847+ unwind : UnwindAction ,
848+ call_args : & [ Value ] ,
849+ target_block : Option < Block > ,
850+ ) -> SmallVec < [ Value ; 2 ] > {
851+ let sig_ref = match func_ref {
852+ CallTarget :: Direct ( func_ref) => fx. bcx . func . dfg . ext_funcs [ func_ref] . signature ,
853+ CallTarget :: Indirect ( sig_ref, _func_ptr) => sig_ref,
854+ } ;
855+
856+ if target_block. is_some ( ) {
857+ assert ! ( fx. bcx. func. dfg. signatures[ sig_ref] . returns. is_empty( ) ) ;
858+ }
859+ match unwind {
860+ UnwindAction :: Continue | UnwindAction :: Unreachable => {
861+ let call_inst = match func_ref {
862+ CallTarget :: Direct ( func_ref) => fx. bcx . ins ( ) . call ( func_ref, & call_args) ,
863+ CallTarget :: Indirect ( sig, func_ptr) => {
864+ fx. bcx . ins ( ) . call_indirect ( sig, func_ptr, & call_args)
865+ }
866+ } ;
867+
868+ if let Some ( target_block) = target_block {
869+ fx. bcx . ins ( ) . jump ( target_block, & [ ] ) ;
870+ smallvec ! [ ]
871+ } else {
872+ fx. bcx
873+ . func
874+ . dfg
875+ . inst_results ( call_inst)
876+ . iter ( )
877+ . copied ( )
878+ . collect :: < SmallVec < [ Value ; 2 ] > > ( )
879+ }
880+ }
881+ UnwindAction :: Cleanup ( _) | UnwindAction :: Terminate ( _) => {
882+ let returns_types = fx. bcx . func . dfg . signatures [ sig_ref]
883+ . returns
884+ . iter ( )
885+ . map ( |return_param| return_param. value_type )
886+ . collect :: < Vec < _ > > ( ) ;
887+
888+ let fallthrough_block = fx. bcx . create_block ( ) ;
889+ let fallthrough_block_call_args = returns_types
890+ . iter ( )
891+ . enumerate ( )
892+ . map ( |( i, _) | BlockArg :: TryCallRet ( i. try_into ( ) . unwrap ( ) ) )
893+ . collect :: < Vec < _ > > ( ) ;
894+ let fallthrough_block_call = fx. bcx . func . dfg . block_call (
895+ target_block. unwrap_or ( fallthrough_block) ,
896+ & fallthrough_block_call_args,
897+ ) ;
898+ let pre_cleanup_block = fx. bcx . create_block ( ) ;
899+ let pre_cleanup_block_call =
900+ fx. bcx . func . dfg . block_call ( pre_cleanup_block, & [ BlockArg :: TryCallExn ( 0 ) ] ) ;
901+ let exception_table = fx. bcx . func . dfg . exception_tables . push ( ExceptionTableData :: new (
902+ sig_ref,
903+ fallthrough_block_call,
904+ [ (
905+ Some ( ExceptionTag :: with_number ( EXCEPTION_HANDLER_CLEANUP ) . unwrap ( ) ) ,
906+ pre_cleanup_block_call,
907+ ) ] ,
908+ ) ) ;
909+
910+ match func_ref {
911+ CallTarget :: Direct ( func_ref) => {
912+ fx. bcx . ins ( ) . try_call ( func_ref, & call_args, exception_table) ;
913+ }
914+ CallTarget :: Indirect ( _sig, func_ptr) => {
915+ fx. bcx . ins ( ) . try_call_indirect ( func_ptr, & call_args, exception_table) ;
916+ }
917+ }
918+
919+ fx. bcx . seal_block ( pre_cleanup_block) ;
920+ fx. bcx . switch_to_block ( pre_cleanup_block) ;
921+ fx. bcx . set_cold_block ( pre_cleanup_block) ;
922+ match unwind {
923+ UnwindAction :: Continue | UnwindAction :: Unreachable => unreachable ! ( ) ,
924+ UnwindAction :: Cleanup ( cleanup) => {
925+ let exception_ptr =
926+ fx. bcx . append_block_param ( pre_cleanup_block, fx. pointer_type ) ;
927+ fx. bcx . def_var ( fx. exception_slot , exception_ptr) ;
928+ let cleanup_block = fx. get_block ( cleanup) ;
929+ fx. bcx . ins ( ) . jump ( cleanup_block, & [ ] ) ;
930+ }
931+ UnwindAction :: Terminate ( reason) => {
932+ // FIXME dedup terminate blocks
933+ fx. bcx . append_block_param ( pre_cleanup_block, fx. pointer_type ) ;
934+
935+ codegen_unwind_terminate ( fx, span, reason) ;
936+ }
937+ }
938+
939+ if target_block. is_none ( ) {
940+ fx. bcx . seal_block ( fallthrough_block) ;
941+ fx. bcx . switch_to_block ( fallthrough_block) ;
942+ let returns = returns_types
943+ . into_iter ( )
944+ . map ( |ty| fx. bcx . append_block_param ( fallthrough_block, ty) )
945+ . collect ( ) ;
946+ fx. bcx . ins ( ) . nop ( ) ;
947+ returns
948+ } else {
949+ smallvec ! [ ]
827950 }
828951 }
829952 }
0 commit comments