@@ -5,7 +5,7 @@ use crate::back::write::{
55 compute_per_cgu_lto_type, start_async_codegen, submit_codegened_module_to_llvm,
66 submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm, ComputedLtoType , OngoingCodegen ,
77} ;
8- use crate :: common:: { IntPredicate , RealPredicate , TypeKind } ;
8+ use crate :: common:: { self , IntPredicate , RealPredicate , TypeKind } ;
99use crate :: errors;
1010use crate :: meth;
1111use crate :: mir;
@@ -33,7 +33,7 @@ use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem};
3333use rustc_middle:: query:: Providers ;
3434use rustc_middle:: ty:: layout:: { HasTyCtxt , LayoutOf , TyAndLayout } ;
3535use rustc_middle:: ty:: { self , Instance , Ty , TyCtxt } ;
36- use rustc_session:: config:: { self , CrateType , EntryFnType , OutputType } ;
36+ use rustc_session:: config:: { self , CrateType , EntryFnType , OptLevel , OutputType } ;
3737use rustc_session:: Session ;
3838use rustc_span:: symbol:: sym;
3939use rustc_span:: Symbol ;
@@ -300,14 +300,32 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
300300 }
301301}
302302
303- pub fn cast_shift_expr_rhs < ' a , ' tcx , Bx : BuilderMethods < ' a , ' tcx > > (
303+ /// Shifts in MIR are all allowed to have mismatched LHS & RHS types.
304+ ///
305+ /// This does all the appropriate conversions needed to pass it to the builder's
306+ /// shift methods, which are UB for out-of-range shifts.
307+ ///
308+ /// If `is_unchecked` is false, this masks the RHS to ensure it stays in-bounds.
309+ /// For 32- and 64-bit types, this matches the semantics
310+ /// of Java. (See related discussion on #1877 and #10183.)
311+ ///
312+ /// If `is_unchecked` is true, this does no masking, and adds sufficient `assume`
313+ /// calls or operation flags to preserve as much freedom to optimize as possible.
314+ pub fn build_shift_expr_rhs < ' a , ' tcx , Bx : BuilderMethods < ' a , ' tcx > > (
304315 bx : & mut Bx ,
305316 lhs : Bx :: Value ,
306- rhs : Bx :: Value ,
317+ mut rhs : Bx :: Value ,
318+ is_unchecked : bool ,
307319) -> Bx :: Value {
308320 // Shifts may have any size int on the rhs
309321 let mut rhs_llty = bx. cx ( ) . val_ty ( rhs) ;
310322 let mut lhs_llty = bx. cx ( ) . val_ty ( lhs) ;
323+
324+ let mask = common:: shift_mask_val ( bx, lhs_llty, rhs_llty, false ) ;
325+ if !is_unchecked {
326+ rhs = bx. and ( rhs, mask) ;
327+ }
328+
311329 if bx. cx ( ) . type_kind ( rhs_llty) == TypeKind :: Vector {
312330 rhs_llty = bx. cx ( ) . element_type ( rhs_llty)
313331 }
@@ -317,6 +335,12 @@ pub fn cast_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
317335 let rhs_sz = bx. cx ( ) . int_width ( rhs_llty) ;
318336 let lhs_sz = bx. cx ( ) . int_width ( lhs_llty) ;
319337 if lhs_sz < rhs_sz {
338+ if is_unchecked && bx. sess ( ) . opts . optimize != OptLevel :: No {
339+ // FIXME: Use `trunc nuw` once that's available
340+ let inrange = bx. icmp ( IntPredicate :: IntULE , rhs, mask) ;
341+ bx. assume ( inrange) ;
342+ }
343+
320344 bx. trunc ( rhs, lhs_llty)
321345 } else if lhs_sz > rhs_sz {
322346 // We zero-extend even if the RHS is signed. So e.g. `(x: i32) << -1i8` will zero-extend the
0 commit comments