Implement atomicSub intrinsic

Polyfill this for HLSL using an atomic add with the operand negated.

Fixed: tint:1130
Change-Id: Ifa32d58973f1b48593ec0f6320f47f4358a5a3a9
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/62760
Auto-Submit: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
This commit is contained in:
James Price
2021-08-26 15:26:25 +00:00
committed by Tint LUCI CQ
parent a96dce9c89
commit f9d19719fd
31 changed files with 1638 additions and 947 deletions

View File

@@ -0,0 +1,44 @@
// Copyright 2021 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
////////////////////////////////////////////////////////////////////////////////
// File generated by tools/intrinsic-gen
// using the template:
// test/intrinsics/intrinsics.wgsl.tmpl
// and the intrinsic defintion file:
// src/intrinsics.def
//
// Do not modify this file directly
////////////////////////////////////////////////////////////////////////////////
[[block]]
struct SB_RW {
arg_0: atomic<i32>;
};
[[group(0), binding(0)]] var<storage, read_write> sb_rw : SB_RW;
// fn atomicSub(ptr<storage, atomic<i32>, read_write>, i32) -> i32
fn atomicSub_051100() {
var res: i32 = atomicSub(&sb_rw.arg_0, 1);
}
[[stage(fragment)]]
fn fragment_main() {
atomicSub_051100();
}
[[stage(compute), workgroup_size(1)]]
fn compute_main() {
atomicSub_051100();
}

View File

@@ -0,0 +1,22 @@
int atomicSub_1(RWByteAddressBuffer buffer, uint offset, int value) {
int original_value = 0;
buffer.InterlockedAdd(offset, -value, original_value);
return original_value;
}
RWByteAddressBuffer sb_rw : register(u0, space0);
void atomicSub_051100() {
int res = atomicSub_1(sb_rw, 0u, 1);
}
void fragment_main() {
atomicSub_051100();
return;
}
[numthreads(1, 1, 1)]
void compute_main() {
atomicSub_051100();
return;
}

View File

@@ -0,0 +1,21 @@
#include <metal_stdlib>
using namespace metal;
struct SB_RW {
/* 0x0000 */ atomic_int arg_0;
};
void atomicSub_051100(device SB_RW& sb_rw) {
int res = atomic_fetch_sub_explicit(&(sb_rw.arg_0), 1, memory_order_relaxed);
}
fragment void fragment_main(device SB_RW& sb_rw [[buffer(0)]]) {
atomicSub_051100(sb_rw);
return;
}
kernel void compute_main(device SB_RW& sb_rw [[buffer(0)]]) {
atomicSub_051100(sb_rw);
return;
}

View File

@@ -0,0 +1,53 @@
; SPIR-V
; Version: 1.3
; Generator: Google Tint Compiler; 0
; Bound: 26
; Schema: 0
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %fragment_main "fragment_main"
OpEntryPoint GLCompute %compute_main "compute_main"
OpExecutionMode %fragment_main OriginUpperLeft
OpExecutionMode %compute_main LocalSize 1 1 1
OpName %SB_RW "SB_RW"
OpMemberName %SB_RW 0 "arg_0"
OpName %sb_rw "sb_rw"
OpName %atomicSub_051100 "atomicSub_051100"
OpName %res "res"
OpName %fragment_main "fragment_main"
OpName %compute_main "compute_main"
OpDecorate %SB_RW Block
OpMemberDecorate %SB_RW 0 Offset 0
OpDecorate %sb_rw DescriptorSet 0
OpDecorate %sb_rw Binding 0
%int = OpTypeInt 32 1
%SB_RW = OpTypeStruct %int
%_ptr_StorageBuffer_SB_RW = OpTypePointer StorageBuffer %SB_RW
%sb_rw = OpVariable %_ptr_StorageBuffer_SB_RW StorageBuffer
%void = OpTypeVoid
%5 = OpTypeFunction %void
%uint = OpTypeInt 32 0
%uint_1 = OpConstant %uint 1
%uint_0 = OpConstant %uint 0
%_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
%int_1 = OpConstant %int 1
%_ptr_Function_int = OpTypePointer Function %int
%19 = OpConstantNull %int
%atomicSub_051100 = OpFunction %void None %5
%8 = OpLabel
%res = OpVariable %_ptr_Function_int Function %19
%15 = OpAccessChain %_ptr_StorageBuffer_int %sb_rw %uint_0
%9 = OpAtomicISub %int %15 %uint_1 %uint_0 %int_1
OpStore %res %9
OpReturn
OpFunctionEnd
%fragment_main = OpFunction %void None %5
%21 = OpLabel
%22 = OpFunctionCall %void %atomicSub_051100
OpReturn
OpFunctionEnd
%compute_main = OpFunction %void None %5
%24 = OpLabel
%25 = OpFunctionCall %void %atomicSub_051100
OpReturn
OpFunctionEnd

