Skip to content

Don't require extern "llvm-intrinsic" return structs to be #[repr(packed)] - #164878

Open
beetrees wants to merge 1 commit into
rust-lang:mainfrom
beetrees:llvm-intrinsic-dont-require-repr-packed
Open

beetrees wants to merge 1 commit into
rust-lang:mainfrom
beetrees:llvm-intrinsic-dont-require-repr-packed

Conversation

@beetrees

@beetrees beetrees commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

View all comments

When LLVM intrinsics return multiple values, they return them in an LLVM struct. As Rust inserts explicit padding when creating the LLVM type of a Rust struct, stdarch currently uses packed structs to generate a similar (packed) struct and then re-packs the struct in autocast. This PR instead creates the struct from the fields in the struct/tuple directly - this allows the use of regular Rust structs and tuples to work as expected, and also removes the dependency on the internals of how Rust converts structs to LLVM types.

As link_llvm_intrinsics is an internal feature I was unsure what the correct approach to error handling was - currently I've just used bug! if the return type is invalid, but I can change it to use proper errors if that's preferred.

@rustbot rustbot added A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. 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 Oct 24, 2026
@rustbot

rustbot commented Oct 24, 2026

Copy link
Copy Markdown
Collaborator

r? @TaKO8Ki

rustbot has assigned @TaKO8Ki.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler
  • compiler expanded to 77 candidates
  • Random selection from 17 candidates

@beetrees
beetrees force-pushed the llvm-intrinsic-dont-require-repr-packed branch from ea2c846 to f468e1e Compare October 24, 2026 22:39
@rust-log-analyzer

This comment has been minimized.

@beetrees
beetrees force-pushed the llvm-intrinsic-dont-require-repr-packed branch from f468e1e to f2e7acb Compare October 25, 2026 00:25
Comment thread tests/codegen-llvm/inject-autocast.rs Outdated
// CHECK-NEXT: %14 = getelementptr inbounds i8, ptr %0, i64 80
// CHECK-NEXT: store <2 x i64> %13, ptr %14, align 16
// CHECK-NEXT: %15 = load %Bar, ptr %0, align 16
// CHECK-NEXT: store %Bar %15, ptr %_0, align 16

@bjorn3 bjorn3 Oct 25, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why was the matching of SSA value names removed? That makes it less robust against future changes, right?

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not really IMO. The numbered LLVM variables are always in sequential order, so any change to the names would involve reordering the statements or adding new statements inbetween, which would cause the test to fail regardless.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Adding new statements didn't require rewriting everything after it previously.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I see what you mean (additionally the original used CHECK whereas I've used CHECK-NEXT). I don't think that extra flexibility is wanted - if e.g. an extra store statement gets added between the existing statements then the test should fail. If the change is desired, it's easy enough to update the test with the new IR.

@bjorn3

bjorn3 commented Oct 25, 2026

Copy link
Copy Markdown
Member

As link_llvm_intrinsics is an internal feature I was unsure what the correct approach to error handling was - currently I've just used bug! if the return type is invalid, but I can change it to use proper errors if that's preferred.

bug!() seems fine to me.

@beetrees

Copy link
Copy Markdown
Contributor Author

Figured out a better way to do this, I'll mark as a draft for now.

@beetrees
beetrees marked this pull request as draft October 27, 2026 21:28
@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Oct 27, 2026
@beetrees
beetrees force-pushed the llvm-intrinsic-dont-require-repr-packed branch from f2e7acb to c5b4fc2 Compare October 28, 2026 00:00
@beetrees

Copy link
Copy Markdown
Contributor Author

Ready for review.

@beetrees
beetrees marked this pull request as ready for review October 28, 2026 00:04
@rustbot

rustbot commented Oct 28, 2026

Copy link
Copy Markdown
Collaborator

rustc_codegen_gcc is developed in its own repository. If possible, consider making this change to rust-lang/rustc_codegen_gcc instead.

