@@ -126,7 +126,7 @@ pub struct OperandRef<'tcx, V> {
126
126
pub layout : TyAndLayout < ' tcx > ,
127
127
}
128
128
129
- impl < V : CodegenObject > fmt:: Debug for OperandRef < ' _ , V > {
129
+ impl < V : fmt :: Debug > fmt:: Debug for OperandRef < ' _ , V > {
130
130
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
131
131
write ! ( f, "OperandRef({:?} @ {:?})" , self . val, self . layout)
132
132
}
@@ -319,16 +319,40 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
319
319
OperandRef { val, layout }
320
320
}
321
321
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).
322
331
pub ( crate ) fn extract_field < Bx : BuilderMethods < ' a , ' tcx , Value = V > > (
323
332
& self ,
324
333
fx : & mut FunctionCx < ' a , ' tcx , Bx > ,
325
334
bx : & mut Bx ,
326
- i : usize ,
335
+ downcast_variant : Option < VariantIdx > ,
336
+ field_idx : FieldIdx ,
327
337
) -> 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
+ } ;
351
+
352
+ let field = layout. field ( bx. cx ( ) , field_idx. as_usize ( ) ) ;
353
+ let offset = layout. fields . offset ( field_idx. as_usize ( ) ) ;
330
354
331
- if !bx. is_backend_ref ( self . layout ) && bx. is_backend_ref ( field) {
355
+ if !bx. is_backend_ref ( layout) && bx. is_backend_ref ( field) {
332
356
// Part of https://github.com/rust-lang/compiler-team/issues/838
333
357
span_bug ! (
334
358
fx. mir. span,
@@ -338,27 +362,35 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
338
362
339
363
let val = if field. is_zst ( ) {
340
364
OperandValue :: ZeroSized
341
- } else if let BackendRepr :: SimdVector { .. } = self . layout . backend_repr {
365
+ } else if let BackendRepr :: SimdVector { .. } = layout. backend_repr {
342
366
// codegen_transmute_operand doesn't support SIMD, but since the previous
343
367
// check handled ZSTs, the only possible field access into something SIMD
344
368
// is to the `non_1zst_field` that's the same SIMD. (Other things, even
345
369
// just padding, would change the wrapper's representation type.)
346
- assert_eq ! ( field. size, self . layout. size) ;
370
+ assert_eq ! ( field. size, layout. size) ;
347
371
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 ( ) || self . layout . ty . is_union ( ) {
375
+ fx. codegen_transmute_operand ( bx, * self , field)
376
+ } else {
377
+ self . val
378
+ }
351
379
} else {
352
- let ( in_scalar, imm) = match ( self . val , self . layout . backend_repr ) {
380
+ let ( in_scalar, imm) = match ( self . val , layout. backend_repr ) {
353
381
// Extract a scalar component from a pair.
354
382
( OperandValue :: Pair ( a_llval, b_llval) , BackendRepr :: ScalarPair ( a, b) ) => {
355
- if offset. bytes ( ) == 0 {
383
+ // This needs to look at `offset`, rather than `i`, because
384
+ // for a type like `Option<u32>`, the first thing in the pair
385
+ // is the tag, so `(_2 as Some).0` needs to read the *second*
386
+ // thing in the pair despite it being "field zero".
387
+ if offset == Size :: ZERO {
356
388
assert_eq ! ( field. size, a. size( bx. cx( ) ) ) ;
357
- ( Some ( a ) , a_llval)
389
+ ( a , a_llval)
358
390
} else {
359
391
assert_eq ! ( offset, a. size( bx. cx( ) ) . align_to( b. align( bx. cx( ) ) . abi) ) ;
360
392
assert_eq ! ( field. size, b. size( bx. cx( ) ) ) ;
361
- ( Some ( b ) , b_llval)
393
+ ( b , b_llval)
362
394
}
363
395
}
364
396
@@ -367,30 +399,18 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
367
399
}
368
400
} ;
369
401
OperandValue :: Immediate ( match field. backend_repr {
370
- BackendRepr :: SimdVector { .. } => imm,
371
- BackendRepr :: Scalar ( out_scalar) => {
372
- let Some ( in_scalar) = in_scalar else {
373
- span_bug ! (
374
- fx. mir. span,
375
- "OperandRef::extract_field({:?}): missing input scalar for output scalar" ,
376
- self
377
- )
378
- } ;
379
- if in_scalar != out_scalar {
380
- // If the backend and backend_immediate types might differ,
381
- // flip back to the backend type then to the new immediate.
382
- // This avoids nop truncations, but still handles things like
383
- // Bools in union fields needs to be truncated.
384
- let backend = bx. from_immediate ( imm) ;
385
- bx. to_immediate_scalar ( backend, out_scalar)
386
- } else {
387
- imm
388
- }
402
+ BackendRepr :: Scalar ( out_scalar) if downcast_variant. is_some ( ) => {
403
+ // For a type like `Result<usize, &u32>` the layout is `Pair(i64, ptr)`.
404
+ // But if we're reading the `Ok` payload, we need to turn that `ptr`
405
+ // back into an integer. To avoid repeating logic we do that by
406
+ // calling the transmute code, which is legal thanks to the size
407
+ // assert we did when pulling it out of the pair.
408
+ transmute_scalar ( bx, imm, in_scalar, out_scalar)
389
409
}
410
+ BackendRepr :: Scalar ( _) | BackendRepr :: SimdVector { .. } => imm,
390
411
BackendRepr :: ScalarPair ( _, _) | BackendRepr :: Memory { .. } => bug ! ( ) ,
391
412
} )
392
413
} ;
393
-
394
414
OperandRef { val, layout : field }
395
415
}
396
416
@@ -438,7 +458,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
438
458
let tag_op = match self . val {
439
459
OperandValue :: ZeroSized => bug ! ( ) ,
440
460
OperandValue :: Immediate ( _) | OperandValue :: Pair ( _, _) => {
441
- self . extract_field ( fx, bx, tag_field. as_usize ( ) )
461
+ self . extract_field ( fx, bx, None , tag_field)
442
462
}
443
463
OperandValue :: Ref ( place) => {
444
464
let tag = place. with_type ( self . layout ) . project_field ( bx, tag_field. as_usize ( ) ) ;
@@ -929,34 +949,28 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
929
949
) -> Option < OperandRef < ' tcx , Bx :: Value > > {
930
950
debug ! ( "maybe_codegen_consume_direct(place_ref={:?})" , place_ref) ;
931
951
952
+ let mut downcast_variant = None ;
932
953
match self . locals [ place_ref. local ] {
933
954
LocalRef :: Operand ( mut o) => {
934
955
// Moves out of scalar and scalar pair fields are trivial.
935
956
for elem in place_ref. projection . iter ( ) {
936
- match elem {
957
+ match * elem {
937
958
mir:: ProjectionElem :: Field ( f, _) => {
938
959
assert ! (
939
960
!o. layout. ty. is_any_ptr( ) ,
940
961
"Bad PlaceRef: destructing pointers should use cast/PtrMetadata, \
941
962
but tried to access field {f:?} of pointer {o:?}",
942
963
) ;
943
- o = o. extract_field ( self , bx, f. index ( ) ) ;
964
+ o = o. extract_field ( self , bx, downcast_variant, f) ;
965
+ downcast_variant = None ;
944
966
}
945
- mir:: ProjectionElem :: Index ( _)
946
- | mir:: ProjectionElem :: ConstantIndex { .. } => {
947
- // ZSTs don't require any actual memory access.
948
- // FIXME(eddyb) deduplicate this with the identical
949
- // checks in `codegen_consume` and `extract_field`.
950
- let elem = o. layout . field ( bx. cx ( ) , 0 ) ;
951
- if elem. is_zst ( ) {
952
- o = OperandRef :: zero_sized ( elem) ;
953
- } else {
954
- return None ;
955
- }
967
+ mir:: ProjectionElem :: Downcast ( _sym, variant_idx) => {
968
+ downcast_variant = Some ( variant_idx) ;
956
969
}
957
970
_ => return None ,
958
971
}
959
972
}
973
+ debug_assert_eq ! ( downcast_variant, None ) ;
960
974
961
975
Some ( o)
962
976
}
0 commit comments