View File

@@ -0,0 +1,20 @@
[[block]]
struct SB_RW {
arg_0 : atomic<i32>;
};
[[group(0), binding(0)]] var<storage, read_write> sb_rw : SB_RW;
fn atomicSub_051100() {
var res : i32 = atomicSub(&(sb_rw.arg_0), 1);
}
[[stage(fragment)]]
fn fragment_main() {
atomicSub_051100();
}
[[stage(compute), workgroup_size(1)]]
fn compute_main() {
atomicSub_051100();
}

View File

@@ -0,0 +1,35 @@
// Copyright 2021 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
////////////////////////////////////////////////////////////////////////////////
// File generated by tools/intrinsic-gen
// using the template:
// test/intrinsics/intrinsics.wgsl.tmpl
// and the intrinsic defintion file:
// src/intrinsics.def
//
// Do not modify this file directly
////////////////////////////////////////////////////////////////////////////////
var<workgroup> arg_0: atomic<u32>;
// fn atomicSub(ptr<workgroup, atomic<u32>, read_write>, u32) -> u32
fn atomicSub_0d26c2() {
var res: u32 = atomicSub(&arg_0, 1u);
}
[[stage(compute), workgroup_size(1)]]
fn compute_main() {
atomicSub_0d26c2();
}

View File

@@ -0,0 +1,26 @@
groupshared uint arg_0;
void atomicSub_0d26c2() {
uint atomic_result = 0u;
InterlockedAdd(arg_0, -1u, atomic_result);
uint res = atomic_result;
}
struct tint_symbol_1 {
uint local_invocation_index : SV_GroupIndex;
};
void compute_main_inner(uint local_invocation_index) {
{
uint atomic_result_1 = 0u;
InterlockedExchange(arg_0, 0u, atomic_result_1);
}
GroupMemoryBarrierWithGroupSync();
atomicSub_0d26c2();
}
[numthreads(1, 1, 1)]
void compute_main(tint_symbol_1 tint_symbol) {
compute_main_inner(tint_symbol.local_invocation_index);
return;
}

View File

@@ -0,0 +1,21 @@
#include <metal_stdlib>
using namespace metal;
void atomicSub_0d26c2(threadgroup atomic_uint* const tint_symbol) {
uint res = atomic_fetch_sub_explicit(tint_symbol, 1u, memory_order_relaxed);
}
void compute_main_inner(uint local_invocation_index, threadgroup atomic_uint* const tint_symbol_1) {
{
atomic_store_explicit(tint_symbol_1, uint(), memory_order_relaxed);
}
threadgroup_barrier(mem_flags::mem_threadgroup);
atomicSub_0d26c2(tint_symbol_1);
}
kernel void compute_main(uint local_invocation_index [[thread_index_in_threadgroup]]) {
threadgroup atomic_uint tint_symbol_2;
compute_main_inner(local_invocation_index, &(tint_symbol_2));
return;
}

View File

