Skip to content

CodeGen: rework Aggregate implemention for rvalue_creates_operand cases #142383

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

scottmcm
Copy link
Member

@scottmcm scottmcm commented Jun 11, 2025

A non-trivial refactor pulled out from #138759
r? workingjubilee

The previous implementation I'd written here based on index_by_increasing_offset is complicated to follow and difficult to extend to non-structs.

This changes the implementation, without actually changing any codegen (thus no test changes either), to be more like the existing extract_field (

pub(crate) fn extract_field<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
&self,
fx: &mut FunctionCx<'a, 'tcx, Bx>,
bx: &mut Bx,
i: usize,
) -> Self {
let field = self.layout.field(bx.cx(), i);
let offset = self.layout.fields.offset(i);
if !bx.is_backend_ref(self.layout) && bx.is_backend_ref(field) {
if let BackendRepr::SimdVector { count, .. } = self.layout.backend_repr
&& let BackendRepr::Memory { sized: true } = field.backend_repr
&& count.is_power_of_two()
{
assert_eq!(field.size, self.layout.size);
// This is being deprecated, but for now stdarch still needs it for
// Newtype vector of array, e.g. #[repr(simd)] struct S([i32; 4]);
let place = PlaceRef::alloca(bx, field);
self.val.store(bx, place.val.with_type(self.layout));
return bx.load_operand(place);
} else {
// Part of https://github.com/rust-lang/compiler-team/issues/838
bug!("Non-ref type {self:?} cannot project to ref field type {field:?}");
}
}
let val = if field.is_zst() {
OperandValue::ZeroSized
} else if field.size == self.layout.size {
assert_eq!(offset.bytes(), 0);
fx.codegen_transmute_operand(bx, *self, field).unwrap_or_else(|| {
bug!(
"Expected `codegen_transmute_operand` to handle equal-size \
field {i:?} projection from {self:?} to {field:?}"
)
})
} else {
let (in_scalar, imm) = match (self.val, self.layout.backend_repr) {
// Extract a scalar component from a pair.
(OperandValue::Pair(a_llval, b_llval), BackendRepr::ScalarPair(a, b)) => {
if offset.bytes() == 0 {
assert_eq!(field.size, a.size(bx.cx()));
(Some(a), a_llval)
} else {
assert_eq!(offset, a.size(bx.cx()).align_to(b.align(bx.cx()).abi));
assert_eq!(field.size, b.size(bx.cx()));
(Some(b), b_llval)
}
}
_ => {
span_bug!(fx.mir.span, "OperandRef::extract_field({:?}): not applicable", self)
}
};
OperandValue::Immediate(match field.backend_repr {
BackendRepr::SimdVector { .. } => imm,
BackendRepr::Scalar(out_scalar) => {
let Some(in_scalar) = in_scalar else {
span_bug!(
fx.mir.span,
"OperandRef::extract_field({:?}): missing input scalar for output scalar",
self
)
};
if in_scalar != out_scalar {
// If the backend and backend_immediate types might differ,
// flip back to the backend type then to the new immediate.
// This avoids nop truncations, but still handles things like
// Bools in union fields needs to be truncated.
let backend = bx.from_immediate(imm);
bx.to_immediate_scalar(backend, out_scalar)
} else {
imm
}
}
BackendRepr::ScalarPair(_, _) | BackendRepr::Memory { .. } => bug!(),
})
};
OperandRef { val, layout: field }
}
) in that it allows setting a particular field directly.

Notably I've found this one much easier to get right, in particular because having the OperandRef<Result<V, Scalar>> gives a really useful thing to include in ICE messages if something did happen to go wrong.

Another refactor pulled out from 138759

The previous implementation I'd written here based on `index_by_increasing_offset` is complicated to follow and difficult to extend to non-structs.

This changes the implementation, without actually changing any codegen (thus no test changes either), to be more like the existing `extract_field` (<https://github.com/rust-lang/rust/blob/2b0274c71dba0e24370ebf65593da450e2e91868/compiler/rustc_codegen_ssa/src/mir/operand.rs#L345-L425>) in that it allows setting a particular field directly.

Notably I've found this one much easier to get right, in particular because having the `OperandRef<Result<V, Scalar>>` gives a really useful thing to include in ICE messages if something did happen to go wrong.
@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jun 11, 2025
@rustbot
Copy link
Collaborator

rustbot commented Jun 11, 2025

These commits modify the Cargo.lock file. Unintentional changes to Cargo.lock can be introduced when switching branches and rebasing PRs.

If this was unintentional then you should revert the changes before this PR is merged.
Otherwise, you can ignore this comment.

Some changes occurred in compiler/rustc_codegen_ssa

cc @WaffleLapkin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants