@@ -4,7 +4,7 @@ use std::{iter, ptr};
44
55pub ( crate ) mod autodiff;
66
7- use libc:: { c_char, c_uint} ;
7+ use libc:: { c_char, c_uint, size_t } ;
88use rustc_abi as abi;
99use rustc_abi:: { Align , Size , WrappingRange } ;
1010use rustc_codegen_ssa:: MemFlags ;
@@ -32,7 +32,7 @@ use crate::abi::FnAbiLlvmExt;
3232use crate :: attributes;
3333use crate :: common:: Funclet ;
3434use 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 } ;
3636use crate :: type_:: Type ;
3737use crate :: type_of:: LayoutLlvmExt ;
3838use crate :: value:: Value ;
@@ -333,6 +333,50 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
333333 }
334334 }
335335
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+
336380 fn invoke (
337381 & mut self ,
338382 llty : & ' ll Type ,
0 commit comments