Skip to content

Commit 2edb711

Browse files
committed
Hopefully this is less work...
1. Don't downcast both parts of a pair to read just one 2. Avoid the transmute calls if it's not downcasting
1 parent 4a7039b commit 2edb711

File tree

3 files changed

+50
-33
lines changed

3 files changed

+50
-33
lines changed

compiler/rustc_abi/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1821,7 +1821,7 @@ pub enum Variants<FieldIdx: Idx, VariantIdx: Idx> {
18211821

18221822
/// Single enum variants, structs/tuples, unions, and all non-ADTs.
18231823
Single {
1824-
/// Always `0` for types that cannot have multiple variants.
1824+
/// Always [`FIRST_VARIANT`] for types that cannot have multiple variants.
18251825
index: VariantIdx,
18261826
},
18271827

compiler/rustc_codegen_ssa/src/mir/block.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::cmp;
22

3-
use rustc_abi::{Align, BackendRepr, ExternAbi, HasDataLayout, Reg, Size, WrappingRange};
3+
use rustc_abi::{Align, BackendRepr, ExternAbi, FieldIdx, HasDataLayout, Reg, Size, WrappingRange};
44
use rustc_ast as ast;
55
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
66
use rustc_data_structures::packed::Pu128;
@@ -1038,7 +1038,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
10381038
let (idx, _) = op.layout.non_1zst_field(bx).expect(
10391039
"not exactly one non-1-ZST field in a `DispatchFromDyn` type",
10401040
);
1041-
op = op.extract_field(self, bx, idx.as_usize());
1041+
op = op.extract_field(self, bx, None, idx);
10421042
}
10431043

10441044
// Now that we have `*dyn Trait` or `&dyn Trait`, split it up into its
@@ -1598,7 +1598,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
15981598
} else {
15991599
// If the tuple is immediate, the elements are as well.
16001600
for i in 0..tuple.layout.fields.count() {
1601-
let op = tuple.extract_field(self, bx, i);
1601+
let op = tuple.extract_field(self, bx, None, FieldIdx::from_usize(i));
16021602
self.codegen_argument(bx, op, llargs, &args[i], lifetime_ends_after_call);
16031603
}
16041604
}

compiler/rustc_codegen_ssa/src/mir/operand.rs

Lines changed: 46 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -319,16 +319,40 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
319319
OperandRef { val, layout }
320320
}
321321

