-
Notifications
You must be signed in to change notification settings - Fork 91
Open
Labels
bugSomething isn't workingSomething isn't working
Description
Premise
I was wondering whether I could replace expressions like x * x with x.powi(2) and went ahead and compared the generated SPIR-V in both cases. Turns out, Rust-GPU fails to optimize even the most obvious opportunities.
Method
I inspected the SPIR-V using https://www.khronos.org/spirv/visualizer/ and the artifact was generated in release mode using rust-gpu 08f98a7 (a commit from Mon Jan 5 12:45:27 2026 +0100), which uses Rust nightly-2025-06-30.
Case: Manual Multiply
This Rust code:
#[spirv(fragment)]
pub fn fragment(out: &mut Vec4, #[spirv(frag_coord)] frag_coord: Vec4) {
*out = Vec4::splat(frag_coord.x * frag_coord.x);
}Becomes the following SPIR-V:
OpCapability Shader
OpCapability VulkanMemoryModel
OpMemoryModel Logical Vulkan
OpEntryPoint Fragment %1 "fragment" %2 %3
OpExecutionMode %1 OriginUpperLeft
OpDecorate %2 BuiltIn FragCoord
OpDecorate %3 Location 0
%6 = OpTypeFloat 32
%7 = OpTypeVector %6 4
%8 = OpTypePointer Output %7
%9 = OpTypePointer Input %7
%10 = OpTypeVoid
%11 = OpTypeFunction %10
%2 = OpVariable %9 Input
%3 = OpVariable %8 Output
%1 = OpFunction %10 None %11
%12 = OpLabel
%13 = OpLoad %7 %2
%14 = OpCompositeExtract %6 %13 0
%16 = OpFMul %6 %14 %14
%17 = OpCompositeConstruct %7 %16 %16 %16 %16
OpStore %3 %17
OpReturn
OpFunctionEnd
Case: Powi
The following Rust code:
#[spirv(fragment)]
pub fn fragment(out: &mut Vec4, #[spirv(frag_coord)] frag_coord: Vec4) {
*out = Vec4::splat(frag_coord.x.powi(2));
}Becomes the following SPIR-V:
OpCapability Shader
OpCapability VulkanMemoryModel
OpMemoryModel Logical Vulkan
OpEntryPoint Fragment %1 "fragment" %2 %3
OpExecutionMode %1 OriginUpperLeft
OpDecorate %2 BuiltIn FragCoord
OpDecorate %3 Location 0
%14 = OpTypeFloat 32
%15 = OpTypeVector %14 4
%16 = OpTypePointer Output %15
%17 = OpTypePointer Input %15
%18 = OpTypeVoid
%19 = OpTypeFunction %18
%2 = OpVariable %17 Input
%20 = OpTypeBool
%21 = OpTypeInt 32 1
%25 = OpTypeInt 32 0
%30 = OpConstant %25 0
%31 = OpConstant %25 1
%32 = OpConstant %21 1
%33 = OpUndef %14
%34 = OpUndef %25
%3 = OpVariable %16 Output
%127 = OpConstant %25 2
%1 = OpFunction %18 None %19
%35 = OpLabel
%36 = OpLoad %15 %2
%37 = OpCompositeExtract %14 %36 0
OpBranch %75
%75 = OpLabel
%76 = OpPhi %14 (%37 : %35) (%77 : %78)
%79 = OpPhi %25 (%127 : %35) (%80 : %78)
OpLoopMerge %81 %78 None
OpBranch %82
%82 = OpLabel
%83 = OpBitwiseAnd %25 %79 %31
%84 = OpIEqual %20 %83 %30
OpSelectionMerge %85 None
OpBranchConditional %84 %86 %87
%87 = OpLabel
OpBranch %85
%86 = OpLabel
%88 = OpFMul %14 %76 %76
%89 = OpShiftRightLogical %25 %79 %32
OpBranch %85
%85 = OpLabel
%77 = OpPhi %14 (%88 : %86) (%33 : %87)
%80 = OpPhi %25 (%89 : %86) (%34 : %87)
OpBranch %78
%78 = OpLabel
OpBranchConditional %84 %75 %81
%81 = OpLabel
%90 = OpIEqual %20 %79 %31
OpSelectionMerge %91 None
OpBranchConditional %90 %92 %93
%93 = OpLabel
OpBranch %94
%94 = OpLabel
%95 = OpPhi %14 (%76 : %93) (%96 : %97)
%98 = OpPhi %14 (%76 : %93) (%99 : %97)
%100 = OpPhi %25 (%79 : %93) (%101 : %97)
OpLoopMerge %102 %97 None
OpBranch %103
%103 = OpLabel
%104 = OpUGreaterThan %20 %100 %31
OpSelectionMerge %105 None
OpBranchConditional %104 %106 %107
%107 = OpLabel
OpBranch %105
%106 = OpLabel
%108 = OpShiftRightLogical %25 %100 %32
%109 = OpFMul %14 %95 %95
%110 = OpBitwiseAnd %25 %108 %31
%111 = OpIEqual %20 %110 %31
OpSelectionMerge %112 None
OpBranchConditional %111 %113 %114
%114 = OpLabel
OpBranch %112
%113 = OpLabel
%115 = OpFMul %14 %98 %109
OpBranch %112
%112 = OpLabel
%116 = OpPhi %14 (%115 : %113) (%98 : %114)
OpBranch %105
%105 = OpLabel
%96 = OpPhi %14 (%109 : %112) (%33 : %107)
%99 = OpPhi %14 (%116 : %112) (%33 : %107)
%101 = OpPhi %25 (%108 : %112) (%34 : %107)
OpBranch %97
%97 = OpLabel
OpBranchConditional %104 %94 %102
%102 = OpLabel
OpBranch %91
%92 = OpLabel
OpBranch %91
%91 = OpLabel
%117 = OpPhi %14 (%76 : %92) (%98 : %102)
%119 = OpCompositeConstruct %15 %117 %117 %117 %117
OpStore %3 %119
OpReturn
OpFunctionEnd
Proposal
Support "unrolling" x.powi(2) etcetera into multiplications, i.e. x * x, which are significantly faster.
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working