@@ -5,7 +5,7 @@ use crate::back::write::{
5
5
compute_per_cgu_lto_type, start_async_codegen, submit_codegened_module_to_llvm,
6
6
submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm, ComputedLtoType , OngoingCodegen ,
7
7
} ;
8
- use crate :: common:: { IntPredicate , RealPredicate , TypeKind } ;
8
+ use crate :: common:: { self , IntPredicate , RealPredicate , TypeKind } ;
9
9
use crate :: errors;
10
10
use crate :: meth;
11
11
use crate :: mir;
@@ -33,7 +33,7 @@ use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem};
33
33
use rustc_middle:: query:: Providers ;
34
34
use rustc_middle:: ty:: layout:: { HasTyCtxt , LayoutOf , TyAndLayout } ;
35
35
use 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 } ;
37
37
use rustc_session:: Session ;
38
38
use rustc_span:: symbol:: sym;
39
39
use rustc_span:: Symbol ;
@@ -300,14 +300,32 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
300
300
}
301
301
}
302
302
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 > > (
304
315
bx : & mut Bx ,
305
316
lhs : Bx :: Value ,
306
- rhs : Bx :: Value ,
317
+ mut rhs : Bx :: Value ,
318
+ is_unchecked : bool ,
307
319
) -> Bx :: Value {
308
320
// Shifts may have any size int on the rhs
309
321
let mut rhs_llty = bx. cx ( ) . val_ty ( rhs) ;
310
322
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
+
311
329
if bx. cx ( ) . type_kind ( rhs_llty) == TypeKind :: Vector {
312
330
rhs_llty = bx. cx ( ) . element_type ( rhs_llty)
313
331
}
@@ -317,6 +335,12 @@ pub fn cast_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
317
335
let rhs_sz = bx. cx ( ) . int_width ( rhs_llty) ;
318
336
let lhs_sz = bx. cx ( ) . int_width ( lhs_llty) ;
319
337
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
+
320
344
bx. trunc ( rhs, lhs_llty)
321
345
} else if lhs_sz > rhs_sz {
322
346
// We zero-extend even if the RHS is signed. So e.g. `(x: i32) << -1i8` will zero-extend the
0 commit comments