Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_abi/src/callconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
unreachable!("`homogeneous_aggregate` should not be called for scalable vectors")
}

BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => {
BackendRepr::ScalarPair { .. } | BackendRepr::Memory { sized: true } => {
// Helper for computing `homogeneous_aggregate`, allowing a custom
// starting offset (used below for handling variants).
let from_fields_at =
Expand Down
24 changes: 16 additions & 8 deletions compiler/rustc_abi/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
Err(AbiMismatch) | Ok(None) => BackendRepr::Memory { sized: true },
Ok(Some((repr, _))) => match repr {
// Mismatched alignment (e.g. union is #[repr(packed)]): disable opt
BackendRepr::Scalar(_) | BackendRepr::ScalarPair(_, _)
BackendRepr::Scalar(_) | BackendRepr::ScalarPair { .. }
if repr.scalar_platform_align(dl).unwrap() != align =>
{
BackendRepr::Memory { sized: true }
Expand All @@ -489,7 +489,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
}
// the alignment tests passed and we can use this
BackendRepr::Scalar(..)
| BackendRepr::ScalarPair(..)
| BackendRepr::ScalarPair { .. }
| BackendRepr::SimdVector { .. }
| BackendRepr::SimdScalableVector { .. }
| BackendRepr::Memory { .. } => repr,
Expand Down Expand Up @@ -558,7 +558,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
};
match &mut st.backend_repr {
BackendRepr::Scalar(scalar) => hide_niches(scalar),
BackendRepr::ScalarPair(a, b) => {
BackendRepr::ScalarPair { a, b, b_offset: _ } => {
hide_niches(a);
hide_niches(b);
}
Expand Down Expand Up @@ -701,13 +701,21 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
// When the total alignment and size match, we can use the
// same ABI as the scalar variant with the reserved niche.
BackendRepr::Scalar(_) => BackendRepr::Scalar(niche_scalar),
BackendRepr::ScalarPair(first, second) => {
BackendRepr::ScalarPair { a: first, b: second, b_offset } => {
// Only the niche is guaranteed to be initialised,
// so use union layouts for the other primitive.
if niche_offset == Size::ZERO {
BackendRepr::ScalarPair(niche_scalar, second.to_union())
BackendRepr::ScalarPair {
a: niche_scalar,
b: second.to_union(),
b_offset,
}
} else {
BackendRepr::ScalarPair(first.to_union(), niche_scalar)
BackendRepr::ScalarPair {
a: first.to_union(),
b: niche_scalar,
b_offset,
}
}
}
_ => BackendRepr::Memory { sized: true },
Expand Down Expand Up @@ -1037,7 +1045,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
// If we pick a "clever" (by-value) ABI, we might have to adjust the ABI of the
// variants to ensure they are consistent. This is because a downcast is
// semantically a NOP, and thus should not affect layout.
if matches!(abi, BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..)) {
if matches!(abi, BackendRepr::Scalar(..) | BackendRepr::ScalarPair { .. }) {
for variant in &mut layout_variants {
// We only do this for variants with fields; the others are not accessed anyway.
// Also do not overwrite any already existing "clever" ABIs.
Expand Down Expand Up @@ -1354,7 +1362,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
}
// But scalar pairs are Rust-specific and get
// treated as aggregates by C ABIs anyway.
BackendRepr::ScalarPair(..) => {
BackendRepr::ScalarPair { .. } => {
abi = field.backend_repr;
}
_ => {}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_abi/src/layout/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
offsets: [Size::ZERO, b_offset].into(),
in_memory_order: [FieldIdx::new(0), FieldIdx::new(1)].into(),
},
backend_repr: BackendRepr::ScalarPair(a, b),
backend_repr: BackendRepr::ScalarPair { a, b, b_offset },
largest_niche,
uninhabited: false,
align: AbiAlign::new(align),
Expand Down
38 changes: 23 additions & 15 deletions compiler/rustc_abi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1796,14 +1796,18 @@ impl IntoDiagArg for NumScalableVectors {
pub enum BackendRepr {
Scalar(Scalar),
/// The data contained in this type can be entirely represented by two scalars.
/// The two scalars are listed in *memory* order, so the first is at offset zero
/// and the second at a non-zero offset.
/// The two scalars are listed in *memory* order, so `a` is at offset zero
/// and `b` is at non-zero offset `b_offset`.
/// These need not be `FieldIdx(0)` and `FieldIdx(1)`.
///
/// As of June 2026 the offset to the second scalar is the size of the first
/// scalar rounded up to the platform alignment of the second scalar.
/// As of June 2026 the `b_offset` is always the size of the `a`
/// scalar rounded up to the platform alignment of the `b` scalar.
/// That may soon change, however; see MCP#1007.
ScalarPair(Scalar, Scalar),
ScalarPair {
a: Scalar,
b: Scalar,
b_offset: Size,
},
SimdScalableVector {
element: Scalar,
count: u64,
Expand All @@ -1826,7 +1830,7 @@ impl BackendRepr {
pub fn is_unsized(&self) -> bool {
match *self {
BackendRepr::Scalar(_)
| BackendRepr::ScalarPair(..)
| BackendRepr::ScalarPair { .. }
// FIXME(rustc_scalable_vector): Scalable vectors are `Sized` while the
// `sized_hierarchy` feature is not yet fully implemented. After `sized_hierarchy` is
// fully implemented, scalable vectors will remain `Sized`, they just won't be
Expand Down Expand Up @@ -1875,7 +1879,7 @@ impl BackendRepr {
pub fn scalar_platform_align<C: HasDataLayout>(&self, cx: &C) -> Option<Align> {
match *self {
BackendRepr::Scalar(s) => Some(s.default_align(cx).abi),
BackendRepr::ScalarPair(s1, s2) => {
BackendRepr::ScalarPair { a: s1, b: s2, b_offset: _ } => {
Some(s1.default_align(cx).max(s2.default_align(cx)).abi)
}
// The align of a Vector can vary in surprising ways
Expand All @@ -1893,8 +1897,7 @@ impl BackendRepr {
// No padding in scalars.
BackendRepr::Scalar(s) => Some(s.size(cx)),
// May have some padding between the pair.
BackendRepr::ScalarPair(s1, s2) => {
let field2_offset = s1.size(cx).align_to(s2.default_align(cx).abi);
BackendRepr::ScalarPair { a: _, b: s2, b_offset: field2_offset } => {
let size = (field2_offset + s2.size(cx)).align_to(
self.scalar_platform_align(cx)
// We absolutely must have an answer here or everything is FUBAR.
Expand All @@ -1913,8 +1916,8 @@ impl BackendRepr {
pub fn to_union(&self) -> Self {
match *self {
BackendRepr::Scalar(s) => BackendRepr::Scalar(s.to_union()),
BackendRepr::ScalarPair(s1, s2) => {
BackendRepr::ScalarPair(s1.to_union(), s2.to_union())
BackendRepr::ScalarPair { a: s1, b: s2, b_offset } => {
BackendRepr::ScalarPair { a: s1.to_union(), b: s2.to_union(), b_offset }
}
BackendRepr::SimdVector { element, count } => {
BackendRepr::SimdVector { element: element.to_union(), count }
Expand All @@ -1939,8 +1942,13 @@ impl BackendRepr {
BackendRepr::SimdVector { element: element_l, count: count_l },
BackendRepr::SimdVector { element: element_r, count: count_r },
) => element_l.primitive() == element_r.primitive() && count_l == count_r,
(BackendRepr::ScalarPair(l1, l2), BackendRepr::ScalarPair(r1, r2)) => {
l1.primitive() == r1.primitive() && l2.primitive() == r2.primitive()
(
BackendRepr::ScalarPair { a: l1, b: l2, b_offset: l_offset },
BackendRepr::ScalarPair { a: r1, b: r2, b_offset: r_offset },
) => {
l1.primitive() == r1.primitive()
&& l2.primitive() == r2.primitive()
&& l_offset == r_offset

@scottmcm scottmcm Jul 1, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: since this is an eq-like method, I also check that the offsets are the same here. (They always will be right now, but it makes sense to check it regardless IMHO.)

View changes since the review

}
// Everything else must be strictly identical.
_ => self == other,
Expand Down Expand Up @@ -2180,7 +2188,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
BackendRepr::Scalar(_)
| BackendRepr::SimdVector { .. }
| BackendRepr::SimdScalableVector { .. } => false,
BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => true,
BackendRepr::ScalarPair { .. } | BackendRepr::Memory { .. } => true,
}
}

Expand Down Expand Up @@ -2294,7 +2302,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
pub fn is_zst(&self) -> bool {
match self.backend_repr {
BackendRepr::Scalar(_)
| BackendRepr::ScalarPair(..)
| BackendRepr::ScalarPair { .. }
| BackendRepr::SimdScalableVector { .. }
| BackendRepr::SimdVector { .. } => false,
BackendRepr::Memory { sized } => sized && self.size.bytes() == 0,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_cranelift/src/abi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ fn make_local_place<'tcx>(
);
}
let place = if is_ssa {
if let BackendRepr::ScalarPair(_, _) = layout.backend_repr {
if let BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } = layout.backend_repr {
CPlace::new_var_pair(fx, local, layout)
} else {
CPlace::new_var(fx, local, layout)
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
_ => unreachable!("{:?}", self.layout.backend_repr),
},
PassMode::Pair(attrs_a, attrs_b) => match self.layout.backend_repr {
BackendRepr::ScalarPair(a, b) => {
BackendRepr::ScalarPair { a, b, b_offset: _ } => {
let a = scalar_to_clif_type(tcx, a);
let b = scalar_to_clif_type(tcx, b);
smallvec![
Expand Down Expand Up @@ -167,7 +167,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
_ => unreachable!("{:?}", self.layout.backend_repr),
},
PassMode::Pair(attrs_a, attrs_b) => match self.layout.backend_repr {
BackendRepr::ScalarPair(a, b) => {
BackendRepr::ScalarPair { a, b, b_offset: _ } => {
let a = scalar_to_clif_type(tcx, a);
let b = scalar_to_clif_type(tcx, b);
(
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_cranelift/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,7 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt:
}
UnOp::PtrMetadata => match layout.backend_repr {
BackendRepr::Scalar(_) => CValue::zst(dest_layout),
BackendRepr::ScalarPair(_, _) => {
BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } => {
CValue::by_val(operand.load_scalar_pair(fx).1, dest_layout)
}
_ => bug!("Unexpected `PtrToMetadata` operand: {operand:?}"),
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,9 @@ fn codegen_regular_intrinsic_call<'tcx>(
let layout = fx.layout_of(generic_args.type_at(0));
// Note: Can't use is_unsized here as truly unsized types need to take the fixed size
// branch
let meta = if let BackendRepr::ScalarPair(_, _) = ptr.layout().backend_repr {
let meta = if let BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } =
ptr.layout().backend_repr
{
Some(ptr.load_scalar_pair(fx).1)
} else {
None
Expand All @@ -586,7 +588,9 @@ fn codegen_regular_intrinsic_call<'tcx>(
let layout = fx.layout_of(generic_args.type_at(0));
// Note: Can't use is_unsized here as truly unsized types need to take the fixed size
// branch
let meta = if let BackendRepr::ScalarPair(_, _) = ptr.layout().backend_repr {
let meta = if let BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } =
ptr.layout().backend_repr
{
Some(ptr.load_scalar_pair(fx).1)
} else {
None
Expand Down
23 changes: 10 additions & 13 deletions compiler/rustc_codegen_cranelift/src/value_and_place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@ fn codegen_field<'tcx>(
}
}

fn scalar_pair_calculate_b_offset(tcx: TyCtxt<'_>, a_scalar: Scalar, b_scalar: Scalar) -> Offset32 {
let b_offset = a_scalar.size(&tcx).align_to(b_scalar.default_align(&tcx).abi);
fn scalar_pair_convert_b_offset(b_offset: Size) -> Offset32 {
Offset32::new(b_offset.bytes().try_into().unwrap())
}

Expand Down Expand Up @@ -159,11 +158,11 @@ impl<'tcx> CValue<'tcx> {
let layout = self.1;
match self.0 {
CValueInner::ByRef(ptr, None) => {
let (a_scalar, b_scalar) = match layout.backend_repr {
BackendRepr::ScalarPair(a, b) => (a, b),
let (a_scalar, b_scalar, b_offset) = match layout.backend_repr {
BackendRepr::ScalarPair { a, b, b_offset } => (a, b, b_offset),
_ => unreachable!("load_scalar_pair({:?})", self),
};
let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar);
let b_offset = scalar_pair_convert_b_offset(b_offset);
let clif_ty1 = scalar_to_clif_type(fx.tcx, a_scalar);
let clif_ty2 = scalar_to_clif_type(fx.tcx, b_scalar);
let mut flags = MemFlags::new();
Expand All @@ -189,7 +188,7 @@ impl<'tcx> CValue<'tcx> {
match self.0 {
CValueInner::ByVal(_) => unreachable!(),
CValueInner::ByValPair(val1, val2) => match layout.backend_repr {
BackendRepr::ScalarPair(_, _) => {
BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } => {
let val = match field.as_u32() {
0 => val1,
1 => val2,
Expand Down Expand Up @@ -580,7 +579,7 @@ impl<'tcx> CPlace<'tcx> {
}
CPlaceInner::VarPair(_local, var1, var2) => {
let (data1, data2) = match from.1.backend_repr {
BackendRepr::ScalarPair(_, _) => {
BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } => {
CValue(from.0, dst_layout).load_scalar_pair(fx)
}
_ => {
Expand All @@ -607,9 +606,8 @@ impl<'tcx> CPlace<'tcx> {
to_ptr.store(fx, val, flags);
}
CValueInner::ByValPair(val1, val2) => match from.layout().backend_repr {
BackendRepr::ScalarPair(a_scalar, b_scalar) => {
let b_offset =
scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar);
BackendRepr::ScalarPair { a: _, b: _, b_offset } => {
let b_offset = scalar_pair_convert_b_offset(b_offset);
to_ptr.store(fx, val1, flags);
to_ptr.offset(fx, b_offset).store(fx, val2, flags);
}
Expand All @@ -627,9 +625,8 @@ impl<'tcx> CPlace<'tcx> {
to_ptr.store(fx, val, flags);
return;
}
BackendRepr::ScalarPair(a_scalar, b_scalar) => {
let b_offset =
scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar);
BackendRepr::ScalarPair { a: _, b: _, b_offset } => {
let b_offset = scalar_pair_convert_b_offset(b_offset);
let (val1, val2) = from.load_scalar_pair(fx);
to_ptr.store(fx, val1, flags);
to_ptr.offset(fx, b_offset).store(fx, val2, flags);
Expand Down
15 changes: 8 additions & 7 deletions compiler/rustc_codegen_cranelift/src/vtable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,14 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>(
}
}

let (ptr, vtable) = if let BackendRepr::ScalarPair(_, _) = arg.layout().backend_repr {
let (ptr, vtable) = arg.load_scalar_pair(fx);
(Pointer::new(ptr), vtable)
} else {
let (ptr, vtable) = arg.try_to_ptr().unwrap();
(ptr, vtable.unwrap())
};
let (ptr, vtable) =
if let BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } = arg.layout().backend_repr {
let (ptr, vtable) = arg.load_scalar_pair(fx);
(Pointer::new(ptr), vtable)
} else {
let (ptr, vtable) = arg.try_to_ptr().unwrap();
(ptr, vtable.unwrap())
};

let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes();
let func_ref = fx.bcx.ins().load(
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_codegen_gcc/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1064,9 +1064,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
load
},
)
} else if let abi::BackendRepr::ScalarPair(ref a, ref b) = place.layout.backend_repr {
let b_offset = a.size(self).align_to(b.default_align(self).abi);

} else if let abi::BackendRepr::ScalarPair { ref a, ref b, b_offset } =
place.layout.backend_repr
{
let mut load = |i, scalar: &abi::Scalar, align| {
let ptr = if i == 0 {
place.val.llval
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
let tp_ty = fn_args.type_at(0);
let layout = self.layout_of(tp_ty).layout;
let _use_integer_compare = match layout.backend_repr() {
Scalar(_) | ScalarPair(_, _) => true,
Scalar(_) | ScalarPair { a: _, b: _, b_offset: _ } => true,
SimdVector { .. } | SimdScalableVector { .. } => false,
Memory { .. } => {
// For rusty ABIs, small aggregates are actually passed
Expand Down
Loading
Loading