@@ -0,0 +1,52 @@
; SPIR-V
; Version: 1.3
; Generator: Google Tint Compiler; 0
; Bound: 31
; Schema: 0
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %compute_main "compute_main" %local_invocation_index_1
OpExecutionMode %compute_main LocalSize 1 1 1
OpName %local_invocation_index_1 "local_invocation_index_1"
OpName %arg_0 "arg_0"
OpName %atomicSub_0d26c2 "atomicSub_0d26c2"
OpName %res "res"
OpName %compute_main_inner "compute_main_inner"
OpName %local_invocation_index "local_invocation_index"
OpName %compute_main "compute_main"
OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
%uint = OpTypeInt 32 0
%_ptr_Input_uint = OpTypePointer Input %uint
%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint
%arg_0 = OpVariable %_ptr_Workgroup_uint Workgroup
%void = OpTypeVoid
%6 = OpTypeFunction %void
%uint_2 = OpConstant %uint 2
%uint_0 = OpConstant %uint 0
%uint_1 = OpConstant %uint 1
%_ptr_Function_uint = OpTypePointer Function %uint
%17 = OpConstantNull %uint
%18 = OpTypeFunction %void %uint
%uint_264 = OpConstant %uint 264
%atomicSub_0d26c2 = OpFunction %void None %6
%9 = OpLabel
%res = OpVariable %_ptr_Function_uint Function %17
%10 = OpAtomicISub %uint %arg_0 %uint_2 %uint_0 %uint_1
OpStore %res %10
OpReturn
OpFunctionEnd
%compute_main_inner = OpFunction %void None %18
%local_invocation_index = OpFunctionParameter %uint
%21 = OpLabel
OpAtomicStore %arg_0 %uint_2 %uint_0 %17
OpControlBarrier %uint_2 %uint_2 %uint_264
%26 = OpFunctionCall %void %atomicSub_0d26c2
OpReturn
OpFunctionEnd
%compute_main = OpFunction %void None %6
%28 = OpLabel
%30 = OpLoad %uint %local_invocation_index_1
%29 = OpFunctionCall %void %compute_main_inner %30
OpReturn
OpFunctionEnd

View File

@@ -0,0 +1,10 @@
var<workgroup> arg_0 : atomic<u32>;
fn atomicSub_0d26c2() {
var res : u32 = atomicSub(&(arg_0), 1u);
}
[[stage(compute), workgroup_size(1)]]
fn compute_main() {
atomicSub_0d26c2();
}

View File

@@ -0,0 +1,44 @@
// Copyright 2021 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
////////////////////////////////////////////////////////////////////////////////
// File generated by tools/intrinsic-gen
// using the template:
// test/intrinsics/intrinsics.wgsl.tmpl
// and the intrinsic defintion file:
// src/intrinsics.def
//
// Do not modify this file directly
////////////////////////////////////////////////////////////////////////////////
[[block]]
struct SB_RW {
arg_0: atomic<u32>;
};
[[group(0), binding(0)]] var<storage, read_write> sb_rw : SB_RW;
// fn atomicSub(ptr<storage, atomic<u32>, read_write>, u32) -> u32
fn atomicSub_15bfc9() {
var res: u32 = atomicSub(&sb_rw.arg_0, 1u);
}
[[stage(fragment)]]
fn fragment_main() {
atomicSub_15bfc9();
}
[[stage(compute), workgroup_size(1)]]
fn compute_main() {
atomicSub_15bfc9();
}

View File

@@ -0,0 +1,22 @@
uint atomicSub_1(RWByteAddressBuffer buffer, uint offset, uint value) {
uint original_value = 0;
buffer.InterlockedAdd(offset, -value, original_value);
return original_value;
}
RWByteAddressBuffer sb_rw : register(u0, space0);
void atomicSub_15bfc9() {
uint res = atomicSub_1(sb_rw, 0u, 1u);
}
void fragment_main() {
atomicSub_15bfc9();
return;
}
[numthreads(1, 1, 1)]
void compute_main() {
atomicSub_15bfc9();
return;
}

View File

