Emit trunc nuw
for unchecked shifts and to_immediate_scalar
- For shifts this shrinks the IR by no longer needing an `assume` while still providing the UB information - Having this on the `i8`→`i1` truncations will hopefully help with some places that have to load `i8`s or pass those in LLVM structs without range information
This commit is contained in:
parent
ed49386d3a
commit
511bf307f0
10 changed files with 77 additions and 50 deletions
|
@ -24,7 +24,7 @@ use rustc_middle::query::Providers;
|
|||
use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType};
|
||||
use rustc_session::config::{self, CrateType, EntryFnType, OutputType};
|
||||
use rustc_span::{DUMMY_SP, Symbol, sym};
|
||||
use rustc_trait_selection::infer::{BoundRegionConversionTime, TyCtxtInferExt};
|
||||
use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
|
||||
|
@ -364,13 +364,7 @@ pub(crate) fn build_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
let rhs_sz = bx.cx().int_width(rhs_llty);
|
||||
let lhs_sz = bx.cx().int_width(lhs_llty);
|
||||
if lhs_sz < rhs_sz {
|
||||
if is_unchecked && bx.sess().opts.optimize != OptLevel::No {
|
||||
// FIXME: Use `trunc nuw` once that's available
|
||||
let inrange = bx.icmp(IntPredicate::IntULE, rhs, mask);
|
||||
bx.assume(inrange);
|
||||
}
|
||||
|
||||
bx.trunc(rhs, lhs_llty)
|
||||
if is_unchecked { bx.unchecked_utrunc(rhs, lhs_llty) } else { bx.trunc(rhs, lhs_llty) }
|
||||
} else if lhs_sz > rhs_sz {
|
||||
// We zero-extend even if the RHS is signed. So e.g. `(x: i32) << -1i8` will zero-extend the
|
||||
// RHS to `255i32`. But then we mask the shift amount to be within the size of the LHS
|
||||
|
|
|
@ -340,6 +340,17 @@ pub trait BuilderMethods<'a, 'tcx>:
|
|||
}
|
||||
|
||||
fn trunc(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
|
||||
/// Produces the same value as [`Self::trunc`] (and defaults to that),
|
||||
/// but is UB unless the *zero*-extending the result can reproduce `val`.
|
||||
fn unchecked_utrunc(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value {
|
||||
self.trunc(val, dest_ty)
|
||||
}
|
||||
/// Produces the same value as [`Self::trunc`] (and defaults to that),
|
||||
/// but is UB unless the *sign*-extending the result can reproduce `val`.
|
||||
fn unchecked_strunc(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value {
|
||||
self.trunc(val, dest_ty)
|
||||
}
|
||||
|
||||
fn sext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
|
||||
fn fptoui_sat(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
|
||||
fn fptosi_sat(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue