-
-
Notifications
You must be signed in to change notification settings - Fork 14.2k
Implement intrinsics with fallback bodies #120500
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
Conversation
|
(rustbot has picked a reviewer for you, use r? to override) |
|
Some changes occurred in compiler/rustc_codegen_gcc Some changes occurred in compiler/rustc_codegen_cranelift cc @bjorn3 Some changes occurred to the CTFE / Miri engine cc @rust-lang/miri Some changes occurred in src/tools/clippy cc @rust-lang/clippy Some changes occurred to MIR optimizations cc @rust-lang/wg-mir-opt |
This comment has been minimized.
This comment has been minimized.
| /// Whether the function is an intrinsic | ||
| query is_intrinsic(def_id: DefId) -> bool { | ||
| desc { |tcx| "checking whether `{}` is an intrinsic", tcx.def_path_str(def_id) } | ||
| query intrinsic(def_id: DefId) -> Option<Symbol> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would cg_clif need to use this too? It currently matches on the IntrinsicDef and uses tcx.item_name() when it is an intrinsic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IntrinsicDef is only created if intrinsic returns Some. Otherwise you get a normal definition. That's why I needed to query the backend. I created this design because I think it is more robust than letting the IntrinsicDef go all the way to backends and have them figure out how to call the fallback body again.
Basically if the backend doesn't say it has an impl for a rustc_intrinsic intrinsic, then the intrinsic becomes just a normal function from the perspective of the entire compiler
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem with the current design as far as I can tell is that the return value of intrinsic is hard coded in the crate metadata for libcore based on the codegen backend with which libcore is compiled. This would break linking crates compiled by different codegen backends together.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm... I guess I can make the backend check happen outside the query
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not relevant anymore. They are always intrinsics now, and the backends can choose to call the default body instead.
compiler/rustc_middle/src/ty/util.rs
Outdated
| .name, | ||
| ) | ||
| .name; | ||
| tcx.intrinsics_implemented_by_backend(()).contains(&name).then_some(name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like it is bound to go out of sync with what the backend actually supports. Would it be possible to instead obtain the fallback MIR body inside the codegen backend when the backend determines that there is no implementation? Also there are various places where is_intrinsic doesn't just affect codegen for the local crate. For example the lower intrinsics MIR pass (which uses is_intrinsic) affects the MIR bodies recorded in the crate metadata, const eval will use is_intrinsic to skip counting any execution cost for intrinsics. The value of is_intrinsic is also recorded in the crate metadata and thus only the codegen backend with which libcore is compiled effectively determines if is_intrinsic would return true. This completely breaks when mixing codegen backends, like mixing cg_clif with a cg_llvm sysroot as using the rustc-codegen-cranelift-preview component would do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm... I wanted to avoid that, but I agree it's annoying that they go out of sync.
I'll think about how to make backends able to call the default body.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Being able to call the default body would be really nice -- I was thinking about swap the other day, where being able to have a looping version as the default but then override it with something smarter sometimes in the codegen backend would be particularly nice if the codegen backend didn't also need to emit the loop version.
(That said it could always be approximated by having the intrinsic return a bool that says whether it did anything, for example, and thus getting the library fallback that way if it's particularly needed for some intrinsics.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. The backends need to implement this logic themselves every time (I implemented it for cranelift), but that indeed seems like the best solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for doing this, really glad someone finally found time for this! :3
r=me, modulo couple nits (did not notice bjorn's concern, you might want to address it)
This comment has been minimized.
This comment has been minimized.
|
Thanks for working on this, Oli! I'm really excited 🎉 |
0ed9f48 to
dadf506
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Some changes occurred in src/librustdoc/clean/types.rs cc @camelid |
This comment has been minimized.
This comment has been minimized.
|
Should finally be ready. We don't need miri support from the get go, so I'd rather do it in a separate PR. |
| fx.tcx | ||
| .dcx() | ||
| .span_fatal(source_info.span, format!("unsupported intrinsic {}", intrinsic)); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What will the error message be for intrinsics that are neither implemented by cg_clif nor have a fallback body?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably gonna ICE 😆
|
cg_clif changes LGTM |
This comment has been minimized.
This comment has been minimized.
WaffleLapkin
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
r=me with or without nits
|
The Miri subtree was changed cc @rust-lang/miri |
7ef9869 to
585e76a
Compare
|
@bors r=WaffleLapkin |
|
The default log presentation was not expanding for me; below is what I think was causing the failure according to what I saw from skimming the raw log itself. Snippet of raw log output with ui test failures |
|
That's an error from a different PR: #120847 (see last commit) |
Implement intrinsics with fallback bodies fixes rust-lang#93145 (though we can port many more intrinsics) cc rust-lang#63585 The way this works is that the backend logic for generating custom code for intrinsics has been made fallible. The only failure path is "this intrinsic is unknown". The `Instance` (that was `InstanceDef::Intrinsic`) then gets converted to `InstanceDef::Item`, which represents the fallback body. A regular function call to that body is then codegenned. This is currently implemented for * codegen_ssa (so llvm and gcc) * codegen_cranelift other backends will need to adjust, but they can just keep doing what they were doing if they prefer (though adding new intrinsics to the compiler will then require them to implement them, instead of getting the fallback body). cc `@scottmcm` `@WaffleLapkin` ### todo * [ ] miri support * [x] default intrinsic name to name of function instead of requiring it to be specified in attribute * [x] make sure that the bodies are always available (must be collected for metadata)
|
☀️ Test successful - checks-actions |
|
Finished benchmarking commit (dfa88b3): comparison URL. Overall result: no relevant changes - no action needed@rustbot label: -perf-regression Instruction countThis benchmark run did not return any relevant results for this metric. Max RSS (memory usage)ResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
CyclesThis benchmark run did not return any relevant results for this metric. Binary sizeThis benchmark run did not return any relevant results for this metric. Bootstrap: 637.782s -> 637.11s (-0.11%) |
Add a scheme for moving away from `extern "rust-intrinsic"` entirely All `rust-intrinsic`s can become free functions now, either with a fallback body, or with a dummy body and an attribute, requiring backends to actually implement the intrinsic. This PR demonstrates the dummy-body scheme with the `vtable_size` intrinsic. cc rust-lang#63585 follow-up to rust-lang#120500 MCP at rust-lang/compiler-team#720
Add a scheme for moving away from `extern "rust-intrinsic"` entirely All `rust-intrinsic`s can become free functions now, either with a fallback body, or with a dummy body and an attribute, requiring backends to actually implement the intrinsic. This PR demonstrates the dummy-body scheme with the `vtable_size` intrinsic. cc rust-lang#63585 follow-up to rust-lang#120500 MCP at rust-lang/compiler-team#720
Add a scheme for moving away from `extern "rust-intrinsic"` entirely All `rust-intrinsic`s can become free functions now, either with a fallback body, or with a dummy body and an attribute, requiring backends to actually implement the intrinsic. This PR demonstrates the dummy-body scheme with the `vtable_size` intrinsic. cc rust-lang#63585 follow-up to rust-lang#120500 MCP at rust-lang/compiler-team#720
Upgrade toolchain to 2024-02-17. Relevant PR: - rust-lang/rust#120500 - rust-lang/rust#100603 Fixes #87 Fixes #3034 Fixes #3037
Implement intrinsics with fallback bodies fixes rust-lang#93145 (though we can port many more intrinsics) cc rust-lang#63585 The way this works is that the backend logic for generating custom code for intrinsics has been made fallible. The only failure path is "this intrinsic is unknown". The `Instance` (that was `InstanceDef::Intrinsic`) then gets converted to `InstanceDef::Item`, which represents the fallback body. A regular function call to that body is then codegenned. This is currently implemented for * codegen_ssa (so llvm and gcc) * codegen_cranelift other backends will need to adjust, but they can just keep doing what they were doing if they prefer (though adding new intrinsics to the compiler will then require them to implement them, instead of getting the fallback body). cc `@scottmcm` `@WaffleLapkin` ### todo * [ ] miri support * [x] default intrinsic name to name of function instead of requiring it to be specified in attribute * [x] make sure that the bodies are always available (must be collected for metadata)
Add a scheme for moving away from `extern "rust-intrinsic"` entirely All `rust-intrinsic`s can become free functions now, either with a fallback body, or with a dummy body and an attribute, requiring backends to actually implement the intrinsic. This PR demonstrates the dummy-body scheme with the `vtable_size` intrinsic. cc rust-lang#63585 follow-up to rust-lang#120500 MCP at rust-lang/compiler-team#720
Add a scheme for moving away from `extern "rust-intrinsic"` entirely All `rust-intrinsic`s can become free functions now, either with a fallback body, or with a dummy body and an attribute, requiring backends to actually implement the intrinsic. This PR demonstrates the dummy-body scheme with the `vtable_size` intrinsic. cc rust-lang#63585 follow-up to rust-lang#120500 MCP at rust-lang/compiler-team#720
Add a scheme for moving away from `extern "rust-intrinsic"` entirely All `rust-intrinsic`s can become free functions now, either with a fallback body, or with a dummy body and an attribute, requiring backends to actually implement the intrinsic. This PR demonstrates the dummy-body scheme with the `vtable_size` intrinsic. cc rust-lang#63585 follow-up to rust-lang#120500 MCP at rust-lang/compiler-team#720
Sorry, I just now realized that |
|
Note that is_val_statically_known and const_eval_select are entirely unrelated. (The first is about const propagation, the second about Const eval / CTFE. These two concepts have very little to do with each other.)
|
fixes #93145 (though we can port many more intrinsics)
cc #63585
The way this works is that the backend logic for generating custom code for intrinsics has been made fallible. The only failure path is "this intrinsic is unknown". The
Instance(that wasInstanceDef::Intrinsic) then gets converted toInstanceDef::Item, which represents the fallback body. A regular function call to that body is then codegenned. This is currently implemented forother backends will need to adjust, but they can just keep doing what they were doing if they prefer (though adding new intrinsics to the compiler will then require them to implement them, instead of getting the fallback body).
cc @scottmcm @WaffleLapkin
todo