@@ -14,7 +14,7 @@ use rustc_middle::{bug, span_bug};
1414use rustc_session:: config:: OptLevel ;
1515use rustc_span:: Span ;
1616use rustc_span:: source_map:: Spanned ;
17- use rustc_target:: callconv:: { ArgAbi , CastTarget , FnAbi , PassMode } ;
17+ use rustc_target:: callconv:: { ArgAbi , ArgAttributes , CastTarget , FnAbi , PassMode } ;
1818use tracing:: { debug, info} ;
1919
2020use super :: operand:: OperandRef ;
@@ -1036,6 +1036,90 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
10361036 _ => bug ! ( "{} is not callable" , callee. layout. ty) ,
10371037 } ;
10381038
1039+ if let Some ( instance) = instance
1040+ && let Some ( name) = bx. tcx ( ) . codegen_fn_attrs ( instance. def_id ( ) ) . symbol_name
1041+ && name. as_str ( ) . starts_with ( "llvm." )
1042+ {
1043+ let mut llargs = Vec :: with_capacity ( args. len ( ) ) ;
1044+
1045+ let dest_ty = destination. ty ( & self . mir . local_decls , bx. tcx ( ) ) . ty ;
1046+ let return_dest = if dest_ty. is_unit ( ) {
1047+ ReturnDest :: Nothing
1048+ } else if let Some ( index) = destination. as_local ( ) {
1049+ match self . locals [ index] {
1050+ LocalRef :: Place ( dest) => ReturnDest :: Store ( dest) ,
1051+ LocalRef :: UnsizedPlace ( _) => bug ! ( "return type must be sized" ) ,
1052+ LocalRef :: PendingOperand => {
1053+ // Handle temporary places, specifically `Operand` ones, as
1054+ // they don't have `alloca`s.
1055+ ReturnDest :: DirectOperand ( index)
1056+ }
1057+ LocalRef :: Operand ( _) => bug ! ( "place local already assigned to" ) ,
1058+ }
1059+ } else {
1060+ ReturnDest :: Store ( self . codegen_place ( bx, destination. as_ref ( ) ) )
1061+ } ;
1062+
1063+ for arg in args {
1064+ let op = self . codegen_operand ( bx, & arg. node ) ;
1065+
1066+ match op. val {
1067+ ZeroSized => { }
1068+ Immediate ( _) => llargs. push ( op. immediate ( ) ) ,
1069+ Pair ( a, b) => {
1070+ llargs. push ( a) ;
1071+ llargs. push ( b) ;
1072+ }
1073+ Ref ( op_place_val) => {
1074+ let mut llval = op_place_val. llval ;
1075+ // We can't use `PlaceRef::load` here because the argument
1076+ // may have a type we don't treat as immediate, but the ABI
1077+ // used for this call is passing it by-value. In that case,
1078+ // the load would just produce `OperandValue::Ref` instead
1079+ // of the `OperandValue::Immediate` we need for the call.
1080+ llval = bx. load ( bx. backend_type ( op. layout ) , llval, op_place_val. align ) ;
1081+ if let BackendRepr :: Scalar ( scalar) = op. layout . backend_repr {
1082+ if scalar. is_bool ( ) {
1083+ bx. range_metadata ( llval, WrappingRange { start : 0 , end : 1 } ) ;
1084+ }
1085+ // We store bools as `i8` so we need to truncate to `i1`.
1086+ llval = bx. to_immediate_scalar ( llval, scalar) ;
1087+ }
1088+ llargs. push ( llval) ;
1089+ }
1090+ }
1091+ }
1092+
1093+ let fn_ptr = bx. get_fn_addr ( instance) ;
1094+ self . set_debug_loc ( bx, source_info) ;
1095+
1096+ // FIXME remove usage of fn_abi
1097+ let fn_abi = bx. fn_abi_of_instance ( instance, ty:: List :: empty ( ) ) ;
1098+ assert ! ( !fn_abi. ret. is_indirect( ) ) ;
1099+ let fn_ty = bx. fn_decl_backend_type ( fn_abi) ;
1100+
1101+ let llret = bx. call ( fn_ty, None , None , fn_ptr, & llargs, None , None ) ;
1102+ if self . mir [ helper. bb ] . is_cleanup {
1103+ bx. apply_attrs_to_cleanup_callsite ( llret) ;
1104+ }
1105+
1106+ if let Some ( target) = target {
1107+ self . store_return (
1108+ bx,
1109+ return_dest,
1110+ & ArgAbi {
1111+ layout : bx. layout_of ( dest_ty) ,
1112+ mode : PassMode :: Direct ( ArgAttributes :: new ( ) ) ,
1113+ } ,
1114+ llret,
1115+ ) ;
1116+ return helper. funclet_br ( self , bx, target, mergeable_succ) ;
1117+ } else {
1118+ bx. unreachable ( ) ;
1119+ return MergingSucc :: False ;
1120+ }
1121+ }
1122+
10391123 // FIXME(eddyb) avoid computing this if possible, when `instance` is
10401124 // available - right now `sig` is only needed for getting the `abi`
10411125 // and figuring out how many extra args were passed to a C-variadic `fn`.
0 commit comments