Skip to content

Fix -Zregparm for LLVM builtins #145309

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

winstonallo
Copy link

@winstonallo winstonallo commented Aug 12, 2025

This fixes the issue where -Zregparm=N was not working correctly when calling LLVM intrinsics

By default on x86-32, arguments are passed on the stack. The -Zregparm=N flag allows the first N arguments to be passed in registers instead.

When calling intrinsics like memset, LLVM still passes parameters on the stack, which prevents optimizations like tail calls.

As proposed by @tgross35, I fixed this by setting the NumRegisterParameters LLVM module flag to N when the -Zregparm=N is set.

// compiler/rust_codegen_llvm/src/context.rs#375-382
if let Some(regparm_count) = sess.opts.unstable_opts.regparm {
    llvm::add_module_flag_u32(
        llmod,
        llvm::ModuleFlagMergeBehavior::Error,
        "NumRegisterParameters",
        regparm_count,
    );
}

Here is a before/after compiler explorer.

Here is the final result for the code snippet in the original issue:

entrypoint:
        push    esi
        mov     esi, eax
        mov     eax, ecx
        mov     ecx, esi
        pop     esi
        jmp     memset   ; Tail call parameters in registers

Fixes: #145271

@rustbot rustbot added A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Aug 12, 2025
@winstonallo
Copy link
Author

winstonallo commented Aug 12, 2025

I think this should fix it already, let me know if I am missing something! Working on the tests now.

@winstonallo winstonallo marked this pull request as ready for review August 12, 2025 13:32
@rustbot
Copy link
Collaborator

rustbot commented Aug 12, 2025

r? @petrochenkov

rustbot has assigned @petrochenkov.
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

@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 Aug 12, 2025
@winstonallo
Copy link
Author

I added a test verifying that the memset parameters are passed in registers as discussed.

@petrochenkov
Copy link
Contributor

r? nikic

Copy link
Contributor

@tgross35 tgross35 left a comment

Choose a reason for hiding this comment

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

Thank you for doing a quick fix here!

Just a few requests to make sure we're testing what we expect

@rustbot rustbot added the A-test-infra-minicore Area: `minicore` test auxiliary and `//@ add-core-stubs` label Aug 12, 2025
@rustbot
Copy link
Collaborator

rustbot commented Aug 12, 2025

This PR modifies tests/auxiliary/minicore.rs.

cc @jieyouxu

@rust-log-analyzer

This comment has been minimized.

Copy link
Contributor

@tgross35 tgross35 left a comment

Choose a reason for hiding this comment

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

Two small nits but this looks good to me once CI passes, please squash

@nikic anything else?

@winstonallo
Copy link
Author

winstonallo commented Aug 13, 2025

I squashed, let me know if there is anything else I can do!

@tgross35
Copy link
Contributor

Looks great! Thanks for making this happen, and welcome :)

@bors r+

@bors
Copy link
Collaborator

bors commented Aug 13, 2025

📌 Commit 02d4666 has been approved by tgross35

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Aug 13, 2025
@winstonallo
Copy link
Author

winstonallo commented Aug 13, 2025

Looks great! Thanks for making this happen, and welcome :)

Thank you very much for all the help! I'll keep an eye on the issue tracker, but if you come across anything you think would be a good fit, please let me know!

@tgross35
Copy link
Contributor

