Search Issue Tracker
Won't Fix
Votes
1
Found in [Package]
1.8.4
Issue ID
BUR-2424
Regression
No
Burst Constant.IsConstantExpression() check is ignored when using float8
Reproduction steps:
1. Open the attached “ASDQWE” project
2. Open the “Asset/Scenes/SampleScene.unity” Scene
3. Open the Burst Inspector (Jobs > Burst > Open Inspector…)
4. Observe the “Bug.Testing.ConstantPow(MaxMath.float8&, MaxMath.float8&)” method
Expected result: “Bug.Testing.ConstantPow(MaxMath.float8&, MaxMath.float8&)” method performs a series of multiplications instead of pow calls
Actual result: “Bug.Testing.ConstantPow(MaxMath.float8&, MaxMath.float8&)” method ignores the Constant.IsConstantExpression() check and contains calls to pow
Reproducible with: 1.7.4 (2021.3.27f1), 1.8.3(2021.3.27f1), 1.8.4 (2021.3.27f1, 2022.3.2f1, 2023.1.0f1, 2023.2.0a19)
Reproducible on: Intel MacOS 13.4
Add comment
All about bugs
View bugs we have successfully reproduced, and vote for the bugs you want to see fixed most urgently.
Latest issues
- GPU utilization increases by 20% on Meta Quest headsets when Render Graph is enabled on 6000.0.16f1 and higher
- Value on Slider (Int) control in UI Builder displays as default when saving UI Document
- Color mismatch in UI Builders Library panel when the Editors theme is set to Light Mode
- [Android ] "AndroidJNI.ToBooleanArray" returns a random non-zero value instead of "IntPtr.Zero" when the method argument is null
- Non-HDR color picker opens when selecting material color with HDR enabled
Resolution Note:
Constant.IsConstantExpression is technically working as intended. The short explanation of why the float8 version doesn't behave like the float4 one is mainly due to internal optimization heuristics doing things in a slightly different order, causing `y` at the time `Constant.IsConstantExpression` is evaluated not to be constant.
Here's the more technical and longer answer:
Burst compiles your code into LLVM's intermediate representation (IR) and then uses several LLVM optimization-passes to produce the final program. Some of these optimization-passes do constant folding (evaluating things at compile time) and some do inlining (substituting calls to functions for their implementations at the call-site). We have several phases of these and they interact non-triviallly. The order in which those are applied on a per-function basis also has an effect on the final out-come.
Now, we compile our Constant.IsConstantExpression down to LLVM's intrinsic `llvm.is.constant.*`. And as LLVM write themselves:
"The result [of llvm.is.constant] also intentionally depends on the result of optimization passes – e.g., the result can change depending on whether a function gets inlined or not. A function’s parameters are obviously not constant. However, a call like llvm.is.constant.i32(i32 %param) can return true after the function is inlined, if the value passed to the function parameter was a constant.
On the other hand, if constant folding is not run, it will never evaluate to true, even in simple cases."
Now, we don't have full control over exactly in what order any given collection of functions get visited, but if for example the `maxmath.pow` happens to get folded before it gets inlined into the caller, then Constant.IsConstantExpression would be false. Which, is exactly what happens in your case. I suspect this different ordering happens become of the relative order of the functions being visited through a hash-map iterator, because changing `maxmath.pow`'s name to `maxmath.powee` will yield the "nice" result. We don't control this ordering from our side, as this is very much just part of LLVM's internals.
While it's obviously suboptimal in your specific case, there's no trivial good general solution. As said, the interaction between the many different optimization passes are non-trivial, and changing them to generate better code in your case, might worsen the code-gen in many order cases.
We will be updating the documentation for `Constant.IsConstantExpression` in order to make the nature of it clearer though.