AST -> SPV: Add basic atomic_uint and atomic*() built-in function functionality.
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index eef4e53..42a3b82 100644
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -99,6 +99,7 @@
spv::Id createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id operand, bool isFloat);
spv::Id createConversion(glslang::TOperator op, spv::Decoration precision, spv::Id destTypeId, spv::Id operand);
spv::Id makeSmearedConstant(spv::Id constant, int vectorSize);
+ spv::Id createAtomicOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands);
spv::Id createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands);
spv::Id createNoArgOperation(glslang::TOperator op);
spv::Id getSymbolId(const glslang::TIntermSymbol* node);
@@ -718,6 +719,16 @@
builder.createNoResultOp(spv::OpEndStreamPrimitive, operand);
return false;
+ case glslang::EOpAtomicCounterIncrement:
+ case glslang::EOpAtomicCounterDecrement:
+ case glslang::EOpAtomicCounter:
+ {
+ // Handle all of the atomics in one place, in createAtomicOperation()
+ std::vector<spv::Id> operands;
+ operands.push_back(operand);
+ result = createAtomicOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands);
+ return false;
+ }
default:
spv::MissingFunctionality("glslang unary");
break;
@@ -733,6 +744,7 @@
bool reduceComparison = true;
bool isMatrix = false;
bool noReturnValue = false;
+ bool atomic = false;
assert(node->getOp());
@@ -952,6 +964,17 @@
// These all have 0 operands and will naturally finish up in the code below for 0 operands
break;
+ case glslang::EOpAtomicAdd:
+ case glslang::EOpAtomicMin:
+ case glslang::EOpAtomicMax:
+ case glslang::EOpAtomicAnd:
+ case glslang::EOpAtomicOr:
+ case glslang::EOpAtomicXor:
+ case glslang::EOpAtomicExchange:
+ case glslang::EOpAtomicCompSwap:
+ atomic = true;
+ break;
+
default:
break;
}
@@ -959,7 +982,6 @@
//
// See if it maps to a regular operation.
//
-
if (binOp != glslang::EOpNull) {
glslang::TIntermTyped* left = node->getSequence()[0]->getAsTyped();
glslang::TIntermTyped* right = node->getSequence()[1]->getAsTyped();
@@ -987,6 +1009,9 @@
return false;
}
+ //
+ // Create the list of operands.
+ //
glslang::TIntermSequence& glslangOperands = node->getSequence();
std::vector<spv::Id> operands;
for (int arg = 0; arg < (int)glslangOperands.size(); ++arg) {
@@ -1012,16 +1037,23 @@
else
operands.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangOperands[arg]->getAsTyped()->getType())));
}
- switch (glslangOperands.size()) {
- case 0:
- result = createNoArgOperation(node->getOp());
- break;
- case 1:
- result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands.front(), node->getType().getBasicType() == glslang::EbtFloat || node->getType().getBasicType() == glslang::EbtDouble);
- break;
- default:
- result = createMiscOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands);
- break;
+
+ if (atomic) {
+ // Handle all atomics
+ result = createAtomicOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands);
+ } else {
+ // Pass through to generic operations.
+ switch (glslangOperands.size()) {
+ case 0:
+ result = createNoArgOperation(node->getOp());
+ break;
+ case 1:
+ result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands.front(), node->getType().getBasicType() == glslang::EbtFloat || node->getType().getBasicType() == glslang::EbtDouble);
+ break;
+ default:
+ result = createMiscOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands);
+ break;
+ }
}
if (noReturnValue)
@@ -1272,6 +1304,10 @@
case glslang::EbtUint:
spvType = builder.makeUintType(32);
break;
+ case glslang::EbtAtomicUint:
+ spv::TbdFunctionality("Is atomic_uint an opaque handle in the uniform storage class, or an addresses in the atomic storage class?");
+ spvType = builder.makeUintType(32);
+ break;
case glslang::EbtSampler:
{
const glslang::TSampler& sampler = type.getSampler();
@@ -2245,6 +2281,67 @@
return builder.makeCompositeConstant(vectorTypeId, components);
}
+// For glslang ops that map to SPV atomic opCodes
+spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands)
+{
+ spv::Op opCode = spv::OpNop;
+
+ switch (op) {
+ case glslang::EOpAtomicAdd:
+ opCode = spv::OpAtomicIAdd;
+ break;
+ case glslang::EOpAtomicMin:
+ opCode = spv::OpAtomicIMin;
+ break;
+ case glslang::EOpAtomicMax:
+ opCode = spv::OpAtomicIMax;
+ break;
+ case glslang::EOpAtomicAnd:
+ opCode = spv::OpAtomicAnd;
+ break;
+ case glslang::EOpAtomicOr:
+ opCode = spv::OpAtomicOr;
+ break;
+ case glslang::EOpAtomicXor:
+ opCode = spv::OpAtomicXor;
+ break;
+ case glslang::EOpAtomicExchange:
+ opCode = spv::OpAtomicExchange;
+ break;
+ case glslang::EOpAtomicCompSwap:
+ opCode = spv::OpAtomicCompareExchange;
+ break;
+ case glslang::EOpAtomicCounterIncrement:
+ opCode = spv::OpAtomicIIncrement;
+ break;
+ case glslang::EOpAtomicCounterDecrement:
+ opCode = spv::OpAtomicIDecrement;
+ break;
+ case glslang::EOpAtomicCounter:
+ opCode = spv::OpAtomicLoad;
+ break;
+ default:
+ spv::MissingFunctionality("missing nested atomic");
+ break;
+ }
+
+ // Sort out the operands
+ // - mapping from glslang -> SPV
+ // - there are extra SPV operands with no glslang source
+ std::vector<spv::Id> spvAtomicOperands; // hold the spv operands
+ auto opIt = operands.begin(); // walk the glslang operands
+ spvAtomicOperands.push_back(*(opIt++));
+ spvAtomicOperands.push_back(spv::ExecutionScopeDevice); // TBD: what is the correct scope?
+ spvAtomicOperands.push_back( spv::MemorySemanticsMaskNone); // TBD: what are the correct memory semantics?
+
+ // Add the rest of the operands, skipping the first one, which was dealt with above.
+ // For some ops, there are none, for some 1, for compare-exchange, 2.
+ for (; opIt != operands.end(); ++opIt)
+ spvAtomicOperands.push_back(*opIt);
+
+ return builder.createOp(opCode, typeId, spvAtomicOperands);
+}
+
spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands)
{
spv::Op opCode = spv::OpNop;
@@ -2298,6 +2395,7 @@
case glslang::EOpRefract:
libCall = GLSL_STD_450::Refract;
break;
+
default:
return 0;
}
@@ -2319,7 +2417,7 @@
id = builder.createBinOp(opCode, typeId, operands[0], operands[1]);
break;
case 3:
- id = builder.createTernaryOp(opCode, typeId, operands[0], operands[1], operands[2]);
+ id = builder.createTriOp(opCode, typeId, operands[0], operands[1], operands[2]);
break;
default:
// These do not exist yet
diff --git a/SPIRV/SpvBuilder.cpp b/SPIRV/SpvBuilder.cpp
index 91cb2d0..d62d2bc 100644
--- a/SPIRV/SpvBuilder.cpp
+++ b/SPIRV/SpvBuilder.cpp
@@ -45,6 +45,8 @@
#include <stdio.h>
#include <stdlib.h>
+#include <unordered_set>
+
#include "SpvBuilder.h"
#ifndef _WIN32
@@ -989,12 +991,11 @@
return op->getResultId();
}
-Id Builder::createTernaryOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)
+Id Builder::createOp(Op opCode, Id typeId, std::vector<Id>& operands)
{
Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
- op->addIdOperand(op1);
- op->addIdOperand(op2);
- op->addIdOperand(op3);
+ for (auto operand : operands)
+ op->addIdOperand(operand);
buildPoint->addInstruction(op);
return op->getResultId();
@@ -2172,17 +2173,22 @@
}
}
+void TbdFunctionality(const char* tbd)
+{
+ static std::unordered_set<const char*> issued;
+
+ if (issued.find(tbd) == issued.end()) {
+ printf("TBD functionality: %s\n", tbd);
+ issued.insert(tbd);
+ }
+}
+
void MissingFunctionality(const char* fun)
{
printf("Missing functionality: %s\n", fun);
exit(1);
}
-void ValidationError(const char* error)
-{
- printf("Validation Error: %s\n", error);
-}
-
Builder::Loop::Loop(Builder& builder, bool testFirstArg)
: function(&builder.getBuildPoint()->getParent()),
header(new Block(builder.getUniqueId(), *function)),
diff --git a/SPIRV/SpvBuilder.h b/SPIRV/SpvBuilder.h
index c220960..e8711e3 100644
--- a/SPIRV/SpvBuilder.h
+++ b/SPIRV/SpvBuilder.h
@@ -238,7 +238,7 @@
Id createUnaryOp(Op, Id typeId, Id operand);
Id createBinOp(Op, Id typeId, Id operand1, Id operand2);
Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
- Id createTernaryOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
+ Id createOp(Op, Id typeId, std::vector<Id>& operands);
Id createFunctionCall(spv::Function*, std::vector<spv::Id>&);
// Take an rvalue (source) and a set of channels to extract from it to
@@ -564,8 +564,11 @@
std::stack<Loop> loops;
}; // end Builder class
+// Use for non-fatal notes about what's not complete
+void TbdFunctionality(const char*);
+
+// Use for fatal missing functionality
void MissingFunctionality(const char*);
-void ValidationError(const char* error);
}; // end spv namespace
diff --git a/Test/baseResults/spv.atomic.comp.out b/Test/baseResults/spv.atomic.comp.out
new file mode 100644
index 0000000..12da7db
--- /dev/null
+++ b/Test/baseResults/spv.atomic.comp.out
@@ -0,0 +1,142 @@
+spv.atomic.comp
+Warning, version 310 is not yet complete; most version-specific features are present, but some are missing.
+
+
+Linked compute stage:
+
+
+TBD functionality: Is atomic_uint an opaque handle in the uniform storage class, or an addresses in the atomic storage class?
+TBD functionality: Is atomic_uint an opaque handle in the uniform storage class, or an addresses in the atomic storage class?
+TBD functionality: Is atomic_uint an opaque handle in the uniform storage class, or an addresses in the atomic storage class?
+TBD functionality: Is atomic_uint an opaque handle in the uniform storage class, or an addresses in the atomic storage class?
+TBD functionality: Is atomic_uint an opaque handle in the uniform storage class, or an addresses in the atomic storage class?
+// Module Version 99
+// Generated by (magic number): 51a00bb
+// Id's are bound by 75
+
+ Source ESSL 310
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel Logical GLSL450
+ EntryPoint GLCompute 4
+ Name 4 "main"
+ Name 11 "func(au1;"
+ Name 10 "c"
+ Name 13 "atoms("
+ Name 20 "counter"
+ Name 21 "param"
+ Name 24 "val"
+ Name 28 "countArr"
+ Name 38 "origi"
+ Name 40 "atomi"
+ Name 44 "origu"
+ Name 46 "atomu"
+ Name 48 "value"
+ Name 72 "arrX"
+ Name 73 "arrY"
+ Name 74 "arrZ"
+ Decorate 20(counter) PrecisionHigh
+ Decorate 20(counter) Binding 0
+ Decorate 24(val) PrecisionHigh
+ Decorate 28(countArr) PrecisionHigh
+ Decorate 28(countArr) Binding 0
+ Decorate 38(origi) PrecisionHigh
+ Decorate 40(atomi) PrecisionHigh
+ Decorate 44(origu) PrecisionHigh
+ Decorate 46(atomu) PrecisionHigh
+ Decorate 48(value) PrecisionHigh
+ Decorate 72(arrX) PrecisionHigh
+ Decorate 72(arrX) NoStaticUse
+ Decorate 73(arrY) PrecisionHigh
+ Decorate 73(arrY) NoStaticUse
+ Decorate 74(arrZ) PrecisionHigh
+ Decorate 74(arrZ) NoStaticUse
+ 2: TypeVoid
+ 3: TypeFunction 2
+ 7: TypeInt 32 0
+ 8: TypePointer Function 7(int)
+ 9: TypeFunction 7(int) 8(ptr)
+ 19: TypePointer UniformConstant 7(int)
+ 20(counter): 19(ptr) Variable UniformConstant
+ 25: 7(int) Constant 4
+ 26: TypeArray 7(int) 25
+ 27: TypePointer UniformConstant 26
+ 28(countArr): 27(ptr) Variable UniformConstant
+ 29: TypeInt 32 1
+ 30: 29(int) Constant 2
+ 37: TypePointer Function 29(int)
+ 39: TypePointer WorkgroupLocal 29(int)
+ 40(atomi): 39(ptr) Variable WorkgroupLocal
+ 42: 29(int) Constant 3
+ 45: TypePointer WorkgroupLocal 7(int)
+ 46(atomu): 45(ptr) Variable WorkgroupLocal
+ 48(value): 19(ptr) Variable UniformConstant
+ 52: 7(int) Constant 7
+ 60: 29(int) Constant 7
+ 66: 7(int) Constant 10
+ 69: 7(int) Constant 1
+ 70: TypeArray 29(int) 69
+ 71: TypePointer PrivateGlobal 70
+ 72(arrX): 71(ptr) Variable PrivateGlobal
+ 73(arrY): 71(ptr) Variable PrivateGlobal
+ 74(arrZ): 71(ptr) Variable PrivateGlobal
+ 4(main): 2 Function None 3
+ 5: Label
+ 21(param): 8(ptr) Variable Function
+ 24(val): 8(ptr) Variable Function
+ MemoryBarrier Device AtomicCounterMemory
+ 22: 7(int) Load 20(counter)
+ Store 21(param) 22
+ 23: 7(int) FunctionCall 11(func(au1;) 21(param)
+ 31: 19(ptr) AccessChain 28(countArr) 30
+ 32: 7(int) Load 31
+ 33: 7(int) AtomicLoad 32 Device None
+ 34: 7(int) Load 31
+ Store 24(val) 34
+ 35: 7(int) Load 20(counter)
+ 36: 7(int) AtomicIDecrement 35 Device None
+ Branch 6
+ 6: Label
+ Return
+ FunctionEnd
+ 11(func(au1;): 7(int) Function None 9
+ 10(c): 8(ptr) FunctionParameter
+ 12: Label
+ 15: 7(int) Load 10(c)
+ 16: 7(int) AtomicIIncrement 15 Device None
+ 17: 7(int) Load 10(c)
+ ReturnValue 17
+ FunctionEnd
+ 13(atoms(): 2 Function None 3
+ 14: Label
+ 38(origi): 37(ptr) Variable Function
+ 44(origu): 8(ptr) Variable Function
+ 41: 29(int) Load 40(atomi)
+ 43: 29(int) AtomicIAdd 41 Device None 42
+ Store 38(origi) 43
+ 47: 7(int) Load 46(atomu)
+ 49: 7(int) Load 48(value)
+ 50: 7(int) AtomicAnd 47 Device None 49
+ Store 44(origu) 50
+ 51: 7(int) Load 46(atomu)
+ 53: 7(int) AtomicOr 51 Device None 52
+ Store 44(origu) 53
+ 54: 7(int) Load 46(atomu)
+ 55: 7(int) AtomicXor 54 Device None 52
+ Store 44(origu) 55
+ 56: 7(int) Load 46(atomu)
+ 57: 7(int) Load 48(value)
+ 58: 7(int) AtomicIMin 56 Device None 57
+ Store 44(origu) 58
+ 59: 29(int) Load 40(atomi)
+ 61: 29(int) AtomicIMax 59 Device None 60
+ Store 38(origi) 61
+ 62: 29(int) Load 40(atomi)
+ 63: 29(int) Load 38(origi)
+ 64: 29(int) AtomicExchange 62 Device None 63
+ Store 38(origi) 64
+ 65: 7(int) Load 46(atomu)
+ 67: 7(int) Load 48(value)
+ 68: 7(int) AtomicCompareExchange 65 Device None 66 67
+ Store 44(origu) 68
+ Return
+ FunctionEnd
diff --git a/Test/spv.atomic.comp b/Test/spv.atomic.comp
new file mode 100644
index 0000000..1a91b3e
--- /dev/null
+++ b/Test/spv.atomic.comp
@@ -0,0 +1,38 @@
+#version 310 es
+
+layout(binding = 0) uniform atomic_uint counter;
+
+layout(binding = 0, offset = 4) uniform atomic_uint countArr[4];
+uniform uint value;
+
+int arrX[gl_WorkGroupSize.x];
+int arrY[gl_WorkGroupSize.y];
+int arrZ[gl_WorkGroupSize.z];
+
+uint func(atomic_uint c)
+{
+ return atomicCounterIncrement(c);
+}
+
+void main()
+{
+ memoryBarrierAtomicCounter();
+ func(counter);
+ uint val = atomicCounter(countArr[2]);
+ atomicCounterDecrement(counter);
+}
+
+shared int atomi;
+shared uint atomu;
+
+void atoms()
+{
+ int origi = atomicAdd(atomi, 3);
+ uint origu = atomicAnd(atomu, value);
+ origu = atomicOr(atomu, 7u);
+ origu = atomicXor(atomu, 7u);
+ origu = atomicMin(atomu, value);
+ origi = atomicMax(atomi, 7);
+ origi = atomicExchange(atomi, origi);
+ origu = atomicCompSwap(atomu, 10u, value);
+}
diff --git a/Test/test-spirv-list b/Test/test-spirv-list
index fed5688..ccfa068 100644
--- a/Test/test-spirv-list
+++ b/Test/test-spirv-list
@@ -78,3 +78,4 @@
spv.varyingArrayIndirect.frag
spv.voidFunction.frag
spv.whileLoop.frag
+spv.atomic.comp