GLSL 4.6: Implement atomic counter ops and SPV_KHR_shader_atomic_counter_ops.
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index 36b2707..1661d5b 100755
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -1745,6 +1745,20 @@
         atomic = true;
         break;
 
+    case glslang::EOpAtomicCounterAdd:
+    case glslang::EOpAtomicCounterSubtract:
+    case glslang::EOpAtomicCounterMin:
+    case glslang::EOpAtomicCounterMax:
+    case glslang::EOpAtomicCounterAnd:
+    case glslang::EOpAtomicCounterOr:
+    case glslang::EOpAtomicCounterXor:
+    case glslang::EOpAtomicCounterExchange:
+    case glslang::EOpAtomicCounterCompSwap:
+        builder.addExtension("SPV_KHR_shader_atomic_counter_ops");
+        builder.addCapability(spv::CapabilityAtomicStorageOps);
+        atomic = true;
+        break;
+
     default:
         break;
     }
@@ -1815,6 +1829,15 @@
         case glslang::EOpAtomicXor:
         case glslang::EOpAtomicExchange:
         case glslang::EOpAtomicCompSwap:
+        case glslang::EOpAtomicCounterAdd:
+        case glslang::EOpAtomicCounterSubtract:
+        case glslang::EOpAtomicCounterMin:
+        case glslang::EOpAtomicCounterMax:
+        case glslang::EOpAtomicCounterAnd:
+        case glslang::EOpAtomicCounterOr:
+        case glslang::EOpAtomicCounterXor:
+        case glslang::EOpAtomicCounterExchange:
+        case glslang::EOpAtomicCounterCompSwap:
             if (arg == 0)
                 lvalue = true;
             break;
