This repository was archived by the owner on Oct 31, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 249
This repository was archived by the owner on Oct 31, 2025. It is now read-only.
min/max on ints results in quite branchy code #758
Copy link
Copy link
Closed
Labels
t: bugSomething isn't workingSomething isn't working
Description
This is perhaps more of a rust issue.
On 35172f7, this code results in the following spir-v:
#![cfg_attr(
target_arch = "spirv",
feature(register_attr),
register_attr(spirv),
no_std,
)]
// This needs to be here to provide `#[panic_handler]`.
extern crate spirv_std;
#[spirv(fragment)]
pub fn x() {
let x = min_i32(1, 2);
let y = min_u32(1, 2);
let z = min_f32(1.0, 2.0);
}
#[inline(never)]
fn min_i32(a: i32, b: i32) -> i32 {
a.min(b)
}
#[inline(never)]
fn min_u32(a: u32, b: u32) -> u32 {
a.min(b)
}
#[inline(never)]
fn min_f32(a: f32, b: f32) -> f32 {
a.min(b)
}(With comments added to indicate the different functions)
; SPIR-V
; Version: 1.4
; Generator: Embark Studios Rust GPU Compiler Backend; 0
; Bound: 198
; Schema: 0
OpCapability Int8
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical Simple
OpEntryPoint Fragment %2 "x"
OpExecutionMode %2 OriginUpperLeft
%int = OpTypeInt 32 1
%14 = OpTypeFunction %int %int %int
%uint = OpTypeInt 32 0
%16 = OpTypeFunction %uint %uint %uint
%float = OpTypeFloat 32
%18 = OpTypeFunction %float %float %float
%char = OpTypeInt 8 1
%void = OpTypeVoid
%25 = OpTypeFunction %void
%bool = OpTypeBool
%false = OpConstantFalse %bool
%true = OpConstantTrue %bool
%uint_1 = OpConstant %uint 1
%char_n1 = OpConstant %char -1
%char_0 = OpConstant %char 0
%char_1 = OpConstant %char 1
%int_1 = OpConstant %int 1
%int_2 = OpConstant %int 2
%uint_2 = OpConstant %uint 2
%float_1 = OpConstant %float 1
%float_2 = OpConstant %float 2
%41 = OpUndef %int
%42 = OpUndef %uint
; min_i32:
%9 = OpFunction %int DontInline %14
%77 = OpFunctionParameter %int
%78 = OpFunctionParameter %int
%79 = OpLabel
%166 = OpSLessThan %bool %77 %78
OpSelectionMerge %176 None
OpBranchConditional %166 %167 %168
%167 = OpLabel
OpBranch %176
%168 = OpLabel
%171 = OpIEqual %bool %77 %78
%194 = OpSelect %char %171 %char_0 %char_1
OpBranch %176
%176 = OpLabel
%177 = OpPhi %char %char_n1 %167 %194 %168
%85 = OpSConvert %int %177
OpSelectionMerge %86 None
OpSwitch %85 %87 -1 %88 0 %89 1 %90
%87 = OpLabel
OpUnreachable
%88 = OpLabel
OpBranch %86
%89 = OpLabel
OpBranch %86
%90 = OpLabel
OpBranch %86
%86 = OpLabel
%94 = OpPhi %int %41 %88 %41 %89 %78 %90
%95 = OpPhi %bool %true %88 %true %89 %false %90
%195 = OpSelect %int %95 %77 %94
OpReturnValue %195
OpFunctionEnd
; min_u32:
%10 = OpFunction %uint DontInline %16
%112 = OpFunctionParameter %uint
%113 = OpFunctionParameter %uint
%114 = OpLabel
%182 = OpULessThan %bool %112 %113
OpSelectionMerge %192 None
OpBranchConditional %182 %183 %184
%183 = OpLabel
OpBranch %192
%184 = OpLabel
%187 = OpIEqual %bool %112 %113
%196 = OpSelect %char %187 %char_0 %char_1
OpBranch %192
%192 = OpLabel
%193 = OpPhi %char %char_n1 %183 %196 %184
%120 = OpSConvert %int %193
OpSelectionMerge %121 None
OpSwitch %120 %122 -1 %123 0 %124 1 %125
%122 = OpLabel
OpUnreachable
%123 = OpLabel
OpBranch %121
%124 = OpLabel
OpBranch %121
%125 = OpLabel
OpBranch %121
%121 = OpLabel
%129 = OpPhi %uint %42 %123 %42 %124 %113 %125
%130 = OpPhi %bool %true %123 %true %124 %false %125
%197 = OpSelect %uint %130 %112 %129
OpReturnValue %197
OpFunctionEnd
; min_f32:
%11 = OpFunction %float DontInline %18
%147 = OpFunctionParameter %float
%148 = OpFunctionParameter %float
%149 = OpLabel
%150 = OpExtInst %float %1 FMin %147 %148
OpReturnValue %150
OpFunctionEnd
; main:
%2 = OpFunction %void None %25
%155 = OpLabel
%158 = OpFunctionCall %int %9 %int_1 %int_2
%159 = OpFunctionCall %uint %10 %uint_1 %uint_2
%160 = OpFunctionCall %float %11 %float_1 %float_2
OpReturn
OpFunctionEnd
Expected Behaviour
While FMin is used correctly for floats, SMin and UMin are not used for integers. Same happens for max as well. Ideally they should be used as they're more-or-less guaranteed to generate the fastest code.
Alternatively, we could provide functions that call SMin/UMin via asm!.
- Rustc version:
nightly-2021-08-27-x86_64-pc-windows-msvc - SPIR-V version:
SPIRV-Tools v2021.3 v2021.3
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
t: bugSomething isn't workingSomething isn't working