Skip to content

Commit 340816a

Browse files
committed
abi: make dig_scalar_pointee search for offsets in all layout fields.
1 parent 7393c38 commit 340816a

File tree

2 files changed

+63
-114
lines changed

2 files changed

+63
-114
lines changed

crates/rustc_codegen_spirv/src/abi.rs

Lines changed: 62 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::spirv_type::SpirvType;
77
use rspirv::spirv::{StorageClass, Word};
88
use rustc_data_structures::fx::FxHashMap;
99
use rustc_errors::ErrorReported;
10+
use rustc_index::vec::Idx;
1011
use rustc_middle::bug;
1112
use rustc_middle::ty::layout::{FnAbiExt, TyAndLayout};
1213
use rustc_middle::ty::subst::SubstsRef;
@@ -18,7 +19,7 @@ use rustc_span::Span;
1819
use rustc_span::DUMMY_SP;
1920
use rustc_target::abi::call::{CastTarget, FnAbi, PassMode, Reg, RegKind};
2021
use rustc_target::abi::{
21-
Abi, Align, FieldsShape, LayoutOf, Primitive, Scalar, Size, TagEncoding, VariantIdx, Variants,
22+
Abi, Align, FieldsShape, LayoutOf, Primitive, Scalar, Size, VariantIdx, Variants,
2223
};
2324
use std::cell::RefCell;
2425
use std::collections::hash_map::Entry;
@@ -349,15 +350,15 @@ fn trans_type_impl<'tcx>(
349350
field_names: None,
350351
}
351352
.def_with_name(cx, span, TyLayoutNameKey::from(ty)),
352-
Abi::Scalar(ref scalar) => trans_scalar(cx, span, ty, scalar, None, is_immediate),
353+
Abi::Scalar(ref scalar) => trans_scalar(cx, span, ty, scalar, Size::ZERO, is_immediate),
353354
Abi::ScalarPair(ref a, ref b) => {
354355
// Note: We can't use auto_struct_layout here because the spirv types here might be undefined due to
355356
// recursive pointer types.
356357
let a_offset = Size::ZERO;
357358
let b_offset = a.value.size(cx).align_to(b.value.align(cx).abi);
358359
// Note! Do not pass through is_immediate here - they're wrapped in a struct, hence, not immediate.
359-
let a = trans_scalar(cx, span, ty, a, Some(a_offset), false);
360-
let b = trans_scalar(cx, span, ty, b, Some(b_offset), false);
360+
let a = trans_scalar(cx, span, ty, a, a_offset, false);
361+
let b = trans_scalar(cx, span, ty, b, b_offset, false);
361362
let size = if ty.is_unsized() { None } else { Some(ty.size) };
362363
SpirvType::Adt {
363364
def_id: def_id_for_spirv_type_adt(ty),
@@ -370,7 +371,7 @@ fn trans_type_impl<'tcx>(
370371
.def_with_name(cx, span, TyLayoutNameKey::from(ty))
371372
}
372373
Abi::Vector { ref element, count } => {
373-
let elem_spirv = trans_scalar(cx, span, ty, element, None, false);
374+
let elem_spirv = trans_scalar(cx, span, ty, element, Size::ZERO, false);
374375
SpirvType::Vector {
375376
element: elem_spirv,
376377
count: count as u32,
@@ -399,7 +400,7 @@ pub fn scalar_pair_element_backend_type<'tcx>(
399400
1 => a.value.size(cx).align_to(b.value.align(cx).abi),
400401
_ => unreachable!(),
401402
};
402-
trans_scalar(cx, span, ty, [a, b][index], Some(offset), is_immediate)
403+
trans_scalar(cx, span, ty, [a, b][index], offset, is_immediate)
403404
}
404405

405406
/// A "scalar" is a basic building block: bools, ints, floats, pointers. (i.e. not something complex like a struct)
@@ -414,7 +415,7 @@ fn trans_scalar<'tcx>(
414415
span: Span,
415416
ty: TyAndLayout<'tcx>,
416417
scalar: &Scalar,
417-
scalar_pair_field_offset: Option<Size>,
418+
offset: Size,
418419
is_immediate: bool,
419420
) -> Word {
420421
if is_immediate && scalar.is_bool() {
@@ -428,7 +429,7 @@ fn trans_scalar<'tcx>(
428429
Primitive::F32 => SpirvType::Float(32).def(span, cx),
429430
Primitive::F64 => SpirvType::Float(64).def(span, cx),
430431
Primitive::Pointer => {
431-
let pointee_ty = dig_scalar_pointee(cx, ty, scalar_pair_field_offset);
432+
let pointee_ty = dig_scalar_pointee(cx, ty, offset);
432433
// Pointers can be recursive. So, record what we're currently translating, and if we're already translating
433434
// the same type, emit an OpTypeForwardPointer and use that ID.
434435
if let Some(predefined_result) = cx
@@ -459,125 +460,72 @@ fn trans_scalar<'tcx>(
459460
// If the above didn't make sense, please poke Ashley, it's probably easier to explain via conversation.
460461
fn dig_scalar_pointee<'tcx>(
461462
cx: &CodegenCx<'tcx>,
462-
ty: TyAndLayout<'tcx>,
463-
scalar_pair_field_offset: Option<Size>,
463+
layout: TyAndLayout<'tcx>,
464+
offset: Size,
464465
) -> PointeeTy<'tcx> {
465-
match *ty.ty.kind() {
466-
TyKind::Ref(_, elem_ty, _) | TyKind::RawPtr(TypeAndMut { ty: elem_ty, .. }) => {
467-
let elem = cx.layout_of(elem_ty);
468-
match scalar_pair_field_offset {
469-
None => PointeeTy::Ty(elem),
470-
Some(scalar_pair_field_offset) => {
471-
if elem.is_unsized() {
472-
let field_idx = if scalar_pair_field_offset == Size::ZERO {
473-
0
474-
} else {
475-
1
476-
};
477-
dig_scalar_pointee(cx, ty.field(cx, field_idx), None)
478-
} else {
479-
// This can sometimes happen in weird cases when going through the Adt case below - an ABI
480-
// of ScalarPair could be deduced, but it's actually e.g. a sized pointer followed by some other
481-
// completely unrelated type, not a wide pointer. So, translate this as a single scalar, one
482-
// component of that ScalarPair.
483-
PointeeTy::Ty(elem)
484-
}
485-
}
466+
if let FieldsShape::Primitive = layout.fields {
467+
assert_eq!(offset, Size::ZERO);
468+
let pointee = match *layout.ty.kind() {
469+
TyKind::Ref(_, pointee_ty, _) | TyKind::RawPtr(TypeAndMut { ty: pointee_ty, .. }) => {
470+
PointeeTy::Ty(cx.layout_of(pointee_ty))
486471
}
487-
}
488-
TyKind::FnPtr(sig) if scalar_pair_field_offset.is_none() => PointeeTy::Fn(sig),
489-
TyKind::Adt(def, _) if def.is_box() => {
490-
let ptr_ty = cx.layout_of(cx.tcx.mk_mut_ptr(ty.ty.boxed_ty()));
491-
dig_scalar_pointee(cx, ptr_ty, scalar_pair_field_offset)
492-
}
493-
TyKind::Tuple(_) | TyKind::Adt(..) | TyKind::Closure(..) => {
494-
dig_scalar_pointee_adt(cx, ty, scalar_pair_field_offset)
495-
}
496-
ref kind => cx.tcx.sess.fatal(&format!(
497-
"TODO: Unimplemented Primitive::Pointer TyKind scalar_pair_field_offset={:?} ({:#?}):\n{:#?}",
498-
scalar_pair_field_offset, kind, ty
499-
)),
472+
TyKind::FnPtr(sig) => PointeeTy::Fn(sig),
473+
_ => bug!("Pointer is not `&T`, `*T` or `fn` pointer: {:#?}", layout),
474+
};
475+
return pointee;
500476
}
501-
}
502477

503-
fn dig_scalar_pointee_adt<'tcx>(
504-
cx: &CodegenCx<'tcx>,
505-
ty: TyAndLayout<'tcx>,
506-
scalar_pair_field_offset: Option<Size>,
507-
) -> PointeeTy<'tcx> {
508-
match &ty.variants {
509-
// If it's a Variants::Multiple, then we want to emit the type of the dataful variant, not the type of the
510-
// discriminant. This is because the discriminant can e.g. have type *mut(), whereas we want the full underlying
511-
// type, only available in the dataful variant.
512-
Variants::Multiple {
513-
tag_encoding,
514-
tag_field,
515-
variants,
516-
..
517-
} => {
518-
match *tag_encoding {
519-
TagEncoding::Direct => cx.tcx.sess.fatal(&format!(
520-
"dig_scalar_pointee_adt Variants::Multiple TagEncoding::Direct makes no sense: {:#?}",
521-
ty
522-
)),
523-
TagEncoding::Niche { dataful_variant, .. } => {
524-
// This *should* be something like Option<&T>: a very simple enum.
525-
// TODO: This might not be, if it's a scalar pair?
526-
assert_eq!(1, ty.fields.count());
527-
assert_eq!(1, variants[dataful_variant].fields.count());
528-
if let TyKind::Adt(adt, substs) = ty.ty.kind() {
529-
assert_eq!(1, adt.variants[dataful_variant].fields.len());
530-
assert_eq!(0, *tag_field);
531-
let field_ty = adt.variants[dataful_variant].fields[0].ty(cx.tcx, substs);
532-
dig_scalar_pointee(cx, cx.layout_of(field_ty), scalar_pair_field_offset)
533-
} else {
534-
bug!("Variants::Multiple not TyKind::Adt: {:#?}", ty)
535-
}
536-
},
537-
}
478+
let all_fields = (match &layout.variants {
479+
Variants::Multiple { variants, .. } => 0..variants.len(),
480+
Variants::Single { index } => {
481+
let i = index.as_usize();
482+
i..i + 1
538483
}
539-
Variants::Single { .. } => {
540-
let fields = ty
541-
.fields
542-
.index_by_increasing_offset()
543-
.map(|f| ty.field(cx, f))
544-
.filter(|f| !f.is_zst())
545-
.collect::<Vec<_>>();
546-
match scalar_pair_field_offset {
547-
Some(scalar_pair_field_offset) => match fields.len() {
548-
1 => dig_scalar_pointee(cx, fields[0], Some(scalar_pair_field_offset)),
549-
// This case right here is the cause of the comment handling TyKind::Ref.
550-
2 => {
551-
let field_idx = if scalar_pair_field_offset == Size::ZERO {
552-
0
553-
} else {
554-
1
555-
};
556-
dig_scalar_pointee(cx, fields[field_idx], None)
557-
}
558-
other => cx.tcx.sess.fatal(&format!(
559-
"Unable to dig scalar pair pointer type: fields length {}",
560-
other
561-
)),
562-
},
563-
None => match fields.len() {
564-
1 => dig_scalar_pointee(cx, fields[0], None),
565-
other => cx.tcx.sess.fatal(&format!(
566-
"Unable to dig scalar pointer type: fields length {}",
567-
other
568-
)),
569-
},
484+
})
485+
.flat_map(|variant_idx| {
486+
let variant = layout.for_variant(cx, VariantIdx::new(variant_idx));
487+
(0..variant.fields.count()).map(move |field_idx| {
488+
(
489+
variant.field(cx, field_idx),
490+
variant.fields.offset(field_idx),
491+
)
492+
})
493+
});
494+
495+
let mut pointee = None;
496+
for (field, field_offset) in all_fields {
497+
if field.is_zst() {
498+
continue;
499+
}
500+
if (field_offset..field_offset + field.size).contains(&offset) {
501+
let new_pointee = dig_scalar_pointee(cx, field, offset - field_offset);
502+
match pointee {
503+
Some(old_pointee) if old_pointee != new_pointee => {
504+
cx.tcx.sess.fatal(&format!(
505+
"dig_scalar_pointee: unsupported Pointer with different \
506+
pointee types ({:?} vs {:?}) at offset {:?} in {:#?}",
507+
old_pointee, new_pointee, offset, layout
508+
));
509+
}
510+
_ => pointee = Some(new_pointee),
570511
}
571512
}
572513
}
514+
pointee.unwrap_or_else(|| {
515+
bug!(
516+
"field containing Pointer scalar at offset {:?} not found in {:#?}",
517+
offset,
518+
layout
519+
)
520+
})
573521
}
574522

575523
fn trans_aggregate<'tcx>(cx: &CodegenCx<'tcx>, span: Span, ty: TyAndLayout<'tcx>) -> Word {
576524
match ty.fields {
577-
FieldsShape::Primitive => cx.tcx.sess.fatal(&format!(
578-
"FieldsShape::Primitive not supported yet in trans_type: {:?}",
525+
FieldsShape::Primitive => bug!(
526+
"trans_aggregate called for FieldsShape::Primitive layout {:#?}",
579527
ty
580-
)),
528+
),
581529
FieldsShape::Union(_) => {
582530
assert_ne!(ty.size.bytes(), 0, "{:#?}", ty);
583531
assert!(!ty.is_unsized(), "{:#?}", ty);

crates/rustc_codegen_spirv/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ extern crate rustc_data_structures;
115115
extern crate rustc_driver;
116116
extern crate rustc_errors;
117117
extern crate rustc_hir;
118+
extern crate rustc_index;
118119
extern crate rustc_interface;
119120
extern crate rustc_middle;
120121
extern crate rustc_mir;

0 commit comments

Comments
 (0)