@@ -0,0 +1,21 @@
#include <metal_stdlib>
using namespace metal;
struct SB_RW {
/* 0x0000 */ atomic_uint arg_0;
};
void atomicSub_15bfc9(device SB_RW& sb_rw) {
uint res = atomic_fetch_sub_explicit(&(sb_rw.arg_0), 1u, memory_order_relaxed);
}
fragment void fragment_main(device SB_RW& sb_rw [[buffer(0)]]) {
atomicSub_15bfc9(sb_rw);
return;
}
kernel void compute_main(device SB_RW& sb_rw [[buffer(0)]]) {
atomicSub_15bfc9(sb_rw);
return;
}

View File

@@ -0,0 +1,51 @@
; SPIR-V
; Version: 1.3
; Generator: Google Tint Compiler; 0
; Bound: 24
; Schema: 0
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %fragment_main "fragment_main"
OpEntryPoint GLCompute %compute_main "compute_main"
OpExecutionMode %fragment_main OriginUpperLeft
OpExecutionMode %compute_main LocalSize 1 1 1
OpName %SB_RW "SB_RW"
OpMemberName %SB_RW 0 "arg_0"
OpName %sb_rw "sb_rw"
OpName %atomicSub_15bfc9 "atomicSub_15bfc9"
OpName %res "res"
OpName %fragment_main "fragment_main"
OpName %compute_main "compute_main"
OpDecorate %SB_RW Block
OpMemberDecorate %SB_RW 0 Offset 0
OpDecorate %sb_rw DescriptorSet 0
OpDecorate %sb_rw Binding 0
%uint = OpTypeInt 32 0
%SB_RW = OpTypeStruct %uint
%_ptr_StorageBuffer_SB_RW = OpTypePointer StorageBuffer %SB_RW
%sb_rw = OpVariable %_ptr_StorageBuffer_SB_RW StorageBuffer
%void = OpTypeVoid
%5 = OpTypeFunction %void
%uint_1 = OpConstant %uint 1
%uint_0 = OpConstant %uint 0
%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
%_ptr_Function_uint = OpTypePointer Function %uint
%17 = OpConstantNull %uint
%atomicSub_15bfc9 = OpFunction %void None %5
%8 = OpLabel
%res = OpVariable %_ptr_Function_uint Function %17
%14 = OpAccessChain %_ptr_StorageBuffer_uint %sb_rw %uint_0
%9 = OpAtomicISub %uint %14 %uint_1 %uint_0 %uint_1
OpStore %res %9
OpReturn
OpFunctionEnd
%fragment_main = OpFunction %void None %5
%19 = OpLabel
%20 = OpFunctionCall %void %atomicSub_15bfc9
OpReturn
OpFunctionEnd
%compute_main = OpFunction %void None %5
%22 = OpLabel
%23 = OpFunctionCall %void %atomicSub_15bfc9
OpReturn
OpFunctionEnd

View File

@@ -0,0 +1,20 @@
[[block]]
struct SB_RW {
arg_0 : atomic<u32>;
};
[[group(0), binding(0)]] var<storage, read_write> sb_rw : SB_RW;
fn atomicSub_15bfc9() {
var res : u32 = atomicSub(&(sb_rw.arg_0), 1u);
}
[[stage(fragment)]]
fn fragment_main() {
atomicSub_15bfc9();
}
[[stage(compute), workgroup_size(1)]]
fn compute_main() {
atomicSub_15bfc9();
}

View File

@@ -0,0 +1,35 @@
// Copyright 2021 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
////////////////////////////////////////////////////////////////////////////////
// File generated by tools/intrinsic-gen
// using the template:
// test/intrinsics/intrinsics.wgsl.tmpl
// and the intrinsic defintion file:
// src/intrinsics.def
//
// Do not modify this file directly
////////////////////////////////////////////////////////////////////////////////
var<workgroup> arg_0: atomic<i32>;
// fn atomicSub(ptr<workgroup, atomic<i32>, read_write>, i32) -> i32
fn atomicSub_77883a() {
var res: i32 = atomicSub(&arg_0, 1);
}
[[stage(compute), workgroup_size(1)]]
fn compute_main() {
atomicSub_77883a();
}

View File