322+
/// Extracts field `field_idx` from `self`, after downcasting to
323+
/// `downcast_variant` if it's specified.
324+
///
325+
/// Reading from things like tuples or structs, which are always single-variant,
326+
/// don't need to pass a downcast variant since downcasting them to
327+
/// `FIRST_VARIANT` doesn't actually change anything.
328+
/// Things like enums and coroutines, though, must pass the variant from which
329+
/// they want to read unless they're specifically reading the tag field
330+
/// (which is the index at the type level, not inside one of the variants).
322331
pub(crate) fn extract_field<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
323332
&self,
324333
fx: &mut FunctionCx<'a, 'tcx, Bx>,
325334
bx: &mut Bx,
326-
i: usize,
335+
downcast_variant: Option<VariantIdx>,
336+
field_idx: FieldIdx,
327337
) -> Self {
328-
let field = self.layout.field(bx.cx(), i);
329-
let offset = self.layout.fields.offset(i);
338+
let layout = if let Some(vidx) = downcast_variant {
339+
self.layout.for_variant(bx.cx(), vidx)
340+
} else {
341+
debug_assert!(
342+
match self.layout.variants {
343+
Variants::Empty => true,
344+
Variants::Single { index } => index == FIRST_VARIANT,
345+
Variants::Multiple { tag_field, .. } => tag_field == field_idx,
346+
},
347+
"Should have specified a variant to read field {field_idx:?} of {self:?}",
348+
);
349+
self.layout
350+
};
330351

331-
if !bx.is_backend_ref(self.layout) && bx.is_backend_ref(field) {
352+
let field = layout.field(bx.cx(), field_idx.as_usize());
353+
let offset = layout.fields.offset(field_idx.as_usize());
354+
355+
if !bx.is_backend_ref(layout) && bx.is_backend_ref(field) {
332356
// Part of https://github.com/rust-lang/compiler-team/issues/838
333357
span_bug!(
334358
fx.mir.span,
@@ -338,18 +362,22 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
338362

339363
let val = if field.is_zst() {
340364
OperandValue::ZeroSized
341-
} else if let BackendRepr::SimdVector { .. } = self.layout.backend_repr {
365+
} else if let BackendRepr::SimdVector { .. } = layout.backend_repr {
342366
// codegen_transmute_operand doesn't support SIMD, but since the previous
343367
// check handled ZSTs, the only possible field access into something SIMD
344368
// is to the `non_1zst_field` that's the same SIMD. (Other things, even
345369
// just padding, would change the wrapper's representation type.)
346-
assert_eq!(field.size, self.layout.size);
370+
assert_eq!(field.size, layout.size);
347371
self.val
348-
} else if field.size == self.layout.size {
349-
assert_eq!(offset.bytes(), 0);
350-
fx.codegen_transmute_operand(bx, *self, field)
372+
} else if field.size == layout.size {
373+
debug_assert_eq!(offset.bytes(), 0);
374+
if downcast_variant.is_some() {
375+
fx.codegen_transmute_operand(bx, *self, field)
376+
} else {
377+
self.val
378+
}
351379
} else {
352-
let (in_scalar, imm) = match (self.val, self.layout.backend_repr) {
380+
let (in_scalar, imm) = match (self.val, layout.backend_repr) {
353381
// Extract a scalar component from a pair.
354382
(OperandValue::Pair(a_llval, b_llval), BackendRepr::ScalarPair(a, b)) => {
355383
// This needs to look at `offset`, rather than `i`, because
@@ -371,19 +399,18 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
371399
}
372400
};
373401
OperandValue::Immediate(match field.backend_repr {
374-
BackendRepr::SimdVector { .. } => imm,
375-
BackendRepr::Scalar(out_scalar) => {
402+
BackendRepr::Scalar(out_scalar) if downcast_variant.is_some() => {
376403
// For a type like `Result<usize, &u32>` the layout is `Pair(i64, ptr)`.
377404
// But if we're reading the `Ok` payload, we need to turn that `ptr`
378405
// back into an integer. To avoid repeating logic we do that by
379406
// calling the transmute code, which is legal thanks to the size
380407
// assert we did when pulling it out of the pair.
381408
transmute_scalar(bx, imm, in_scalar, out_scalar)
382409
}
410+
BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => imm,
383411
BackendRepr::ScalarPair(_, _) | BackendRepr::Memory { .. } => bug!(),
384412
})
385413
};
386-
387414
OperandRef { val, layout: field }
388415
}
389416

@@ -431,7 +458,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
431458
let tag_op = match self.val {
432459
OperandValue::ZeroSized => bug!(),
433460
OperandValue::Immediate(_) | OperandValue::Pair(_, _) => {
434-
self.extract_field(fx, bx, tag_field.as_usize())
461+
self.extract_field(fx, bx, None, tag_field)
435462
}
436463
OperandValue::Ref(place) => {
437464
let tag = place.with_type(self.layout).project_field(bx, tag_field.as_usize());
@@ -922,6 +949,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
922949
) -> Option<OperandRef<'tcx, Bx::Value>> {
923950
debug!("maybe_codegen_consume_direct(place_ref={:?})", place_ref);
924951

952+
let mut downcast_variant = None;
925953
match self.locals[place_ref.local] {
926954
LocalRef::Operand(mut o) => {
927955
// Moves out of scalar and scalar pair fields are trivial.
@@ -933,27 +961,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
933961
"Bad PlaceRef: destructing pointers should use cast/PtrMetadata, \
934962
but tried to access field {f:?} of pointer {o:?}",
935963
);
936-
o = o.extract_field(self, bx, f.index());
964+
o = o.extract_field(self, bx, downcast_variant, f);
965+
downcast_variant = None;
937966
}
938967
mir::ProjectionElem::Downcast(_sym, variant_idx) => {
939-
let layout = o.layout.for_variant(bx.cx(), variant_idx);
940-
let val = match layout.backend_repr {
941-
// The transmute here handles cases like `Result<bool, u8>`
942-
// where the immediate values need to change for
943-
// the specific types in the cast-to variant.
944-
BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..) => {
945-
self.codegen_transmute_operand(bx, o, layout)
946-
}
947-
BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => {
948-
o.val
949-
}
950-
};
951-
952-
o = OperandRef { val, layout };
968+
downcast_variant = Some(variant_idx);
953969
}
954970
_ => return None,
955971
}
956972
}
973+
debug_assert_eq!(downcast_variant, None);
957974

958975
Some(o)
959976
}

0 commit comments

Comments
 (0)