If you want something tiny then as Miguel mentioned, -Zreg-struct-return could use an assembly test (now that you're an expert at those). It does basically the same thing as regparm, except for return types.

If you're looking for something in particular or just looking to get more involved, https://rust-lang.zulipchat.com/ is a great place to stop by.

@winstonallo
Copy link
Author

Should I create a separate issue for the asm tests, or just submit a PR when I'm done?

@tgross35
Copy link
Contributor

No need for a new issue!

Zalathar added a commit to Zalathar/rust that referenced this pull request Aug 13, 2025
…ross35

Fix `-Zregparm` for LLVM builtins

This fixes the issue where `-Zregparm=N` was not working correctly when calling LLVM intrinsics

By default on `x86-32`, arguments are passed on the stack. The `-Zregparm=N` flag allows the first `N` arguments to be passed in registers instead.

When calling intrinsics like `memset`, LLVM still passes parameters on the stack, which prevents optimizations like tail calls.

As proposed by `@tgross35,` I fixed this by setting the `NumRegisterParameters` LLVM module flag to `N` when the `-Zregparm=N` is set.

```rust
// compiler/rust_codegen_llvm/src/context.rs#375-382
if let Some(regparm_count) = sess.opts.unstable_opts.regparm {
    llvm::add_module_flag_u32(
        llmod,
        llvm::ModuleFlagMergeBehavior::Error,
        "NumRegisterParameters",
        regparm_count,
    );
}
```
[Here](https://rust.godbolt.org/z/YMezreo48) is a before/after compiler explorer.

Here is the final result for the code snippet in the original issue:
```asm
entrypoint:
        push    esi
        mov     esi, eax
        mov     eax, ecx
        mov     ecx, esi
        pop     esi
        jmp     memset   ; Tail call parameters in registers
```

Fixes: rust-lang#145271
jdonszelmann added a commit to jdonszelmann/rust that referenced this pull request Aug 13, 2025
…ross35

Fix `-Zregparm` for LLVM builtins

This fixes the issue where `-Zregparm=N` was not working correctly when calling LLVM intrinsics

By default on `x86-32`, arguments are passed on the stack. The `-Zregparm=N` flag allows the first `N` arguments to be passed in registers instead.

When calling intrinsics like `memset`, LLVM still passes parameters on the stack, which prevents optimizations like tail calls.

As proposed by `@tgross35,` I fixed this by setting the `NumRegisterParameters` LLVM module flag to `N` when the `-Zregparm=N` is set.

```rust
// compiler/rust_codegen_llvm/src/context.rs#375-382
if let Some(regparm_count) = sess.opts.unstable_opts.regparm {
    llvm::add_module_flag_u32(
        llmod,
        llvm::ModuleFlagMergeBehavior::Error,
        "NumRegisterParameters",
        regparm_count,
    );
}
```
[Here](https://rust.godbolt.org/z/YMezreo48) is a before/after compiler explorer.

Here is the final result for the code snippet in the original issue:
```asm
entrypoint:
        push    esi
        mov     esi, eax
        mov     eax, ecx
        mov     ecx, esi
        pop     esi
        jmp     memset   ; Tail call parameters in registers
```

Fixes: rust-lang#145271
bors added a commit that referenced this pull request Aug 13, 2025
Rollup of 9 pull requests

Successful merges:

 - #122661 (Change the desugaring of `assert!` for better error output)
 - #138736 (Sanitizers target modificators)
 - #144955 (search graph: lazily update parent goals)
 - #145120 (llvm: Accept new LLVM lifetime format)
 - #145153 (Handle macros with multiple kinds, and improve errors)
 - #145189 (Weekly `cargo update`)
 - #145250 (Add regression test for former ICE involving malformed meta items containing interpolated tokens)
 - #145309 (Fix `-Zregparm` for LLVM builtins)
 - #145331 (Make std use the edition 2024 prelude)

r? `@ghost`
`@rustbot` modify labels: rollup
@fmease
Copy link
Member

fmease commented Aug 13, 2025

#145309 (comment)
@bors r-

@bors bors 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-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Aug 13, 2025
set

* Enforce the `-Zregparm=N` flag by setting the NumRegisterParameters
LLVM module flag * Add assembly tests verifying that the parameters are
passed in registers for reparm values 1, 2, and 3, for both LLVM
intrinsics and non-builtin functions * Add c_void type to minicore
@winstonallo
Copy link
Author

winstonallo commented Aug 13, 2025

Fixed the typo, thank you!

@nikic
Copy link
Contributor

nikic commented Aug 13, 2025

@bors r=tgross35 rollup=iffy assembly test

@bors
Copy link
Collaborator

bors commented Aug 13, 2025

📌 Commit 04ff144 has been approved by tgross35

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Aug 13, 2025
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. A-test-infra-minicore Area: `minicore` test auxiliary and `//@ add-core-stubs` S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. 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.

-Zregparm does not work correctly for LLVM builtins
10 participants