@@ -0,0 +1,26 @@
groupshared int arg_0;
void atomicSub_77883a() {
int atomic_result = 0;
InterlockedAdd(arg_0, -1, atomic_result);
int res = atomic_result;
}
struct tint_symbol_1 {
uint local_invocation_index : SV_GroupIndex;
};
void compute_main_inner(uint local_invocation_index) {
{
int atomic_result_1 = 0;
InterlockedExchange(arg_0, 0, atomic_result_1);
}
GroupMemoryBarrierWithGroupSync();
atomicSub_77883a();
}
[numthreads(1, 1, 1)]
void compute_main(tint_symbol_1 tint_symbol) {
compute_main_inner(tint_symbol.local_invocation_index);
return;
}

View File

@@ -0,0 +1,21 @@
#include <metal_stdlib>
using namespace metal;
void atomicSub_77883a(threadgroup atomic_int* const tint_symbol) {
int res = atomic_fetch_sub_explicit(tint_symbol, 1, memory_order_relaxed);
}
void compute_main_inner(uint local_invocation_index, threadgroup atomic_int* const tint_symbol_1) {
{
atomic_store_explicit(tint_symbol_1, int(), memory_order_relaxed);
}
threadgroup_barrier(mem_flags::mem_threadgroup);
atomicSub_77883a(tint_symbol_1);
}
kernel void compute_main(uint local_invocation_index [[thread_index_in_threadgroup]]) {
threadgroup atomic_int tint_symbol_2;
compute_main_inner(local_invocation_index, &(tint_symbol_2));
return;
}

View File

@@ -0,0 +1,53 @@
; SPIR-V
; Version: 1.3
; Generator: Google Tint Compiler; 0
; Bound: 32
; Schema: 0
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %compute_main "compute_main" %local_invocation_index_1
OpExecutionMode %compute_main LocalSize 1 1 1
OpName %local_invocation_index_1 "local_invocation_index_1"
OpName %arg_0 "arg_0"
OpName %atomicSub_77883a "atomicSub_77883a"
OpName %res "res"
OpName %compute_main_inner "compute_main_inner"
OpName %local_invocation_index "local_invocation_index"
OpName %compute_main "compute_main"
OpDecorate %local_invocation_index_1 BuiltIn LocalInvocationIndex
%uint = OpTypeInt 32 0
%_ptr_Input_uint = OpTypePointer Input %uint
%local_invocation_index_1 = OpVariable %_ptr_Input_uint Input
%int = OpTypeInt 32 1
%_ptr_Workgroup_int = OpTypePointer Workgroup %int
%arg_0 = OpVariable %_ptr_Workgroup_int Workgroup
%void = OpTypeVoid
%7 = OpTypeFunction %void
%uint_2 = OpConstant %uint 2
%uint_0 = OpConstant %uint 0
%int_1 = OpConstant %int 1
%_ptr_Function_int = OpTypePointer Function %int
%18 = OpConstantNull %int
%19 = OpTypeFunction %void %uint
%uint_264 = OpConstant %uint 264
%atomicSub_77883a = OpFunction %void None %7
%10 = OpLabel
%res = OpVariable %_ptr_Function_int Function %18
%11 = OpAtomicISub %int %arg_0 %uint_2 %uint_0 %int_1
OpStore %res %11
OpReturn
OpFunctionEnd
%compute_main_inner = OpFunction %void None %19
%local_invocation_index = OpFunctionParameter %uint
%22 = OpLabel
OpAtomicStore %arg_0 %uint_2 %uint_0 %18
OpControlBarrier %uint_2 %uint_2 %uint_264
%27 = OpFunctionCall %void %atomicSub_77883a
OpReturn
OpFunctionEnd
%compute_main = OpFunction %void None %7
%29 = OpLabel
%31 = OpLoad %uint %local_invocation_index_1
%30 = OpFunctionCall %void %compute_main_inner %31
OpReturn
OpFunctionEnd

View File

@@ -0,0 +1,10 @@
var<workgroup> arg_0 : atomic<i32>;
fn atomicSub_77883a() {
var res : i32 = atomicSub(&(arg_0), 1);
}
[[stage(compute), workgroup_size(1)]]
fn compute_main() {
atomicSub_77883a();
}