-
Notifications
You must be signed in to change notification settings - Fork 94
Optimize num_traits::Float::powi to use GLSL.std.450 Pow #518
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -166,6 +166,16 @@ impl<'tcx> CodegenCx<'tcx> { | |
| } | ||
| } | ||
|
|
||
| // Check for usage of `num_traits` intrinsics (like Float::powi) that we can optimize | ||
| if self.tcx.crate_name(def_id.krate) == self.sym.num_traits && !def_id.is_local() { | ||
| let item_name = self.tcx.item_name(def_id); | ||
| if let Some(&intrinsic) = self.sym.num_traits_intrinsics.get(&item_name) { | ||
| self.num_traits_intrinsics | ||
| .borrow_mut() | ||
| .insert(def_id, intrinsic); | ||
| } | ||
| } | ||
|
Comment on lines
169
to
177
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have no idea how things work more generally, but why are things like this even necessary? I'd expect the generic machinery of the compiler to optimize it to some canonical form that the target would like the most. So it shouldn't make any difference if one writes
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The problem is we are using One can argue we shouldn't use I have a new optimizer where we can control things much more rather than relying on
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ouch, that definitely looks like a problem. Maybe worth creating an issue to look into getting rid of
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can't get rid of error[E0599]: no function or associated item named `powf` found for type `f32` in the current scope
--> crates/restir-shader/src/material/pbr/eval.rs:159:25
|
159 | f0 + (1.0 - f0) * f32::powf(f32::clamp(1.0 - cos_theta, 0.0, 1.0), 5.0)
| ^^^^ function or associated item not found in `f32`
|
= help: items from traits can only be used if the trait is in scopesee rust-lang/rust#149347 on this sillyness The workaround has usually been this #[cfg(target_arch = "spirv")]
use spirv_std::num_traits::Float;
While researching this, I've noticed this has been discussed in 2021 on the embark repo already, and their conclusion was:
I don't mind if we want to merge this anyway, so it's not a trap to end users @LegNeato. But #[cfg(feature = "std")]
let rem = |x: f32| x.rem_euclid(1.);
#[cfg(not(feature = "std"))]
let rem = |x: f32| x.rem_euclid(&1.);There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm also in favor of replacing num-traits with an in-house solution in the future. It would give Rust-GPU the necessary stability it needs. If num-traits does some change in the future it could silently break Rust-GPU in subtle ways that aren't immediately obvious, which is poison.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Firestar99 created an issue for this, let's just merge for now as the current state is obviously bad and this makes it (slightly) better? |
||
|
|
||
| // Check if this is a From trait implementation | ||
| if let Some(impl_def_id) = self.tcx.impl_of_method(def_id) | ||
| && let Some(trait_ref) = self.tcx.impl_trait_ref(impl_def_id) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| // Test that `Float::powi` uses GLSL.std.450 Pow instead of a loop-based implementation. | ||
| // See https://github.com/Rust-GPU/rust-gpu/issues/516 | ||
|
|
||
| // build-pass | ||
| // compile-flags: -C llvm-args=--disassemble-entry=main | ||
|
|
||
| use spirv_std::num_traits::Float; | ||
| use spirv_std::spirv; | ||
|
|
||
| #[spirv(fragment)] | ||
| pub fn main(input: f32, output: &mut f32) { | ||
| *output = input.powi(2); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| %1 = OpFunction %2 None %3 | ||
| %4 = OpLabel | ||
| OpLine %5 11 12 | ||
| %6 = OpLoad %7 %8 | ||
| OpLine %5 12 20 | ||
| %9 = OpConvertSToF %7 %10 | ||
| %11 = OpExtInst %7 %12 26 %6 %9 | ||
| OpLine %5 12 4 | ||
| OpStore %13 %11 | ||
| OpNoLine | ||
| OpReturn | ||
| OpFunctionEnd |
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.
I think for known low powers it would be better to produce explicit sequence of multiplications (or division + sequence of multiplications for negate powers)
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.
While generally correct, SPIR-V isn't final machine code. Most drivers will spin up an entire LLVM compiler to turn that SPIR-V into whatever machine code they actually run, which are going to be much better at emitting properly optimized Pow. So the best thing we can do is tell them directly it's a Pow, and not needlessly complicating it.