@@ -330,7 +330,17 @@ impl<'ll> FunctionSignature<'ll> {
330
330
pub ( crate ) trait FnAbiLlvmExt < ' ll , ' tcx > {
331
331
fn llvm_return_type ( & self , cx : & CodegenCx < ' ll , ' tcx > ) -> & ' ll Type ;
332
332
fn llvm_argument_types ( & self , cx : & CodegenCx < ' ll , ' tcx > ) -> Vec < & ' ll Type > ;
333
- fn llvm_type ( & self , cx : & CodegenCx < ' ll , ' tcx > , name : & [ u8 ] ) -> FunctionSignature < ' ll > ;
333
+ /// When `do_verify` is set, this function performs checks for the signature of LLVM intrinsics
334
+ /// and emits a fatal error if it doesn't match. These checks are important,but somewhat expensive
335
+ /// So they are only used at function definitions, not at callsites
336
+ fn llvm_type (
337
+ & self ,
338
+ cx : & CodegenCx < ' ll , ' tcx > ,
339
+ name : & [ u8 ] ,
340
+ do_verify : bool ,
341
+ ) -> FunctionSignature < ' ll > ;
342
+ /// **If this function is an LLVM intrinsic** checks if the LLVM signature provided matches with this
343
+ fn verify_intrinsic_signature ( & self , cx : & CodegenCx < ' ll , ' tcx > , llvm_ty : & ' ll Type ) -> bool ;
334
344
fn ptr_to_llvm_type ( & self , cx : & CodegenCx < ' ll , ' tcx > ) -> & ' ll Type ;
335
345
fn llvm_cconv ( & self , cx : & CodegenCx < ' ll , ' tcx > ) -> llvm:: CallConv ;
336
346
@@ -343,31 +353,25 @@ pub(crate) trait FnAbiLlvmExt<'ll, 'tcx> {
343
353
) ;
344
354
345
355
/// Apply attributes to a function call.
346
- fn apply_attrs_callsite ( & self , bx : & mut Builder < ' _ , ' ll , ' tcx > , callsite : & ' ll Value ) ;
356
+ fn apply_attrs_callsite (
357
+ & self ,
358
+ bx : & mut Builder < ' _ , ' ll , ' tcx > ,
359
+ callsite : & ' ll Value ,
360
+ llfn : & ' ll Value ,
361
+ ) ;
347
362
}
348
363
349
- /// checks that the Rust signature of a llvm intrinsic is correct
350
- fn verify_intrinsic_signature < ' ll , ' tcx > (
351
- cx : & CodegenCx < ' ll , ' tcx > ,
352
- fn_ty : & ' ll Type ,
353
- rust_return_ty : & ' ll Type ,
354
- rust_argument_tys : & [ & ' ll Type ] ,
355
- rust_is_variadic : bool ,
356
- ) -> bool {
357
- let llvm_return_ty = cx. get_return_type ( fn_ty) ;
358
- let llvm_argument_tys = cx. func_params_types ( fn_ty) ;
359
- let llvm_is_variadic = cx. func_is_variadic ( fn_ty) ;
360
-
361
- if rust_is_variadic != llvm_is_variadic || rust_argument_tys. len ( ) != llvm_argument_tys. len ( ) {
362
- return false ;
364
+ impl < ' ll , CX : Borrow < SCx < ' ll > > > GenericCx < ' ll , CX > {
365
+ pub ( crate ) fn set_intrinsic_attributes (
366
+ & self ,
367
+ intrinsic : llvm:: Intrinsic ,
368
+ llfn_or_callsite : & ' ll Value ,
369
+ ) {
370
+ unsafe {
371
+ llvm:: LLVMRustSetIntrinsicAttributes ( self . llcx ( ) , llfn_or_callsite, intrinsic. id ( ) ) ;
372
+ }
363
373
}
364
374
365
- iter:: once ( ( & rust_return_ty, & llvm_return_ty) )
366
- . chain ( iter:: zip ( rust_argument_tys, & llvm_argument_tys) )
367
- . all ( |( rust_ty, llvm_ty) | cx. equate_ty ( rust_ty, llvm_ty) )
368
- }
369
-
370
- impl < ' ll , CX : Borrow < SCx < ' ll > > > GenericCx < ' ll , CX > {
371
375
pub ( crate ) fn equate_ty ( & self , rust_ty : & ' ll Type , llvm_ty : & ' ll Type ) -> bool {
372
376
if rust_ty == llvm_ty {
373
377
return true ;
@@ -395,15 +399,32 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
395
399
}
396
400
TypeKind :: BFloat => rust_ty == self . type_i16 ( ) ,
397
401
TypeKind :: Vector => {
398
- let llvm_element_count = self . vector_length ( llvm_ty) ;
402
+ let llvm_element_count = self . vector_length ( llvm_ty) as u64 ;
399
403
let llvm_element_ty = self . element_type ( llvm_ty) ;
400
404
401
405
if llvm_element_ty == self . type_bf16 ( ) {
402
- rust_ty == self . type_vector ( self . type_i16 ( ) , llvm_element_count as u64 )
406
+ rust_ty == self . type_vector ( self . type_i16 ( ) , llvm_element_count)
407
+ } else if llvm_element_ty == self . type_i1 ( ) {
408
+ let int_width = cmp:: max ( llvm_element_count. next_power_of_two ( ) , 8 ) ;
409
+ rust_ty == self . type_ix ( int_width)
403
410
} else {
404
411
false
405
412
}
406
413
}
414
+ TypeKind :: Struct if self . type_kind ( rust_ty) == TypeKind :: Struct => {
415
+ let rust_element_tys = self . struct_element_types ( rust_ty) ;
416
+ let llvm_element_tys = self . struct_element_types ( llvm_ty) ;
417
+
418
+ if rust_element_tys. len ( ) != llvm_element_tys. len ( ) {
419
+ return false ;
420
+ }
421
+
422
+ iter:: zip ( rust_element_tys, llvm_element_tys) . all (
423
+ |( rust_element_ty, llvm_element_ty) | {
424
+ self . equate_ty ( rust_element_ty, llvm_element_ty)
425
+ } ,
426
+ )
427
+ }
407
428
_ => false ,
408
429
}
409
430
}
@@ -482,7 +503,30 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
482
503
llargument_tys
483
504
}
484
505
485
- fn llvm_type ( & self , cx : & CodegenCx < ' ll , ' tcx > , name : & [ u8 ] ) -> FunctionSignature < ' ll > {
506
+ fn verify_intrinsic_signature ( & self , cx : & CodegenCx < ' ll , ' tcx > , llvm_fn_ty : & ' ll Type ) -> bool {
507
+ let rust_return_ty = self . llvm_return_type ( cx) ;
508
+ let rust_argument_tys = self . llvm_argument_types ( cx) ;
509
+
510
+ let llvm_return_ty = cx. get_return_type ( llvm_fn_ty) ;
511
+ let llvm_argument_tys = cx. func_params_types ( llvm_fn_ty) ;
512
+ let llvm_is_variadic = cx. func_is_variadic ( llvm_fn_ty) ;
513
+
514
+ if self . c_variadic != llvm_is_variadic || rust_argument_tys. len ( ) != llvm_argument_tys. len ( )
515
+ {
516
+ return false ;
517
+ }
518
+
519
+ iter:: once ( ( rust_return_ty, llvm_return_ty) )
520
+ . chain ( iter:: zip ( rust_argument_tys, llvm_argument_tys) )
521
+ . all ( |( rust_ty, llvm_ty) | cx. equate_ty ( rust_ty, llvm_ty) )
522
+ }
523
+
524
+ fn llvm_type (
525
+ & self ,
526
+ cx : & CodegenCx < ' ll , ' tcx > ,
527
+ name : & [ u8 ] ,
528
+ do_verify : bool ,
529
+ ) -> FunctionSignature < ' ll > {
486
530
let return_ty = self . llvm_return_type ( cx) ;
487
531
let argument_tys = self . llvm_argument_types ( cx) ;
488
532
@@ -493,30 +537,15 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
493
537
if !intrinsic. is_overloaded ( ) {
494
538
// FIXME: also do this for overloaded intrinsics
495
539
let llvm_fn_ty = cx. intrinsic_type ( intrinsic, & [ ] ) ;
496
- if verify_intrinsic_signature (
497
- cx,
498
- llvm_fn_ty,
499
- return_ty,
500
- & argument_tys,
501
- self . c_variadic ,
502
- ) {
503
- return FunctionSignature :: Intrinsic ( intrinsic, llvm_fn_ty) ;
504
- } else {
505
- // FIXME: ideally we would like to hard error, but there are edge cases like `i1xN`
506
- // and differences between struct representations that we have to tackle first
507
-
508
- let rust_fn_ty = if self . c_variadic {
509
- cx. type_variadic_func ( & argument_tys, return_ty)
510
- } else {
511
- cx. type_func ( & argument_tys, return_ty)
512
- } ;
513
- cx. tcx . dcx ( ) . note ( format ! (
514
- "Intrinsic signature mismatch for `{}`: expected signature `{llvm_fn_ty:?}`, found signature `{rust_fn_ty:?}`" ,
515
- str :: from_utf8( name) . unwrap( )
516
- ) ) ;
517
- // fallback to the rust signature
518
- return FunctionSignature :: Rust ( rust_fn_ty) ;
540
+ if do_verify {
541
+ if !self . verify_intrinsic_signature ( cx, llvm_fn_ty) {
542
+ cx. tcx . dcx ( ) . fatal ( format ! (
543
+ "Intrinsic signature mismatch for `{}`: expected signature `{llvm_fn_ty:?}`" ,
544
+ str :: from_utf8( name) . unwrap( )
545
+ ) ) ;
546
+ }
519
547
}
548
+ return FunctionSignature :: Intrinsic ( intrinsic, llvm_fn_ty) ;
520
549
}
521
550
} else {
522
551
// it's one of 2 cases,
@@ -674,7 +703,24 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
674
703
}
675
704
}
676
705
677
- fn apply_attrs_callsite ( & self , bx : & mut Builder < ' _ , ' ll , ' tcx > , callsite : & ' ll Value ) {
706
+ fn apply_attrs_callsite (
707
+ & self ,
708
+ bx : & mut Builder < ' _ , ' ll , ' tcx > ,
709
+ callsite : & ' ll Value ,
710
+ llfn : & ' ll Value ,
711
+ ) {
712
+ // if we are using the LLVM signature, use the LLVM attributes otherwise it might be problematic
713
+ let name = llvm:: get_value_name ( llfn) ;
714
+ if name. starts_with ( b"llvm." )
715
+ && let Some ( intrinsic) = llvm:: Intrinsic :: lookup ( name)
716
+ {
717
+ // FIXME: also do this for overloaded intrinsics
718
+ if !intrinsic. is_overloaded ( ) {
719
+ bx. set_intrinsic_attributes ( intrinsic, callsite) ;
720
+ return ;
721
+ }
722
+ }
723
+
678
724
let mut func_attrs = SmallVec :: < [ _ ; 2 ] > :: new ( ) ;
679
725
if self . ret . layout . is_uninhabited ( ) {
680
726
func_attrs. push ( llvm:: AttributeKind :: NoReturn . create_attr ( bx. cx . llcx ) ) ;
0 commit comments