Merge pull request #190 from dneto0/check-enumerant-ordering

Header generator: Check enumerant ordering
diff --git a/include/spirv/unified1/spirv.core.grammar.json b/include/spirv/unified1/spirv.core.grammar.json
index f3f585c..49f1bbc 100644
--- a/include/spirv/unified1/spirv.core.grammar.json
+++ b/include/spirv/unified1/spirv.core.grammar.json
@@ -10437,30 +10437,6 @@
           "version" : "1.3"
         },
         {
-          "enumerant" : "SubgroupGeMask",
-          "value" : 4417,
-          "capabilities" : [ "SubgroupBallotKHR", "GroupNonUniformBallot" ],
-          "version" : "1.3"
-        },
-        {
-          "enumerant" : "SubgroupGtMask",
-          "value" : 4418,
-          "capabilities" : [ "SubgroupBallotKHR", "GroupNonUniformBallot" ],
-          "version" : "1.3"
-        },
-        {
-          "enumerant" : "SubgroupLeMask",
-          "value" : 4419,
-          "capabilities" : [ "SubgroupBallotKHR", "GroupNonUniformBallot" ],
-          "version" : "1.3"
-        },
-        {
-          "enumerant" : "SubgroupLtMask",
-          "value" : 4420,
-          "capabilities" : [ "SubgroupBallotKHR", "GroupNonUniformBallot" ],
-          "version" : "1.3"
-        },
-        {
           "enumerant" : "SubgroupEqMaskKHR",
           "value" : 4416,
           "capabilities" : [ "SubgroupBallotKHR", "GroupNonUniformBallot" ],
@@ -10468,6 +10444,12 @@
           "version" : "1.3"
         },
         {
+          "enumerant" : "SubgroupGeMask",
+          "value" : 4417,
+          "capabilities" : [ "SubgroupBallotKHR", "GroupNonUniformBallot" ],
+          "version" : "1.3"
+        },
+        {
           "enumerant" : "SubgroupGeMaskKHR",
           "value" : 4417,
           "capabilities" : [ "SubgroupBallotKHR", "GroupNonUniformBallot" ],
@@ -10475,6 +10457,12 @@
           "version" : "1.3"
         },
         {
+          "enumerant" : "SubgroupGtMask",
+          "value" : 4418,
+          "capabilities" : [ "SubgroupBallotKHR", "GroupNonUniformBallot" ],
+          "version" : "1.3"
+        },
+        {
           "enumerant" : "SubgroupGtMaskKHR",
           "value" : 4418,
           "capabilities" : [ "SubgroupBallotKHR", "GroupNonUniformBallot" ],
@@ -10482,6 +10470,12 @@
           "version" : "1.3"
         },
         {
+          "enumerant" : "SubgroupLeMask",
+          "value" : 4419,
+          "capabilities" : [ "SubgroupBallotKHR", "GroupNonUniformBallot" ],
+          "version" : "1.3"
+        },
+        {
           "enumerant" : "SubgroupLeMaskKHR",
           "value" : 4419,
           "capabilities" : [ "SubgroupBallotKHR", "GroupNonUniformBallot" ],
@@ -10489,6 +10483,12 @@
           "version" : "1.3"
         },
         {
+          "enumerant" : "SubgroupLtMask",
+          "value" : 4420,
+          "capabilities" : [ "SubgroupBallotKHR", "GroupNonUniformBallot" ],
+          "version" : "1.3"
+        },
+        {
           "enumerant" : "SubgroupLtMaskKHR",
           "value" : 4420,
           "capabilities" : [ "SubgroupBallotKHR", "GroupNonUniformBallot" ],
diff --git a/tools/buildHeaders/jsonToSpirv.cpp b/tools/buildHeaders/jsonToSpirv.cpp
index e5b1e3e..17d2ea4 100644
--- a/tools/buildHeaders/jsonToSpirv.cpp
+++ b/tools/buildHeaders/jsonToSpirv.cpp
@@ -25,6 +25,7 @@
 #include <assert.h>
 #include <string.h>
 #include <algorithm>
+#include <cstdlib>
 #include <iostream>
 #include <unordered_map>
 #include <unordered_set>
@@ -326,6 +327,8 @@
 
     // process the instructions
     const Json::Value insts = root["instructions"];
+    unsigned maxOpcode = 0;
+    bool firstOpcode = true;
     for (const auto& inst : insts) {
         const auto printingClass = inst["class"].asString();
         if (printingClass.size() == 0) {
@@ -341,6 +344,19 @@
         }
         const auto opcode = inst["opcode"].asUInt();
         const std::string name = inst["opname"].asString();
+        if (firstOpcode) {
+          maxOpcode = opcode;
+          firstOpcode = false;
+        } else {
+          if (maxOpcode > opcode) {
+            std::cerr << "Error: " << name
+                      << " is out of order. It follows the instruction with opcode " << maxOpcode
+                      << std::endl;
+            std::exit(1);
+          } else {
+            maxOpcode = opcode;
+          }
+        }
         EnumCaps caps = getCaps(inst);
         std::string version = inst["version"].asString();
         std::string lastVersion = inst["lastVersion"].asString();
@@ -384,12 +400,27 @@
             return result;
         };
 
+        unsigned maxValue = 0;
+        bool firstValue = true;
         for (const auto& enumerant : source["enumerants"]) {
             unsigned value;
             bool skip_zero_in_bitfield;
             std::tie(value, skip_zero_in_bitfield) = getValue(enumerant);
             if (skip_zero_in_bitfield)
                 continue;
+            if (firstValue) {
+              maxValue = value;
+              firstValue = false;
+            } else {
+              if (maxValue > value) {
+                std::cerr << "Error: " << source["kind"] << " enumerant " << enumerant["enumerant"]
+                          << " is out of order. It has value " <<  value
+                          << " but follows the enumerant with value " << maxValue << std::endl;
+                std::exit(1);
+              } else {
+                maxValue = value;
+              }
+            }
             EnumCaps caps(getCaps(enumerant));
             std::string version = enumerant["version"].asString();
             std::string lastVersion = enumerant["lastVersion"].asString();