AST -> SPV: Add basic atomic_uint and atomic*() built-in function functionality.
authorJohn Kessenich <cepheus@frii.com>
Thu, 23 Jul 2015 16:22:48 +0000 (10:22 -0600)
committerJohn Kessenich <cepheus@frii.com>
Thu, 23 Jul 2015 16:22:48 +0000 (10:22 -0600)
SPIRV/GlslangToSpv.cpp
SPIRV/SpvBuilder.cpp
SPIRV/SpvBuilder.h
Test/baseResults/spv.atomic.comp.out [new file with mode: 0644]
Test/spv.atomic.comp [new file with mode: 0644]
Test/test-spirv-list

index eef4e53..42a3b82 100644 (file)
@@ -99,6 +99,7 @@ protected:
     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 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI
         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 TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
     bool reduceComparison = true;
     bool isMatrix = false;
     bool noReturnValue = false;
+    bool atomic = false;
 
     assert(node->getOp());
 
@@ -952,6 +964,17 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
         // 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 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
     //
     // 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 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
         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 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
         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 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
     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 @@ spv::Id TGlslangToSpvTraverser::makeSmearedConstant(spv::Id constant, int vector
     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 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
     case glslang::EOpRefract:
         libCall = GLSL_STD_450::Refract;
         break;
+
     default:
         return 0;
     }
@@ -2319,7 +2417,7 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
             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
index 91cb2d0..d62d2bc 100644 (file)
@@ -45,6 +45,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include <unordered_set>
+
 #include "SpvBuilder.h"
 
 #ifndef _WIN32
@@ -989,12 +991,11 @@ Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)
     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,15 +2173,20 @@ void Builder::dumpInstructions(std::vector<unsigned int>& out, const std::vector
     }
 }
 
-void MissingFunctionality(const char* fun)
+void TbdFunctionality(const char* tbd)
 {
-    printf("Missing functionality: %s\n", fun);
-    exit(1);
+    static std::unordered_set<const char*> issued;
+
+    if (issued.find(tbd) == issued.end()) {
+        printf("TBD functionality: %s\n", tbd);
+        issued.insert(tbd);
+    }
 }
 
-void ValidationError(const char* error)
+void MissingFunctionality(const char* fun)
 {
-    printf("Validation Error: %s\n", error);
+    printf("Missing functionality: %s\n", fun);
+    exit(1);
 }
 
 Builder::Loop::Loop(Builder& builder, bool testFirstArg)
index c220960..e8711e3 100644 (file)
@@ -238,7 +238,7 @@ public:
     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 @@ protected:
     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 (file)
