Skip to content

Commit 537d59e

Browse files
committed
Replace hints with optimized code generation.
1 parent cd9662b commit 537d59e

File tree

2 files changed

+83
-75
lines changed

2 files changed

+83
-75
lines changed

compiler/rustc_codegen_ssa/src/mir/rvalue.rs

+80-57
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ use crate::MemFlags;
99

1010
use rustc_hir as hir;
1111
use rustc_middle::mir::{self, AggregateKind, Operand};
12-
use rustc_middle::ty::cast::{CastTy, IntTy};
1312
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
1413
use rustc_middle::ty::{self, adjustment::PointerCoercion, Instance, Ty, TyCtxt};
1514
use rustc_middle::{bug, span_bug};
@@ -237,21 +236,21 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
237236
}
238237
}
239238
OperandValue::Immediate(imm) => {
240-
let OperandValueKind::Immediate(in_scalar) = operand_kind else {
239+
let OperandValueKind::Immediate(from_scalar) = operand_kind else {
241240
bug!("Found {operand_kind:?} for operand {operand:?}");
242241
};
243-
if let OperandValueKind::Immediate(out_scalar) = cast_kind
244-
&& in_scalar.size(self.cx) == out_scalar.size(self.cx)
242+
if let OperandValueKind::Immediate(to_scalar) = cast_kind
243+
&& from_scalar.size(self.cx) == to_scalar.size(self.cx)
245244
{
246-
let operand_bty = bx.backend_type(operand.layout);
247-
let cast_bty = bx.backend_type(cast);
245+
let from_backend_ty = bx.backend_type(operand.layout);
246+
let to_backend_ty = bx.backend_type(cast);
248247
Some(OperandValue::Immediate(self.transmute_immediate(
249248
bx,
250249
imm,
251-
in_scalar,
252-
operand_bty,
253-
out_scalar,
254-
cast_bty,
250+
from_scalar,
251+
from_backend_ty,
252+
to_scalar,
253+
to_backend_ty,
255254
)))
256255
} else {
257256
None
@@ -280,6 +279,59 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
280279
}
281280
}
282281

282+
/// Cast one of the immediates from an [`OperandValue::Immediate`]
283+
/// or an [`OperandValue::Pair`] to an immediate of the target type.
284+
fn cast_immediate(
285+
&self,
286+
bx: &mut Bx,
287+
mut imm: Bx::Value,
288+
from_scalar: abi::Scalar,
289+
from_backend_ty: Bx::Type,
290+
to_scalar: abi::Scalar,
291+
to_backend_ty: Bx::Type,
292+
) -> Option<Bx::Value> {
293+
use abi::Primitive::*;
294+
295+
// When scalars are passed by value, there's no metadata recording their
296+
// valid ranges. For example, `char`s are passed as just `i32`, with no
297+
// way for LLVM to know that they're 0x10FFFF at most. Thus we assume
298+
// the range of the input value too, not just the output range.
299+
self.assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
300+
301+
imm = match (from_scalar.primitive(), to_scalar.primitive()) {
302+
(Int(_, is_signed), Int(..)) => bx.intcast(imm, to_backend_ty, is_signed),
303+
(F16 | F32 | F64 | F128, F16 | F32 | F64 | F128) => {
304+
let srcsz = bx.cx().float_width(from_backend_ty);
305+
let dstsz = bx.cx().float_width(to_backend_ty);
306+
if dstsz > srcsz {
307+
bx.fpext(imm, to_backend_ty)
308+
} else if srcsz > dstsz {
309+
bx.fptrunc(imm, to_backend_ty)
310+
} else {
311+
imm
312+
}
313+
}
314+
(Int(_, is_signed), F16 | F32 | F64 | F128) => {
315+
if is_signed {
316+
bx.sitofp(imm, to_backend_ty)
317+
} else {
318+
bx.uitofp(imm, to_backend_ty)
319+
}
320+
}
321+
(Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty),
322+
(Int(_, is_signed), Pointer(..)) => {
323+
let usize_imm = bx.intcast(imm, bx.cx().type_isize(), is_signed);
324+
bx.inttoptr(usize_imm, to_backend_ty)
325+
}
326+
(F16 | F32 | F64 | F128, Int(_, is_signed)) => {
327+
bx.cast_float_to_int(is_signed, imm, to_backend_ty)
328+
}
329+
_ => return None,
330+
};
331+
self.assume_scalar_range(bx, imm, to_scalar, to_backend_ty);
332+
Some(imm)
333+
}
334+
283335
/// Transmutes one of the immediates from an [`OperandValue::Immediate`]
284336
/// or an [`OperandValue::Pair`] to an immediate of the target type.
285337
///
@@ -508,62 +560,33 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
508560
| mir::CastKind::IntToFloat
509561
| mir::CastKind::PtrToPtr
510562
| mir::CastKind::FnPtrToPtr
511-
512563
// Since int2ptr can have arbitrary integer types as input (so we have to do
513564
// sign extension and all that), it is currently best handled in the same code
514565
// path as the other integer-to-X casts.
515566
| mir::CastKind::PointerWithExposedProvenance => {
567+
let imm = operand.immediate();
568+
let operand_kind = self.value_kind(operand.layout);
569+
let OperandValueKind::Immediate(from_scalar) = operand_kind else {
570+
bug!("Found {operand_kind:?} for operand {operand:?}");
571+
};
572+
let from_backend_ty = bx.cx().immediate_backend_type(operand.layout);
573+
516574
assert!(bx.cx().is_backend_immediate(cast));
517-
let ll_t_out = bx.cx().immediate_backend_type(cast);
575+
let to_backend_ty = bx.cx().immediate_backend_type(cast);
518576
if operand.layout.abi.is_uninhabited() {
519-
let val = OperandValue::Immediate(bx.cx().const_poison(ll_t_out));
577+
let val = OperandValue::Immediate(bx.cx().const_poison(to_backend_ty));
520578
return OperandRef { val, layout: cast };
521579
}
522-
let r_t_in =
523-
CastTy::from_ty(operand.layout.ty).expect("bad input type for cast");
524-
let r_t_out = CastTy::from_ty(cast.ty).expect("bad output type for cast");
525-
let ll_t_in = bx.cx().immediate_backend_type(operand.layout);
526-
let llval = operand.immediate();
527-
528-
let newval = match (r_t_in, r_t_out) {
529-
(CastTy::Int(i), CastTy::Int(_)) => {
530-
bx.intcast(llval, ll_t_out, i.is_signed())
531-
}
532-
(CastTy::Float, CastTy::Float) => {
533-
let srcsz = bx.cx().float_width(ll_t_in);
534-
let dstsz = bx.cx().float_width(ll_t_out);
535-
if dstsz > srcsz {
536-
bx.fpext(llval, ll_t_out)
537-
} else if srcsz > dstsz {
538-
bx.fptrunc(llval, ll_t_out)
539-
} else {
540-
llval
541-
}
542-
}
543-
(CastTy::Int(i), CastTy::Float) => {
544-
if i.is_signed() {
545-
bx.sitofp(llval, ll_t_out)
546-
} else {
547-
bx.uitofp(llval, ll_t_out)
548-
}
549-
}
550-
(CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Ptr(_)) => {
551-
bx.pointercast(llval, ll_t_out)
552-
}
553-
(CastTy::Int(i), CastTy::Ptr(_)) => {
554-
let usize_llval =
555-
bx.intcast(llval, bx.cx().type_isize(), i.is_signed());
556-
bx.inttoptr(usize_llval, ll_t_out)
557-
}
558-
(CastTy::Float, CastTy::Int(IntTy::I)) => {
559-
bx.cast_float_to_int(true, llval, ll_t_out)
560-
}
561-
(CastTy::Float, CastTy::Int(_)) => {
562-
bx.cast_float_to_int(false, llval, ll_t_out)
563-
}
564-
_ => bug!("unsupported cast: {:?} to {:?}", operand.layout.ty, cast.ty),
580+
let cast_kind = self.value_kind(cast);
581+
let OperandValueKind::Immediate(to_scalar) = cast_kind else {
582+
bug!("Found {cast_kind:?} for operand {cast:?}");
565583
};
566-
OperandValue::Immediate(newval)
584+
585+
self.cast_immediate(bx, imm, from_scalar, from_backend_ty, to_scalar, to_backend_ty)
586+
.map(OperandValue::Immediate)
587+
.unwrap_or_else(|| {
588+
bug!("Unsupported cast of {operand:?} to {cast:?}");
589+
})
567590
}
568591
mir::CastKind::Transmute => {
569592
self.codegen_transmute_operand(bx, operand, cast).unwrap_or_else(|| {

library/core/src/char/convert.rs

+3-18
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,7 @@ impl From<char> for u32 {
4848
/// ```
4949
#[inline]
5050
fn from(c: char) -> Self {
51-
let c = c as Self;
52-
53-
// SAFETY: `char::MAX` is the highest valid Unicode code point.
54-
unsafe { core::hint::assert_unchecked(c <= char::MAX as Self) };
55-
56-
c
51+
c as Self
5752
}
5853
}
5954

@@ -74,12 +69,7 @@ impl From<char> for u64 {
7469
fn from(c: char) -> Self {
7570
// The char is casted to the value of the code point, then zero-extended to 64 bit.
7671
// See [https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics]
77-
let c = c as Self;
78-
79-
// SAFETY: `char::MAX` is the highest valid Unicode code point.
80-
unsafe { core::hint::assert_unchecked(c <= char::MAX as Self) };
81-
82-
c
72+
c as Self
8373
}
8474
}
8575

@@ -100,12 +90,7 @@ impl From<char> for u128 {
10090
fn from(c: char) -> Self {
10191
// The char is casted to the value of the code point, then zero-extended to 128 bit.
10292
// See [https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics]
103-
let c = c as Self;
104-
105-
// SAFETY: `char::MAX` is the highest valid Unicode code point.
106-
unsafe { core::hint::assert_unchecked(c <= char::MAX as Self) };
107-
108-
c
93+
c as Self
10994
}
11095
}
11196

0 commit comments

Comments
 (0)