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