cc @antoyo, @GuillaumeGomez

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Oct 28, 2026
&mut self,
instance: ty::Instance<'tcx>,
args: &[OperandRef<'tcx, Self::Value>],
return_slot: ReturnSlot<Self::Value>,

@antoyo antoyo Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please do not use ReturnSlot here as it is specifically meant to support the sret ABI as mentioned in its doc-comment.
I do not want to add a second meaning to ReturnSlot to avoid silently change the ABI when not intended.

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've changed it to an Option called memory_return_pointer.

@beetrees
beetrees force-pushed the llvm-intrinsic-dont-require-repr-packed branch from c5b4fc2 to e52eb7e Compare October 28, 2026 14:26
PassMode::Direct(ArgAttributes::new())
};
let return_abi = ArgAbi { layout: result_layout, mode: return_mode };
let (return_dest, return_slot) = self.make_return_dest(bx, destination, &return_abi);

@antoyo antoyo Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

There's still a risk of messing up the ABI since we have a ReturnSlot here.
I guess the risk is low, but would there be an easy way to avoid using ReturnSlot here?

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not without changing the make_return_dest function to not use it, or duplicating the code. The PassMode used to decide whether a return slot is needed is constructed directly above the call, and I've added an assert straight afterwards to check that return_slot has the expected variant. I think that should mitigate the risks?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

My worry is more about using that return_slot in a call to bx.call(), which would change the ABI: that's what I mean by it is error-prone to use ReturnSlot here.
This assert does not prevent that.
Given that, do you see another solution to avoid using ReturnSlot here?
Would you really need to duplicate the whole code of make_return_dest? Duplicating a few lines of code here seems less of an issue than having the possibility of silently changing the ABI when it is not intended.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

If the issue is the risk of someone passing return_slot to bx.call() in the future, would putting the whole thing in it's own block with a comment help mitigate your concern (apologies if I'm misunderstanding something)? e.g.:

let (return_dest, memory_return_pointer) = {
    // This `return_slot` is just for getting a pointer to an appropriate place to store a `BackendRepr::Memory`
    // result, and must not be passed used for anything else (such as `bx.call`).
    let (return_dest, return_slot) = self.make_return_dest(bx, destination, &return_abi);
    (return_dest, match return_slot {
        ReturnSlot::Direct => None,
        ReturnSlot::Indirect(pointer) => Some(pointer),
    })
}

I really don't want to duplicate make_return_dest as that means that any future changes to that function (e.g. changes to the way MIR locals are stored) will have to be kept in sync with the copy (or fall out of sync, causing bugs). Alternatively I could refactor make_return_dest into make_return_dest_inner which would be exactly the same but return (ReturnDest, Option<Value>) instead of (ReturnDest, ReturnSlot) - make_return_dest would then just be a thin wrapper around make_return_dest_inner.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'd still prefer to keep the type-level safety we have here (the ReturnSlot type that handles the sret ABI) instead of a comment.
As I understand, you don't use the sret ABI for LLVM intrinsics, right?
If that is the case, I would have assume you don't need to copy the whole content of make_return_dest, but I'm not familiar with this code, so I might be wrong.
If you cannot find a way to do so, I guess a thin wrapper over make_return_dest would be a good option, with a comment to explain that this is to hide the return_slot from the caller.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've separate out the logic into make_return_place (which uses Option<PlaceValue> instead of ReturnSlot).

@beetrees
beetrees force-pushed the llvm-intrinsic-dont-require-repr-packed branch 2 times, most recently from a754ea3 to c351765 Compare October 29, 2026 02:26
@rust-log-analyzer

This comment has been minimized.

@beetrees
beetrees force-pushed the llvm-intrinsic-dont-require-repr-packed branch from c351765 to 903da44 Compare October 29, 2026 02:33
@rust-log-analyzer

This comment has been minimized.

@beetrees

This comment was marked as resolved.

@beetrees
beetrees force-pushed the llvm-intrinsic-dont-require-repr-packed branch from 903da44 to a84d309 Compare October 29, 2026 03:05
@rustbot

This comment has been minimized.

@rust-bors

This comment has been minimized.

@beetrees
beetrees force-pushed the llvm-intrinsic-dont-require-repr-packed branch from a84d309 to 228aee1 Compare October 30, 2026 00:05
@rustbot

rustbot commented Oct 30, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. 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.

6 participants