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