@@ -4,7 +4,7 @@ use std::{iter, ptr};
4
4
5
5
pub ( crate ) mod autodiff;
6
6
7
- use libc:: { c_char, c_uint} ;
7
+ use libc:: { c_char, c_uint, size_t } ;
8
8
use rustc_abi as abi;
9
9
use rustc_abi:: { Align , Size , WrappingRange } ;
10
10
use rustc_codegen_ssa:: MemFlags ;
@@ -32,7 +32,7 @@ use crate::abi::FnAbiLlvmExt;
32
32
use crate :: attributes;
33
33
use crate :: common:: Funclet ;
34
34
use crate :: context:: { CodegenCx , SimpleCx } ;
35
- use crate :: llvm:: { self , AtomicOrdering , AtomicRmwBinOp , BasicBlock , False , True } ;
35
+ use crate :: llvm:: { self , AtomicOrdering , AtomicRmwBinOp , BasicBlock , False , Metadata , True } ;
36
36
use crate :: type_:: Type ;
37
37
use crate :: type_of:: LayoutLlvmExt ;
38
38
use crate :: value:: Value ;
@@ -333,6 +333,50 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
333
333
}
334
334
}
335
335
336
+ fn switch_with_weights (
337
+ & mut self ,
338
+ v : Self :: Value ,
339
+ else_llbb : Self :: BasicBlock ,
340
+ else_is_cold : bool ,
341
+ cases : impl ExactSizeIterator < Item = ( u128 , Self :: BasicBlock , bool ) > ,
342
+ ) {
343
+ if self . cx . sess ( ) . opts . optimize == rustc_session:: config:: OptLevel :: No {
344
+ self . switch ( v, else_llbb, cases. map ( |( val, dest, _) | ( val, dest) ) ) ;
345
+ return ;
346
+ }
347
+
348
+ let id_str = "branch_weights" ;
349
+ let id = unsafe {
350
+ llvm:: LLVMMDStringInContext2 ( self . cx . llcx , id_str. as_ptr ( ) . cast ( ) , id_str. len ( ) )
351
+ } ;
352
+
353
+ // For switch instructions with 2 targets, the `llvm.expect` intrinsic is used.
354
+ // This function handles switch instructions with more than 2 targets and it needs to
355
+ // emit branch weights metadata instead of using the intrinsic.
356
+ // The values 1 and 2000 are the same as the values used by the `llvm.expect` intrinsic.
357
+ let cold_weight = unsafe { llvm:: LLVMValueAsMetadata ( self . cx . const_u32 ( 1 ) ) } ;
358
+ let hot_weight = unsafe { llvm:: LLVMValueAsMetadata ( self . cx . const_u32 ( 2000 ) ) } ;
359
+ let weight =
360
+ |is_cold : bool | -> & Metadata { if is_cold { cold_weight } else { hot_weight } } ;
361
+
362
+ let mut md: SmallVec < [ & Metadata ; 16 ] > = SmallVec :: with_capacity ( cases. len ( ) + 2 ) ;
363
+ md. push ( id) ;
364
+ md. push ( weight ( else_is_cold) ) ;
365
+
366
+ let switch =
367
+ unsafe { llvm:: LLVMBuildSwitch ( self . llbuilder , v, else_llbb, cases. len ( ) as c_uint ) } ;
368
+ for ( on_val, dest, is_cold) in cases {
369
+ let on_val = self . const_uint_big ( self . val_ty ( v) , on_val) ;
370
+ unsafe { llvm:: LLVMAddCase ( switch, on_val, dest) }
371
+ md. push ( weight ( is_cold) ) ;
372
+ }
373
+
374
+ unsafe {
375
+ let md_node = llvm:: LLVMMDNodeInContext2 ( self . cx . llcx , md. as_ptr ( ) , md. len ( ) as size_t ) ;
376
+ self . cx . set_metadata ( switch, llvm:: MD_prof , md_node) ;
377
+ }
378
+ }
379
+
336
380
fn invoke (
337
381
& mut self ,
338
382
llty : & ' ll Type ,
0 commit comments