@@ -4619,34 +4642,45 @@
     switch (op) {
     case glslang::EOpAtomicAdd:
     case glslang::EOpImageAtomicAdd:
+    case glslang::EOpAtomicCounterAdd:
         opCode = spv::OpAtomicIAdd;
         break;
+    case glslang::EOpAtomicCounterSubtract:
+        opCode = spv::OpAtomicISub;
+        break;
     case glslang::EOpAtomicMin:
     case glslang::EOpImageAtomicMin:
+    case glslang::EOpAtomicCounterMin:
         opCode = typeProxy == glslang::EbtUint ? spv::OpAtomicUMin : spv::OpAtomicSMin;
         break;
     case glslang::EOpAtomicMax:
     case glslang::EOpImageAtomicMax:
+    case glslang::EOpAtomicCounterMax:
         opCode = typeProxy == glslang::EbtUint ? spv::OpAtomicUMax : spv::OpAtomicSMax;
         break;
     case glslang::EOpAtomicAnd:
     case glslang::EOpImageAtomicAnd:
+    case glslang::EOpAtomicCounterAnd:
         opCode = spv::OpAtomicAnd;
         break;
     case glslang::EOpAtomicOr:
     case glslang::EOpImageAtomicOr:
+    case glslang::EOpAtomicCounterOr:
         opCode = spv::OpAtomicOr;
         break;
     case glslang::EOpAtomicXor:
     case glslang::EOpImageAtomicXor:
+    case glslang::EOpAtomicCounterXor:
         opCode = spv::OpAtomicXor;
         break;
     case glslang::EOpAtomicExchange:
     case glslang::EOpImageAtomicExchange:
+    case glslang::EOpAtomicCounterExchange:
         opCode = spv::OpAtomicExchange;
         break;
     case glslang::EOpAtomicCompSwap:
     case glslang::EOpImageAtomicCompSwap:
+    case glslang::EOpAtomicCounterCompSwap:
         opCode = spv::OpAtomicCompareExchange;
         break;
     case glslang::EOpAtomicCounterIncrement:
diff --git a/SPIRV/doc.cpp b/SPIRV/doc.cpp
index fb0cc36..b47fa48 100755
--- a/SPIRV/doc.cpp
+++ b/SPIRV/doc.cpp
@@ -846,6 +846,8 @@
     case 5009: return "ImageGatherBiasLodAMD";
 #endif
 
+    case 4445: return "AtomicStorageOps";
+
     case 4447: return "SampleMaskPostDepthCoverage";
 #ifdef NV_EXTENSIONS
     case 5251: return "GeometryShaderPassthroughNV";
diff --git a/Test/450.vert b/Test/450.vert
index 4a376a3..17d1abb 100644
--- a/Test/450.vert
+++ b/Test/450.vert
@@ -22,8 +22,20 @@
 struct SS { float f; S s; };

 out SS outSS;

 

+layout(binding = 0) uniform atomic_uint aui;

+uint ui;

+

 void foo()

 {

     SS::f;

+    atomicCounterAdd(aui, ui);           // ERROR, need 4.6

+    atomicCounterSubtract(aui, ui);      // ERROR, need 4.6

+    atomicCounterMin(aui, ui);           // ERROR, need 4.6

+    atomicCounterMax(aui, ui);           // ERROR, need 4.6

+    atomicCounterAnd(aui, ui);           // ERROR, need 4.6

+    atomicCounterOr(aui, ui);            // ERROR, need 4.6

+    atomicCounterXor(aui, ui);           // ERROR, need 4.6

+    atomicCounterExchange(aui, ui);      // ERROR, need 4.6

+    atomicCounterCompSwap(aui, ui, ui);  // ERROR, need 4.6

 }

 ; // ERROR: no extraneous semicolons

diff --git a/Test/baseResults/450.vert.out b/Test/baseResults/450.vert.out
index cd150e3..1005642 100644
--- a/Test/baseResults/450.vert.out
+++ b/Test/baseResults/450.vert.out
@@ -1,9 +1,18 @@
 450.vert
 ERROR: 0:12: 'out' : cannot be bool 
 ERROR: 0:13: 'sampler2D' : sampler/image types can only be used in uniform variables or function parameters: outo
-ERROR: 0:27: '::' : not supported 
-ERROR: 0:29: 'extraneous semicolon' : not supported for this version or the enabled extensions 
-ERROR: 4 compilation errors.  No code generated.
+ERROR: 0:30: '::' : not supported 
+ERROR: 0:31: 'atomicCounterAdd' : no matching overloaded function found 
+ERROR: 0:32: 'atomicCounterSubtract' : no matching overloaded function found 
+ERROR: 0:33: 'atomicCounterMin' : no matching overloaded function found 
+ERROR: 0:34: 'atomicCounterMax' : no matching overloaded function found 
+ERROR: 0:35: 'atomicCounterAnd' : no matching overloaded function found 
+ERROR: 0:36: 'atomicCounterOr' : no matching overloaded function found 
+ERROR: 0:37: 'atomicCounterXor' : no matching overloaded function found 
+ERROR: 0:38: 'atomicCounterExchange' : no matching overloaded function found 
+ERROR: 0:39: 'atomicCounterCompSwap' : no matching overloaded function found 
+ERROR: 0:41: 'extraneous semicolon' : not supported for this version or the enabled extensions 
+ERROR: 13 compilation errors.  No code generated.
 
 
 Shader version: 450
@@ -21,8 +30,27 @@
 0:9            2 (const int)
 0:9        Constant:
 0:9          4.500000
-0:25  Function Definition: foo( ( global void)
-0:25    Function Parameters: 
+0:28  Function Definition: foo( ( global void)
+0:28    Function Parameters: 
+0:?     Sequence
+0:31      Constant:
+0:31        0.000000
+0:32      Constant:
+0:32        0.000000
+0:33      Constant:
+0:33        0.000000
+0:34      Constant:
+0:34        0.000000
+0:35      Constant:
+0:35        0.000000
+0:36      Constant:
+0:36        0.000000
+0:37      Constant:
+0:37        0.000000
+0:38      Constant:
+0:38        0.000000
+0:39      Constant:
+0:39        0.000000
 0:?   Linker Objects
 0:?     'anon@0' ( out block{ out 3-element array of float CullDistance gl_CullDistance})
 0:?     'outb' ( smooth out bool)
@@ -34,6 +62,8 @@
 0:?     'outsa' ( smooth out 4-element array of structure{ global float f})
 0:?     'outSA' ( smooth out structure{ global 4-element array of float f})
 0:?     'outSS' ( smooth out structure{ global float f,  global structure{ global float f} s})
+0:?     'aui' (layout( binding=0 offset=0) uniform atomic_uint)
+0:?     'ui' ( global uint)
 0:?     'gl_VertexID' ( gl_VertexId int VertexId)
 0:?     'gl_InstanceID' ( gl_InstanceId int InstanceId)
 
@@ -67,6 +97,8 @@
 0:?     'outsa' ( smooth out 4-element array of structure{ global float f})
 0:?     'outSA' ( smooth out structure{ global 4-element array of float f})
 0:?     'outSS' ( smooth out structure{ global float f,  global structure{ global float f} s})
+0:?     'aui' (layout( binding=0 offset=0) uniform atomic_uint)
+0:?     'ui' ( global uint)
 0:?     'gl_VertexID' ( gl_VertexId int VertexId)
 0:?     'gl_InstanceID' ( gl_InstanceId int InstanceId)
 
diff --git a/Test/baseResults/spv.460.frag.out b/Test/baseResults/spv.460.frag.out
new file mode 100755
index 0000000..4e827a0
--- /dev/null
+++ b/Test/baseResults/spv.460.frag.out
@@ -0,0 +1,51 @@
+spv.460.frag
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 32
+
+                              Capability Shader
+                              Capability AtomicStorage
+                              Capability AtomicStorageOps
+                              Extension  "SPV_KHR_shader_atomic_counter_ops"
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Fragment 4  "main"
+                              ExecutionMode 4 OriginLowerLeft
+                              Source GLSL 460
+                              Name 4  "main"
+                              Name 8  "aui"
+                              Name 10  "ui"
+                              Decorate 8(aui) Offset 0
+                              Decorate 8(aui) Binding 0
+               2:             TypeVoid
+               3:             TypeFunction 2
+               6:             TypeInt 32 0
+               7:             TypePointer AtomicCounter 6(int)
+          8(aui):      7(ptr) Variable AtomicCounter
+               9:             TypePointer Private 6(int)
+          10(ui):      9(ptr) Variable Private
+              12:      6(int) Constant 1
+              13:      6(int) Constant 0
+         4(main):           2 Function None 3
+               5:             Label
+              11:      6(int) Load 10(ui)
+              14:      6(int) AtomicIAdd 8(aui) 12 13 11
+              15:      6(int) Load 10(ui)
+              16:      6(int) AtomicISub 8(aui) 12 13 15
+              17:      6(int) Load 10(ui)
+              18:      6(int) AtomicUMin 8(aui) 12 13 17
+              19:      6(int) Load 10(ui)
+              20:      6(int) AtomicUMax 8(aui) 12 13 19
+              21:      6(int) Load 10(ui)
+              22:      6(int) AtomicAnd 8(aui) 12 13 21
+              23:      6(int) Load 10(ui)
+              24:      6(int) AtomicOr 8(aui) 12 13 23
+              25:      6(int) Load 10(ui)
+              26:      6(int) AtomicXor 8(aui) 12 13 25
+              27:      6(int) Load 10(ui)
+              28:      6(int) AtomicExchange 8(aui) 12 13 27
+              29:      6(int) Load 10(ui)
+              30:      6(int) Load 10(ui)
+              31:      6(int) AtomicCompareExchange 8(aui) 12 13 13 30 29
+                              Return
+                              FunctionEnd
diff --git a/Test/spv.460.frag b/Test/spv.460.frag
new file mode 100644
index 0000000..9eb8bf4
--- /dev/null
+++ b/Test/spv.460.frag
@@ -0,0 +1,17 @@
+#version 460 core

+

+layout(binding = 0) uniform atomic_uint aui;

+uint ui;

+

+void main()

+{

+    atomicCounterAdd(aui, ui);

+    atomicCounterSubtract(aui, ui);

+    atomicCounterMin(aui, ui);

+    atomicCounterMax(aui, ui);

+    atomicCounterAnd(aui, ui);

+    atomicCounterOr(aui, ui);

+    atomicCounterXor(aui, ui);

+    atomicCounterExchange(aui, ui);

+    atomicCounterCompSwap(aui, ui, ui);

+}

diff --git a/glslang/Include/intermediate.h b/glslang/Include/intermediate.h
index 0922d12..e289efd 100644
--- a/glslang/Include/intermediate.h
+++ b/glslang/Include/intermediate.h
@@ -420,6 +420,15 @@
     EOpAtomicCounterIncrement,
     EOpAtomicCounterDecrement,
     EOpAtomicCounter,
+    EOpAtomicCounterAdd,
+    EOpAtomicCounterSubtract,
+    EOpAtomicCounterMin,
+    EOpAtomicCounterMax,
+    EOpAtomicCounterAnd,
+    EOpAtomicCounterOr,
+    EOpAtomicCounterXor,
+    EOpAtomicCounterExchange,
+    EOpAtomicCounterCompSwap,
 
     EOpAny,
     EOpAll,
diff --git a/glslang/MachineIndependent/Initialize.cpp b/glslang/MachineIndependent/Initialize.cpp
index 5cd167e..921d83a 100644
--- a/glslang/MachineIndependent/Initialize.cpp
+++ b/glslang/MachineIndependent/Initialize.cpp
@@ -1375,9 +1375,23 @@
         if ((profile != EEsProfile && version >= 300) ||
             (profile == EEsProfile && version >= 310)) {
             commonBuiltins.append(
-                "uint atomicCounterIncrement(atomic_uint x);"
-                "uint atomicCounterDecrement(atomic_uint x);"
-                "uint atomicCounter(atomic_uint x);"
+                "uint atomicCounterIncrement(atomic_uint);"
+                "uint atomicCounterDecrement(atomic_uint);"
+                "uint atomicCounter(atomic_uint);"
+
+                "\n");
+        }
+        if (profile != EEsProfile && version >= 460) {
+            commonBuiltins.append(
+                "uint atomicCounterAdd(atomic_uint, uint);"
+                "uint atomicCounterSubtract(atomic_uint, uint);"
+                "uint atomicCounterMin(atomic_uint, uint);"
+                "uint atomicCounterMax(atomic_uint, uint);"
+                "uint atomicCounterAnd(atomic_uint, uint);"
+                "uint atomicCounterOr(atomic_uint, uint);"
+                "uint atomicCounterXor(atomic_uint, uint);"
+                "uint atomicCounterExchange(atomic_uint, uint);"
+                "uint atomicCounterCompSwap(atomic_uint, uint, uint);"
 
                 "\n");
         }
@@ -5909,6 +5923,18 @@
     symbolTable.relateToOperator("atomicCounterDecrement", EOpAtomicCounterDecrement);
     symbolTable.relateToOperator("atomicCounter",          EOpAtomicCounter);
 
+    if (profile != EEsProfile && version >= 460) {
+        symbolTable.relateToOperator("atomicCounterAdd",      EOpAtomicCounterAdd);
+        symbolTable.relateToOperator("atomicCounterSubtract", EOpAtomicCounterSubtract);
+        symbolTable.relateToOperator("atomicCounterMin",      EOpAtomicCounterMin);
+        symbolTable.relateToOperator("atomicCounterMax",      EOpAtomicCounterMax);
+        symbolTable.relateToOperator("atomicCounterAnd",      EOpAtomicCounterAnd);
+        symbolTable.relateToOperator("atomicCounterOr",       EOpAtomicCounterOr);
+        symbolTable.relateToOperator("atomicCounterXor",      EOpAtomicCounterXor);
+        symbolTable.relateToOperator("atomicCounterExchange", EOpAtomicCounterExchange);
+        symbolTable.relateToOperator("atomicCounterCompSwap", EOpAtomicCounterCompSwap);
+    }
+
     symbolTable.relateToOperator("fma",               EOpFma);
     symbolTable.relateToOperator("frexp",             EOpFrexp);
     symbolTable.relateToOperator("ldexp",             EOpLdexp);
diff --git a/glslang/MachineIndependent/intermOut.cpp b/glslang/MachineIndependent/intermOut.cpp
index ba7e0f5..479f15d 100644
--- a/glslang/MachineIndependent/intermOut.cpp
+++ b/glslang/MachineIndependent/intermOut.cpp
@@ -682,6 +682,16 @@
     case EOpAtomicExchange:             out.debug << "AtomicExchange";        break;
     case EOpAtomicCompSwap:             out.debug << "AtomicCompSwap";        break;
 
+    case EOpAtomicCounterAdd:           out.debug << "AtomicCounterAdd";      break;
+    case EOpAtomicCounterSubtract:      out.debug << "AtomicCounterSubtract"; break;
+    case EOpAtomicCounterMin:           out.debug << "AtomicCounterMin";      break;
+    case EOpAtomicCounterMax:           out.debug << "AtomicCounterMax";      break;
+    case EOpAtomicCounterAnd:           out.debug << "AtomicCounterAnd";      break;
+    case EOpAtomicCounterOr:            out.debug << "AtomicCounterOr";       break;
+    case EOpAtomicCounterXor:           out.debug << "AtomicCounterXor";      break;
+    case EOpAtomicCounterExchange:      out.debug << "AtomicCounterExchange"; break;
+    case EOpAtomicCounterCompSwap:      out.debug << "AtomicCounterCompSwap"; break;
+
     case EOpImageQuerySize:             out.debug << "imageQuerySize";        break;
     case EOpImageQuerySamples:          out.debug << "imageQuerySamples";     break;
     case EOpImageLoad:                  out.debug << "imageLoad";             break;
diff --git a/gtests/Spv.FromFile.cpp b/gtests/Spv.FromFile.cpp
index dfad30c..3a236b7 100644
--- a/gtests/Spv.FromFile.cpp
+++ b/gtests/Spv.FromFile.cpp
@@ -360,6 +360,7 @@
 INSTANTIATE_TEST_CASE_P(
     Glsl, CompileOpenGLToSpirvTest,
     ::testing::ValuesIn(std::vector<std::string>({
+        "spv.460.frag",
         "spv.atomic.comp",
         "spv.glFragColor.frag",
         "spv.specConst.vert",