From 15bacd3b1bffb601413bc5e1f1d0cc3b55b9a5b4 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Sun, 19 Jan 2020 16:36:33 -0300 Subject: [PATCH] atomic: Add memory atomic instructions --- include/sirit/sirit.h | 102 +++++++++++++++++++++++++ src/CMakeLists.txt | 1 + src/instructions/atomic.cpp | 148 ++++++++++++++++++++++++++++++++++++ 3 files changed, 251 insertions(+) create mode 100644 src/instructions/atomic.cpp diff --git a/include/sirit/sirit.h b/include/sirit/sirit.h index 25eed05..a0ff027 100644 --- a/include/sirit/sirit.h +++ b/include/sirit/sirit.h @@ -965,6 +965,108 @@ public: /// group xor'ed with mask. Id OpGroupNonUniformShuffleXor(Id result_type, spv::Scope scope, Id value, Id mask); + // Atomic + + /// Atomically load through Pointer using the given Semantics. All subparts of the value that is + /// loaded will be read atomically with respect to all other atomic accesses to it within Scope. + Id OpAtomicLoad(Id result_type, Id pointer, Id memory, Id semantics); + + /// Atomically store through Pointer using the given Semantics. All subparts of Value will be + /// written atomically with respect to all other atomic accesses to it within Scope. + Id OpAtomicStore(Id pointer, Id memory, Id semantics, Id value); + + /// Perform the following steps atomically with respect to any other atomic accesses within + /// Scope to the same location: + /// 1) load through Pointer to get an Original Value, + /// 2) get a New Value from copying Value, and + /// 3) store the New Value back through Pointer. + Id OpAtomicExchange(Id result_type, Id pointer, Id memory, Id semantics, Id value); + + /// Perform the following steps atomically with respect to any other atomic accesses within + /// Scope to the same location: + /// 1) load through Pointer to get an Original Value, + /// 2) get a New Value from Value only if Original Value equals Comparator, and + /// 3) store the New Value back through Pointer only if 'Original Value equaled Comparator. + Id OpAtomicCompareExchange(Id result_type, Id pointer, Id memory, Id equal, Id unequal, + Id value, Id comparator); + + /// Perform the following steps atomically with respect to any other atomic accesses within + /// Scope to the same location: + /// 1) load through Pointer to get an Original Value, + /// 2) get a New Value through integer addition of 1 to Original Value, and + /// 3) store the New Value back through Pointer. + Id OpAtomicIIncrement(Id result_type, Id pointer, Id memory, Id semantics); + + /// Perform the following steps atomically with respect to any other atomic accesses within + /// Scope to the same location: + /// 1) load through Pointer to get an Original Value, + /// 2) get a New Value through integer subtraction of 1 from Original Value, and + /// 3) store the New Value back through Pointer. + Id OpAtomicIDecrement(Id result_type, Id pointer, Id memory, Id semantics); + + /// Perform the following steps atomically with respect to any other atomic accesses within + /// Scope to the same location: + /// 1) load through Pointer to get an Original Value, + /// 2) get a New Value by integer addition of Original Value and Value, and + /// 3) store the New Value back through Pointer. + Id OpAtomicIAdd(Id result_type, Id pointer, Id memory, Id semantics, Id value); + + /// Perform the following steps atomically with respect to any other atomic accesses within + /// Scope to the same location: + /// 1) load through Pointer to get an Original Value, + /// 2) get a New Value by integer subtraction of Value from Original Value, and + /// 3) store the New Value back through Pointer. + Id OpAtomicISub(Id result_type, Id pointer, Id memory, Id semantics, Id value); + + /// Perform the following steps atomically with respect to any other atomic accesses within + /// Scope to the same location: + /// 1) load through Pointer to get an Original Value, + /// 2) get a New Value by finding the smallest signed integer of Original Value and Value, and + /// 3) store the New Value back through Pointer. + Id OpAtomicSMin(Id result_type, Id pointer, Id memory, Id semantics, Id value); + + /// Perform the following steps atomically with respect to any other atomic accesses within + /// Scope to the same location: + /// 1) load through Pointer to get an Original Value, + /// 2) get a New Value by finding the smallest unsigned integer of Original Value and Value, and + /// 3) store the New Value back through Pointer. + Id OpAtomicUMin(Id result_type, Id pointer, Id memory, Id semantics, Id value); + + /// Perform the following steps atomically with respect to any other atomic accesses within + /// Scope to the same location: + /// 1) load through Pointer to get an Original Value, + /// 2) get a New Value by finding the largest signed integer of Original Value and Value, and + /// 3) store the New Value back through Pointer. + Id OpAtomicSMax(Id result_type, Id pointer, Id memory, Id semantics, Id value); + + /// Perform the following steps atomically with respect to any other atomic accesses within + /// Scope to the same location: + /// 1) load through Pointer to get an Original Value, + /// 2) get a New Value by finding the largest unsigned integer of Original Value and Value, and + /// 3) store the New Value back through Pointer. + Id OpAtomicUMax(Id result_type, Id pointer, Id memory, Id semantics, Id value); + + /// Perform the following steps atomically with respect to any other atomic accesses within + /// Scope to the same location: + /// 1) load through Pointer to get an Original Value, + /// 2) get a New Value by the bitwise AND of Original Value and Value, and + /// 3) store the New Value back through Pointer. + Id OpAtomicAnd(Id result_type, Id pointer, Id memory, Id semantics, Id value); + + /// Perform the following steps atomically with respect to any other atomic accesses within + /// Scope to the same location: + /// 1) load through Pointer to get an Original Value, + /// 2) get a New Value by the bitwise OR of Original Value and Value, and + /// 3) store the New Value back through Pointer. + Id OpAtomicOr(Id result_type, Id pointer, Id memory, Id semantics, Id value); + + /// Perform the following steps atomically with respect to any other atomic accesses within + /// Scope to the same location: + /// 1) load through Pointer to get an Original Value, + /// 2) get a New Value by the bitwise exclusive OR of Original Value and Value, and + /// 3) store the New Value back through Pointer. + Id OpAtomicXor(Id result_type, Id pointer, Id memory, Id semantics, Id value); + private: Id AddCode(std::unique_ptr op); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1bcb6e3..5d62c7c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -28,6 +28,7 @@ add_library(sirit instructions/image.cpp instructions/group.cpp instructions/barrier.cpp + instructions/atomic.cpp ) target_compile_options(sirit PRIVATE ${SIRIT_CXX_FLAGS}) diff --git a/src/instructions/atomic.cpp b/src/instructions/atomic.cpp new file mode 100644 index 0000000..a11f0f8 --- /dev/null +++ b/src/instructions/atomic.cpp @@ -0,0 +1,148 @@ +/* This file is part of the sirit project. + * Copyright (c) 2019 sirit + * This software may be used and distributed according to the terms of the + * 3-Clause BSD License + */ + +#include "common_types.h" +#include "op.h" +#include "sirit/sirit.h" + +namespace Sirit { + +Id Module::OpAtomicLoad(Id result_type, Id pointer, Id memory, Id semantics) { + auto op{std::make_unique(spv::Op::OpAtomicLoad, bound++, result_type)}; + op->Add(pointer); + op->Add(memory); + op->Add(semantics); + return AddCode(std::move(op)); +} + +Id Module::OpAtomicStore(Id pointer, Id memory, Id semantics, Id value) { + auto op{std::make_unique(spv::Op::OpAtomicStore)}; + op->Add(pointer); + op->Add(memory); + op->Add(semantics); + op->Add(value); + return AddCode(std::move(op)); +} + +Id Module::OpAtomicExchange(Id result_type, Id pointer, Id memory, Id semantics, Id value) { + auto op{std::make_unique(spv::Op::OpAtomicExchange, bound++, result_type)}; + op->Add(pointer); + op->Add(memory); + op->Add(semantics); + op->Add(value); + return AddCode(std::move(op)); +} + +Id Module::OpAtomicCompareExchange(Id result_type, Id pointer, Id memory, Id equal, Id unequal, + Id value, Id comparator) { + auto op{std::make_unique(spv::Op::OpAtomicCompareExchange, bound++, result_type)}; + op->Add(pointer); + op->Add(memory); + op->Add(equal)); + op->Add(unequal); + op->Add(value); + op->Add(comparator); + return AddCode(std::move(op)); +} + +Id Module::OpAtomicIIncrement(Id result_type, Id pointer, Id memory, Id semantics) { + auto op{std::make_unique(spv::Op::OpAtomicIIncrement, bound++, result_type)}; + op->Add(pointer); + op->Add(memory); + op->Add(semantics); + return AddCode(std::move(op)); +} + +Id Module::OpAtomicIDecrement(Id result_type, Id pointer, Id memory, Id semantics) { + auto op{std::make_unique(spv::Op::OpAtomicIDecrement, bound++, result_type)}; + op->Add(pointer); + op->Add(memory); + op->Add(semantics); + return AddCode(std::move(op)); +} + +Id Module::OpAtomicIAdd(Id result_type, Id pointer, Id memory, Id semantics, Id value) { + auto op{std::make_unique(spv::Op::OpAtomicIAdd, bound++, result_type)}; + op->Add(pointer); + op->Add(memory); + op->Add(semantics); + op->Add(value); + return AddCode(std::move(op)); +} + +Id Module::OpAtomicISub(Id result_type, Id pointer, Id memory, Id semantics, Id value) { + auto op{std::make_unique(spv::Op::OpAtomicISub, bound++, result_type)}; + op->Add(pointer); + op->Add(memory); + op->Add(semantics); + op->Add(value); + return AddCode(std::move(op)); +} + +Id Module::OpAtomicSMin(Id result_type, Id pointer, Id memory, Id semantics, Id value) { + auto op{std::make_unique(spv::Op::OpAtomicSMin, bound++, result_type)}; + op->Add(pointer); + op->Add(memory); + op->Add(semantics); + op->Add(value); + return AddCode(std::move(op)); +} + +Id Module::OpAtomicUMin(Id result_type, Id pointer, Id memory, Id semantics, Id value) { + auto op{std::make_unique(spv::Op::OpAtomicUMin, bound++, result_type)}; + op->Add(pointer); + op->Add(memory); + op->Add(semantics); + op->Add(value); + return AddCode(std::move(op)); +} + +Id Module::OpAtomicSMax(Id result_type, Id pointer, Id memory, Id semantics, Id value) { + auto op{std::make_unique(spv::Op::OpAtomicSMax, bound++, result_type)}; + op->Add(pointer); + op->Add(memory); + op->Add(semantics); + op->Add(value); + return AddCode(std::move(op)); +} + +Id Module::OpAtomicUMax(Id result_type, Id pointer, Id memory, Id semantics, Id value) { + auto op{std::make_unique(spv::Op::OpAtomicUMax, bound++, result_type)}; + op->Add(pointer); + op->Add(memory); + op->Add(semantics); + op->Add(value); + return AddCode(std::move(op)); +} + +Id Module::OpAtomicAnd(Id result_type, Id pointer, Id memory, Id semantics, Id value) { + auto op{std::make_unique(spv::Op::OpAtomicAnd, bound++, result_type)}; + op->Add(pointer); + op->Add(memory); + op->Add(semantics); + op->Add(value); + return AddCode(std::move(op)); +} + +Id Module::OpAtomicOr(Id result_type, Id pointer, Id memory, Id semantics, Id value) { + auto op{std::make_unique(spv::Op::OpAtomicOr, bound++, result_type)}; + op->Add(pointer); + op->Add(memory); + op->Add(semantics); + op->Add(value); + return AddCode(std::move(op)); +} + +Id Module::OpAtomicXor(Id result_type, Id pointer, Id memory, Id semantics, Id value) { + auto op{std::make_unique(spv::Op::OpAtomicXor, bound++, result_type)}; + op->Add(pointer); + op->Add(memory); + op->Add(semantics); + op->Add(value); + return AddCode(std::move(op)); +} + +} // namespace Sirit