index 0000000..12da7db
--- /dev/null
@@ -0,0 +1,142 @@
+spv.atomic.comp\r
+Warning, version 310 is not yet complete; most version-specific features are present, but some are missing.\r
+\r
+\r
+Linked compute stage:\r
+\r
+\r
+TBD functionality: Is atomic_uint an opaque handle in the uniform storage class, or an addresses in the atomic storage class?\r
+TBD functionality: Is atomic_uint an opaque handle in the uniform storage class, or an addresses in the atomic storage class?\r
+TBD functionality: Is atomic_uint an opaque handle in the uniform storage class, or an addresses in the atomic storage class?\r
+TBD functionality: Is atomic_uint an opaque handle in the uniform storage class, or an addresses in the atomic storage class?\r
+TBD functionality: Is atomic_uint an opaque handle in the uniform storage class, or an addresses in the atomic storage class?\r
+// Module Version 99\r
+// Generated by (magic number): 51a00bb\r
+// Id's are bound by 75\r
+\r
+                              Source ESSL 310\r
+               1:             ExtInstImport  "GLSL.std.450"\r
+                              MemoryModel Logical GLSL450\r
+                              EntryPoint GLCompute 4\r
+                              Name 4  "main"\r
+                              Name 11  "func(au1;"\r
+                              Name 10  "c"\r
+                              Name 13  "atoms("\r
+                              Name 20  "counter"\r
+                              Name 21  "param"\r
+                              Name 24  "val"\r
+                              Name 28  "countArr"\r
+                              Name 38  "origi"\r
+                              Name 40  "atomi"\r
+                              Name 44  "origu"\r
+                              Name 46  "atomu"\r
+                              Name 48  "value"\r
+                              Name 72  "arrX"\r
+                              Name 73  "arrY"\r
+                              Name 74  "arrZ"\r
+                              Decorate 20(counter) PrecisionHigh \r
+                              Decorate 20(counter) Binding 0\r
+                              Decorate 24(val) PrecisionHigh \r
+                              Decorate 28(countArr) PrecisionHigh \r
+                              Decorate 28(countArr) Binding 0\r
+                              Decorate 38(origi) PrecisionHigh \r
+                              Decorate 40(atomi) PrecisionHigh \r
+                              Decorate 44(origu) PrecisionHigh \r
+                              Decorate 46(atomu) PrecisionHigh \r
+                              Decorate 48(value) PrecisionHigh \r
+                              Decorate 72(arrX) PrecisionHigh \r
+                              Decorate 72(arrX) NoStaticUse \r
+                              Decorate 73(arrY) PrecisionHigh \r
+                              Decorate 73(arrY) NoStaticUse \r
+                              Decorate 74(arrZ) PrecisionHigh \r
+                              Decorate 74(arrZ) NoStaticUse \r
+               2:             TypeVoid\r
+               3:             TypeFunction 2 \r
+               7:             TypeInt 32 0\r
+               8:             TypePointer Function 7(int)\r
+               9:             TypeFunction 7(int) 8(ptr)\r
+              19:             TypePointer UniformConstant 7(int)\r
+     20(counter):     19(ptr) Variable UniformConstant \r
+              25:      7(int) Constant 4\r
+              26:             TypeArray 7(int) 25\r
+              27:             TypePointer UniformConstant 26\r
+    28(countArr):     27(ptr) Variable UniformConstant \r
+              29:             TypeInt 32 1\r
+              30:     29(int) Constant 2\r
+              37:             TypePointer Function 29(int)\r
+              39:             TypePointer WorkgroupLocal 29(int)\r
+       40(atomi):     39(ptr) Variable WorkgroupLocal \r
+              42:     29(int) Constant 3\r
+              45:             TypePointer WorkgroupLocal 7(int)\r
+       46(atomu):     45(ptr) Variable WorkgroupLocal \r
+       48(value):     19(ptr) Variable UniformConstant \r
+              52:      7(int) Constant 7\r
+              60:     29(int) Constant 7\r
+              66:      7(int) Constant 10\r
+              69:      7(int) Constant 1\r
+              70:             TypeArray 29(int) 69\r
+              71:             TypePointer PrivateGlobal 70\r
+        72(arrX):     71(ptr) Variable PrivateGlobal \r
+        73(arrY):     71(ptr) Variable PrivateGlobal \r
+        74(arrZ):     71(ptr) Variable PrivateGlobal \r
+         4(main):           2 Function None 3\r
+               5:             Label\r
+       21(param):      8(ptr) Variable Function \r
+         24(val):      8(ptr) Variable Function \r
+                              MemoryBarrier Device AtomicCounterMemory \r
+              22:      7(int) Load 20(counter) \r
+                              Store 21(param) 22 \r
+              23:      7(int) FunctionCall 11(func(au1;) 21(param)\r
+              31:     19(ptr) AccessChain 28(countArr) 30\r
+              32:      7(int) Load 31 \r
+              33:      7(int) AtomicLoad 32 Device None\r
+              34:      7(int) Load 31 \r
+                              Store 24(val) 34 \r
+              35:      7(int) Load 20(counter) \r
+              36:      7(int) AtomicIDecrement 35 Device None\r
+                              Branch 6\r
+               6:             Label\r
+                              Return\r
+                              FunctionEnd\r
+   11(func(au1;):      7(int) Function None 9\r
+           10(c):      8(ptr) FunctionParameter\r
+              12:             Label\r
+              15:      7(int) Load 10(c) \r
+              16:      7(int) AtomicIIncrement 15 Device None\r
+              17:      7(int) Load 10(c) \r
+                              ReturnValue 17\r
+                              FunctionEnd\r
+      13(atoms():           2 Function None 3\r
+              14:             Label\r
+       38(origi):     37(ptr) Variable Function \r
+       44(origu):      8(ptr) Variable Function \r
+              41:     29(int) Load 40(atomi) \r
+              43:     29(int) AtomicIAdd 41 Device None 42\r
+                              Store 38(origi) 43 \r
+              47:      7(int) Load 46(atomu) \r
+              49:      7(int) Load 48(value) \r
+              50:      7(int) AtomicAnd 47 Device None 49\r
+                              Store 44(origu) 50 \r
+              51:      7(int) Load 46(atomu) \r
+              53:      7(int) AtomicOr 51 Device None 52\r
+                              Store 44(origu) 53 \r
+              54:      7(int) Load 46(atomu) \r
+              55:      7(int) AtomicXor 54 Device None 52\r
+                              Store 44(origu) 55 \r
+              56:      7(int) Load 46(atomu) \r
+              57:      7(int) Load 48(value) \r
+              58:      7(int) AtomicIMin 56 Device None 57\r
+                              Store 44(origu) 58 \r
+              59:     29(int) Load 40(atomi) \r
+              61:     29(int) AtomicIMax 59 Device None 60\r
+                              Store 38(origi) 61 \r
+              62:     29(int) Load 40(atomi) \r
+              63:     29(int) Load 38(origi) \r
+              64:     29(int) AtomicExchange 62 Device None 63\r
+                              Store 38(origi) 64 \r
+              65:      7(int) Load 46(atomu) \r
+              67:      7(int) Load 48(value) \r
+              68:      7(int) AtomicCompareExchange 65 Device None 66 67\r
+                              Store 44(origu) 68 \r
+                              Return\r
+                              FunctionEnd\r
diff --git a/Test/spv.atomic.comp b/Test/spv.atomic.comp
new file mode 100644 (file)
index 0000000..1a91b3e
--- /dev/null
@@ -0,0 +1,38 @@
+#version 310 es\r
+\r
+layout(binding = 0) uniform atomic_uint counter;\r
+\r
+layout(binding = 0, offset = 4) uniform atomic_uint countArr[4];\r
+uniform uint value;\r
+\r
+int arrX[gl_WorkGroupSize.x];\r
+int arrY[gl_WorkGroupSize.y];\r
+int arrZ[gl_WorkGroupSize.z];\r
+\r
+uint func(atomic_uint c)\r
+{\r
+    return atomicCounterIncrement(c);\r
+}\r
+\r
+void main()\r
+{\r
+    memoryBarrierAtomicCounter();\r
+    func(counter);\r
+    uint val = atomicCounter(countArr[2]);\r
+    atomicCounterDecrement(counter);\r
+}\r
+\r
+shared int atomi;\r
+shared uint atomu;\r
+\r
+void atoms()\r
+{\r
+    int origi = atomicAdd(atomi, 3);\r
+    uint origu = atomicAnd(atomu, value);\r
+    origu = atomicOr(atomu, 7u);\r
+    origu = atomicXor(atomu, 7u);\r
+    origu = atomicMin(atomu, value);\r
+    origi = atomicMax(atomi, 7);\r
+    origi = atomicExchange(atomi, origi);\r
+    origu = atomicCompSwap(atomu, 10u, value);\r
+}\r
index fed5688..ccfa068 100644 (file)
@@ -78,3 +78,4 @@ spv.varyingArray.frag
 spv.varyingArrayIndirect.frag
 spv.voidFunction.frag
 spv.whileLoop.frag
+spv.atomic.comp