1- use std:: cmp;
1+ use std:: { cmp, iter } ;
22
33use libc:: c_uint;
44use rustc_abi:: {
@@ -307,8 +307,46 @@ impl<'ll, 'tcx> ArgAbiBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
307307 }
308308}
309309
310+ pub ( crate ) enum FunctionSignature < ' ll > {
311+ /// This is an LLVM intrinsic, the signature is obtained directly from LLVM, and **may not match the Rust signature**
312+ LLVMSignature ( llvm:: Intrinsic , & ' ll Type ) ,
313+ /// This is an LLVM intrinsic, but the signature is just the Rust signature.
314+ /// FIXME: this should ideally not exist, we should be using the LLVM signature for all LLVM intrinsics
315+ RustSignature ( llvm:: Intrinsic , & ' ll Type ) ,
316+ /// The name starts with `llvm.`, but can't obtain the intrinsic ID. May be invalid or upgradable
317+ MaybeInvalid ( & ' ll Type ) ,
318+ /// Just the Rust signature
319+ NotIntrinsic ( & ' ll Type ) ,
320+ }
321+
322+ impl < ' ll > FunctionSignature < ' ll > {
323+ pub ( crate ) fn fn_ty ( & self ) -> & ' ll Type {
324+ match self {
325+ FunctionSignature :: LLVMSignature ( _, fn_ty)
326+ | FunctionSignature :: RustSignature ( _, fn_ty)
327+ | FunctionSignature :: MaybeInvalid ( fn_ty)
328+ | FunctionSignature :: NotIntrinsic ( fn_ty) => fn_ty,
329+ }
330+ }
331+
332+ pub ( crate ) fn intrinsic ( & self ) -> Option < llvm:: Intrinsic > {
333+ match self {
334+ FunctionSignature :: RustSignature ( intrinsic, _)
335+ | FunctionSignature :: LLVMSignature ( intrinsic, _) => Some ( * intrinsic) ,
336+ _ => None ,
337+ }
338+ }
339+ }
340+
310341pub ( crate ) trait FnAbiLlvmExt < ' ll , ' tcx > {
311- fn llvm_type ( & self , cx : & CodegenCx < ' ll , ' tcx > ) -> & ' ll Type ;
342+ fn llvm_return_type ( & self , cx : & CodegenCx < ' ll , ' tcx > ) -> & ' ll Type ;
343+ fn llvm_argument_types ( & self , cx : & CodegenCx < ' ll , ' tcx > ) -> Vec < & ' ll Type > ;
344+ fn llvm_type ( & self , cx : & CodegenCx < ' ll , ' tcx > , name : & [ u8 ] ) -> FunctionSignature < ' ll > ;
345+ /// The normal Rust signature for this
346+ fn rust_signature ( & self , cx : & CodegenCx < ' ll , ' tcx > ) -> & ' ll Type ;
347+ /// **If this function is an LLVM intrinsic** checks if the LLVM signature provided matches with this
348+ fn verify_intrinsic_signature ( & self , cx : & CodegenCx < ' ll , ' tcx > , llvm_ty : & ' ll Type ) -> bool ;
349+
312350 fn ptr_to_llvm_type ( & self , cx : & CodegenCx < ' ll , ' tcx > ) -> & ' ll Type ;
313351 fn llvm_cconv ( & self , cx : & CodegenCx < ' ll , ' tcx > ) -> llvm:: CallConv ;
314352
@@ -321,30 +359,39 @@ pub(crate) trait FnAbiLlvmExt<'ll, 'tcx> {
321359 ) ;
322360
323361 /// Apply attributes to a function call.
324- fn apply_attrs_callsite ( & self , bx : & mut Builder < ' _ , ' ll , ' tcx > , callsite : & ' ll Value ) ;
362+ fn apply_attrs_callsite (
363+ & self ,
364+ bx : & mut Builder < ' _ , ' ll , ' tcx > ,
365+ callsite : & ' ll Value ,
366+ llfn : & ' ll Value ,
367+ ) ;
325368}
326369
327370impl < ' ll , ' tcx > FnAbiLlvmExt < ' ll , ' tcx > for FnAbi < ' tcx , Ty < ' tcx > > {
328- fn llvm_type ( & self , cx : & CodegenCx < ' ll , ' tcx > ) -> & ' ll Type {
371+ fn llvm_return_type ( & self , cx : & CodegenCx < ' ll , ' tcx > ) -> & ' ll Type {
372+ match & self . ret . mode {
373+ PassMode :: Ignore => cx. type_void ( ) ,
374+ PassMode :: Direct ( _) | PassMode :: Pair ( ..) => self . ret . layout . immediate_llvm_type ( cx) ,
375+ PassMode :: Cast { cast, pad_i32 : _ } => cast. llvm_type ( cx) ,
376+ PassMode :: Indirect { .. } => cx. type_void ( ) ,
377+ }
378+ }
379+
380+ fn llvm_argument_types ( & self , cx : & CodegenCx < ' ll , ' tcx > ) -> Vec < & ' ll Type > {
381+ let indirect_return = matches ! ( self . ret. mode, PassMode :: Indirect { .. } ) ;
382+
329383 // Ignore "extra" args from the call site for C variadic functions.
330384 // Only the "fixed" args are part of the LLVM function signature.
331385 let args =
332386 if self . c_variadic { & self . args [ ..self . fixed_count as usize ] } else { & self . args } ;
333387
334388 // This capacity calculation is approximate.
335- let mut llargument_tys = Vec :: with_capacity (
336- self . args . len ( ) + if let PassMode :: Indirect { .. } = self . ret . mode { 1 } else { 0 } ,
337- ) ;
389+ let mut llargument_tys =
390+ Vec :: with_capacity ( args. len ( ) + if indirect_return { 1 } else { 0 } ) ;
338391
339- let llreturn_ty = match & self . ret . mode {
340- PassMode :: Ignore => cx. type_void ( ) ,
341- PassMode :: Direct ( _) | PassMode :: Pair ( ..) => self . ret . layout . immediate_llvm_type ( cx) ,
342- PassMode :: Cast { cast, pad_i32 : _ } => cast. llvm_type ( cx) ,
343- PassMode :: Indirect { .. } => {
344- llargument_tys. push ( cx. type_ptr ( ) ) ;
345- cx. type_void ( )
346- }
347- } ;
392+ if indirect_return {
393+ llargument_tys. push ( cx. type_ptr ( ) ) ;
394+ }
348395
349396 for arg in args {
350397 // Note that the exact number of arguments pushed here is carefully synchronized with
@@ -391,10 +438,56 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
391438 llargument_tys. push ( llarg_ty) ;
392439 }
393440
441+ llargument_tys
442+ }
443+
444+ fn verify_intrinsic_signature ( & self , cx : & CodegenCx < ' ll , ' tcx > , llvm_fn_ty : & ' ll Type ) -> bool {
445+ let rust_return_ty = self . llvm_return_type ( cx) ;
446+ let rust_argument_tys = self . llvm_argument_types ( cx) ;
447+
448+ let llvm_return_ty = cx. get_return_type ( llvm_fn_ty) ;
449+ let llvm_argument_tys = cx. func_params_types ( llvm_fn_ty) ;
450+ let llvm_is_variadic = cx. func_is_variadic ( llvm_fn_ty) ;
451+
452+ if self . c_variadic != llvm_is_variadic || rust_argument_tys. len ( ) != llvm_argument_tys. len ( )
453+ {
454+ return false ;
455+ }
456+
457+ iter:: once ( ( rust_return_ty, llvm_return_ty) )
458+ . chain ( iter:: zip ( rust_argument_tys, llvm_argument_tys) )
459+ . all ( |( rust_ty, llvm_ty) | rust_ty == llvm_ty)
460+ }
461+
462+ fn rust_signature ( & self , cx : & CodegenCx < ' ll , ' tcx > ) -> & ' ll Type {
463+ let return_ty = self . llvm_return_type ( cx) ;
464+ let argument_tys = self . llvm_argument_types ( cx) ;
465+
394466 if self . c_variadic {
395- cx. type_variadic_func ( & llargument_tys , llreturn_ty )
467+ cx. type_variadic_func ( & argument_tys , return_ty )
396468 } else {
397- cx. type_func ( & llargument_tys, llreturn_ty)
469+ cx. type_func ( & argument_tys, return_ty)
470+ }
471+ }
472+
473+ fn llvm_type ( & self , cx : & CodegenCx < ' ll , ' tcx > , name : & [ u8 ] ) -> FunctionSignature < ' ll > {
474+ if name. starts_with ( b"llvm." ) {
475+ if let Some ( intrinsic) = llvm:: Intrinsic :: lookup ( name) {
476+ if !intrinsic. is_overloaded ( ) {
477+ // FIXME: also do this for overloaded intrinsics
478+ FunctionSignature :: LLVMSignature ( intrinsic, intrinsic. get_type ( cx. llcx , & [ ] ) )
479+ } else {
480+ FunctionSignature :: RustSignature ( intrinsic, self . rust_signature ( cx) )
481+ }
482+ } else {
483+ // it's one of 2 cases,
484+ // - either the base name is invalid
485+ // - it has been superseded by something else, so the intrinsic was removed entirely
486+ // to check for upgrades, we need the `llfn`, so we defer it for now
487+ FunctionSignature :: MaybeInvalid ( self . rust_signature ( cx) )
488+ }
489+ } else {
490+ FunctionSignature :: NotIntrinsic ( self . rust_signature ( cx) )
398491 }
399492 }
400493
@@ -574,7 +667,17 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
574667 }
575668 }
576669
577- fn apply_attrs_callsite ( & self , bx : & mut Builder < ' _ , ' ll , ' tcx > , callsite : & ' ll Value ) {
670+ fn apply_attrs_callsite (
671+ & self ,
672+ bx : & mut Builder < ' _ , ' ll , ' tcx > ,
673+ callsite : & ' ll Value ,
674+ llfn : & ' ll Value ,
675+ ) {
676+ // Don't apply any attributes to LLVM intrinsics, they will be applied by AutoUpgrade
677+ if llvm:: get_value_name ( llfn) . starts_with ( b"llvm." ) {
678+ return ;
679+ }
680+
578681 let mut func_attrs = SmallVec :: < [ _ ; 2 ] > :: new ( ) ;
579682 if self . ret . layout . is_uninhabited ( ) {
580683 func_attrs. push ( llvm:: AttributeKind :: NoReturn . create_attr ( bx. cx . llcx ) ) ;
0 commit comments