SPV reflection: Add OpModuleProcessed for compile options.
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index a167702..bda9922 100755
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -880,11 +880,30 @@
     spv::ExecutionModel executionModel = TranslateExecutionModel(glslangIntermediate->getStage());
 
     builder.clearAccessChain();
-    builder.setSource(TranslateSourceLanguage(glslangIntermediate->getSource(), glslangIntermediate->getProfile()), glslangIntermediate->getVersion());
+    builder.setSource(TranslateSourceLanguage(glslangIntermediate->getSource(), glslangIntermediate->getProfile()),
+                      glslangIntermediate->getVersion());
+
     if (options.generateDebugInfo) {
-        builder.setSourceFile(glslangIntermediate->getSourceFile());
-        builder.setSourceText(glslangIntermediate->getSourceText());
         builder.setEmitOpLines();
+        builder.setSourceFile(glslangIntermediate->getSourceFile());
+
+        // Set the source shader's text. If for SPV version 1.0, include
+        // a preamble in comments stating the OpModuleProcessed instructions.
+        // Otherwise, emit those as actual instructions.
+        std::string text;
+        const std::vector<std::string>& processes = glslangIntermediate->getProcesses();
+        for (int p = 0; p < (int)processes.size(); ++p) {
+            if (glslangIntermediate->getSpv().spv < 0x00010100) {
+                text.append("// OpModuleProcessed ");
+                text.append(processes[p]);
+                text.append("\n");
+            } else
+                builder.addModuleProcessed(processes[p]);
+        }
+        if (glslangIntermediate->getSpv().spv < 0x00010100 && (int)processes.size() > 0)
+            text.append("#line 1\n");
+        text.append(glslangIntermediate->getSourceText());
+        builder.setSourceText(text);
     }
     stdBuiltins = builder.import("GLSL.std.450");
     builder.setMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);
diff --git a/SPIRV/SpvBuilder.cpp b/SPIRV/SpvBuilder.cpp
index 9246a81..289d59a 100644
--- a/SPIRV/SpvBuilder.cpp
+++ b/SPIRV/SpvBuilder.cpp
@@ -2430,6 +2430,7 @@
 
     // Debug instructions
     dumpInstructions(out, strings);
+    dumpModuleProcesses(out);
     dumpSourceInstructions(out);
     for (int e = 0; e < (int)sourceExtensions.size(); ++e) {
         Instruction sourceExtInst(0, 0, OpSourceExtension);
@@ -2637,4 +2638,15 @@
     }
 }
 
+void Builder::dumpModuleProcesses(std::vector<unsigned int>& out) const
+{
+    for (int i = 0; i < (int)moduleProcesses.size(); ++i) {
+        // TODO: switch this out for the 1.1 headers
+        const spv::Op OpModuleProcessed = (spv::Op)330;
+        Instruction moduleProcessed(OpModuleProcessed);
+        moduleProcessed.addStringOperand(moduleProcesses[i]);
+        moduleProcessed.dump(out);
+    }
+}
+
 }; // end spv namespace
diff --git a/SPIRV/SpvBuilder.h b/SPIRV/SpvBuilder.h
index 3a94919..59b1da2 100755
--- a/SPIRV/SpvBuilder.h
+++ b/SPIRV/SpvBuilder.h
@@ -79,6 +79,7 @@
     }
     void setSourceText(const std::string& text) { sourceText = text; }
     void addSourceExtension(const char* ext) { sourceExtensions.push_back(ext); }
+    void addModuleProcessed(const std::string& p) { moduleProcesses.push_back(p.c_str()); }
     void setEmitOpLines() { emitOpLines = true; }
     void addExtension(const char* ext) { extensions.insert(ext); }
     Id import(const char*);
@@ -582,6 +583,7 @@
     void createSelectionMerge(Block* mergeBlock, unsigned int control);
     void dumpSourceInstructions(std::vector<unsigned int>&) const;
     void dumpInstructions(std::vector<unsigned int>&, const std::vector<std::unique_ptr<Instruction> >&) const;
+    void dumpModuleProcesses(std::vector<unsigned int>&) const;
 
     SourceLanguage source;
     int sourceVersion;
@@ -591,6 +593,7 @@
     bool emitOpLines;
     std::set<std::string> extensions;
     std::vector<const char*> sourceExtensions;
+    std::vector<const char*> moduleProcesses;
     AddressingModel addressModel;
     MemoryModel memoryModel;
     std::set<spv::Capability> capabilities;
diff --git a/StandAlone/StandAlone.cpp b/StandAlone/StandAlone.cpp
index 3301df4..53a33b8 100644
--- a/StandAlone/StandAlone.cpp
+++ b/StandAlone/StandAlone.cpp
@@ -152,6 +152,7 @@
 int VulkanClientVersion = 100;           // would map to, say, Vulkan 1.0
 int OpenGLClientVersion = 450;           // doesn't influence anything yet, but maps to OpenGL 4.50
 unsigned int TargetVersion = 0x00001000; // maps to, say, SPIR-V 1.0
+std::vector<std::string> Processes;      // what should be recorded by OpModuleProcessed, or equivalent
 
 std::array<unsigned int, EShLangCount> baseSamplerBinding;
 std::array<unsigned int, EShLangCount> baseTextureBinding;
@@ -175,6 +176,9 @@
         text.append("#define ");
         fixLine(def);
 
+        Processes.push_back("D");
+        Processes.back().append(def);
+
         // The first "=" needs to turn into a space
         const size_t equal = def.find_first_of("=");
         if (equal != def.npos)
@@ -189,6 +193,10 @@
     {
         text.append("#undef ");
         fixLine(undef);
+
+        Processes.push_back("U");
+        Processes.back().append(undef);
+
         text.append(undef);
         text.append("\n");
     }
@@ -421,6 +429,8 @@
                     } else if (lowerword == "no-storage-format" || // synonyms
                                lowerword == "nsf") {
                         Options |= EOptionNoStorageFormat;
+                    } else if (lowerword == "relaxed-errors") {
+                        Options |= EOptionRelaxedErrors;
                     } else if (lowerword == "resource-set-bindings" ||  // synonyms
                                lowerword == "resource-set-binding"  ||
                                lowerword == "rsb") {
@@ -459,6 +469,8 @@
                         sourceEntryPointName = argv[1];
                         bumpArg();
                         break;
+                    } else if (lowerword == "suppress-warnings") {
+                        Options |= EOptionSuppressWarnings;
                     } else if (lowerword == "target-env") {
                         if (argc > 1) {
                             if (strcmp(argv[1], "vulkan1.0") == 0) {
@@ -737,6 +749,7 @@
             shader->setSourceEntryPoint(sourceEntryPointName);
         if (UserPreamble.isSet())
             shader->setPreamble(UserPreamble.get());
+        shader->addProcesses(Processes);
 
         shader->setShiftSamplerBinding(baseSamplerBinding[compUnit.stage]);
         shader->setShiftTextureBinding(baseTextureBinding[compUnit.stage]);
@@ -1162,11 +1175,11 @@
            "  -m          memory leak mode\n"
            "  -o  <file>  save binary to <file>, requires a binary option (e.g., -V)\n"
            "  -q          dump reflection query database\n"
-           "  -r          relaxed semantic error-checking mode\n"
+           "  -r          synonym for --relaxed-errors\n"
            "  -s          silent mode\n"
            "  -t          multi-threaded mode\n"
            "  -v          print version strings\n"
-           "  -w          suppress warnings (except as required by #extension : warn)\n"
+           "  -w          synonym for --suppress-warnings\n"
            "  -x          save binary output as text-based 32-bit hexadecimal numbers\n"
            "  --auto-map-bindings                  automatically bind uniform variables\n"
            "                                       without explicit bindings.\n"
@@ -1185,6 +1198,7 @@
            "  --ku                                 synonym for --keep-uncalled\n"
            "  --no-storage-format                  use Unknown image format\n"
            "  --nsf                                synonym for --no-storage-format\n"
+           "  --relaxed-errors                     relaxed GLSL semantic error-checking mode\n"
            "  --resource-set-binding [stage] name set binding\n"
            "              Set descriptor set and binding for individual resources\n"
            "  --resource-set-binding [stage] set\n"
@@ -1206,11 +1220,13 @@
            "  --source-entrypoint name             the given shader source function is\n"
            "                                       renamed to be the entry point given in -e\n"
            "  --sep                                synonym for --source-entrypoint\n"
-           "  --target-env {vulkan1.0|opengl}      set the execution environment the generated\n"
-           "                                       code will execute in (as opposed to language\n"
-           "                                       semantics selected by --client)\n"
-           "                                       default is 'vulkan1.0' under '--client vulkan'\n"
-           "                                       default is 'opengl' under '--client opengl'\n"
+           "  --suppress-warnings                  suppress GLSL warnings\n"
+           "                                       (except as required by #extension : warn)\n"
+           "  --target-env {vulkan1.0|opengl}      set the execution environment code will\n"
+           "                                       execute in (as opposed to language\n"
+           "                                       semantics selected by --client) defaults:\n"
+           "                                        'vulkan1.0' under '--client vulkan<ver>'\n"
+           "                                        'opengl' under '--client opengl<ver>'\n"
            "  --variable-name <name>               Creates a C header file that contains a\n"
            "                                       uint32_t array named <name>\n"
            "                                       initialized with the shader binary code.\n"
diff --git a/Test/baseResults/spv.debugInfo.frag.out b/Test/baseResults/spv.debugInfo.frag.out
index f501528..2e0d1b3 100644
--- a/Test/baseResults/spv.debugInfo.frag.out
+++ b/Test/baseResults/spv.debugInfo.frag.out
@@ -7,9 +7,19 @@
                2:             ExtInstImport  "GLSL.std.450"
                               MemoryModel Logical GLSL450
                               EntryPoint Fragment 5  "main" 24 52
-                              ExecutionMode 5 OriginUpperLeft
+                              ExecutionMode 5 OriginLowerLeft
                1:             String  "spv.debugInfo.frag"
-                              Source GLSL 450 1  "#version 450
+                              Source GLSL 450 1  "// OpModuleProcessed no-storage-format
+// OpModuleProcessed resource-set-binding 3
+// OpModuleProcessed auto-map-locations
+// OpModuleProcessed client opengl100
+// OpModuleProcessed target-env opengl
+// OpModuleProcessed relaxed-errors
+// OpModuleProcessed suppress-warnings
+// OpModuleProcessed hlsl-offsets
+// OpModuleProcessed entry-point main
+#line 1
+#version 450
 
 struct S {
     int a;
@@ -84,8 +94,8 @@
                               MemberDecorate 53(S) 0 Offset 0
                               MemberDecorate 54(ubuf) 0 Offset 0
                               Decorate 54(ubuf) Block
-                              Decorate 56 DescriptorSet 0
-                              Decorate 69(s2d) DescriptorSet 0
+                              Decorate 56 DescriptorSet 3
+                              Decorate 69(s2d) DescriptorSet 3
                3:             TypeVoid
                4:             TypeFunction 3
                7:             TypeInt 32 1
diff --git a/Test/baseResults/spv.hlslDebugInfo.frag.out b/Test/baseResults/spv.hlslDebugInfo.frag.out
new file mode 100644
index 0000000..571e594
--- /dev/null
+++ b/Test/baseResults/spv.hlslDebugInfo.frag.out
@@ -0,0 +1,58 @@
+spv.hlslDebugInfo.vert
+// Module Version 10000
+// Generated by (magic number): 80001
+// Id's are bound by 19
+
+                              Capability Shader
+               2:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Vertex 5  "newMain" 17
+               1:             String  "spv.hlslDebugInfo.vert"
+                              Source HLSL 500 1  "// OpModuleProcessed entry-point newMain
+// OpModuleProcessed shift-sampler-binding 2
+// OpModuleProcessed shift-texture-binding 4
+// OpModuleProcessed shift-image-binding 1
+// OpModuleProcessed shift-UBO-binding 6
+// OpModuleProcessed shift-ssbo-binding 3
+// OpModuleProcessed shift-uav-binding 5
+// OpModuleProcessed flatten-uniform-arrays
+// OpModuleProcessed no-storage-format
+// OpModuleProcessed resource-set-binding t0 0 0
+// OpModuleProcessed hlsl-iomap
+// OpModuleProcessed auto-map-bindings
+// OpModuleProcessed auto-map-locations
+// OpModuleProcessed client vulkan100
+// OpModuleProcessed target-env vulkan1.0
+// OpModuleProcessed source-entrypoint origMain
+// OpModuleProcessed hlsl-offsets
+#line 1
+float4 origMain() : SV_Position
+{
+    return (float4)0;
+}
+"
+                              Name 5  "newMain"
+                              Name 10  "@newMain("
+                              Name 17  "@entryPointOutput"
+                              Decorate 17(@entryPointOutput) BuiltIn Position
+               3:             TypeVoid
+               4:             TypeFunction 3
+               7:             TypeFloat 32
+               8:             TypeVector 7(float) 4
+               9:             TypeFunction 8(fvec4)
+              12:    7(float) Constant 0
+              13:    8(fvec4) ConstantComposite 12 12 12 12
+              16:             TypePointer Output 8(fvec4)
+17(@entryPointOutput):     16(ptr) Variable Output
+      5(newMain):           3 Function None 4
+               6:             Label
+                              Line 1 2 0
+              18:    8(fvec4) FunctionCall 10(@newMain()
+                              Store 17(@entryPointOutput) 18
+                              Return
+                              FunctionEnd
+   10(@newMain():    8(fvec4) Function None 9
+              11:             Label
+                              Line 1 3 0
+                              ReturnValue 13
+                              FunctionEnd
diff --git a/Test/runtests b/Test/runtests
index c5a9337..98cd944 100755
--- a/Test/runtests
+++ b/Test/runtests
@@ -116,8 +116,12 @@
 # Testing debug information
 #
 echo Testing SPV Debug Information
-$EXE -g -H spv.debugInfo.frag > $TARGETDIR/spv.debugInfo.frag.out
+$EXE -g --relaxed-errors --suppress-warnings --aml --hlsl-offsets --nsf \
+     -G -H spv.debugInfo.frag --rsb frag 3 > $TARGETDIR/spv.debugInfo.frag.out
 diff -b $BASEDIR/spv.debugInfo.frag.out $TARGETDIR/spv.debugInfo.frag.out || HASERROR=1
+$EXE -g -D -e newMain -g --amb --aml --fua --hlsl-iomap --nsf --sib 1 --ssb 2 --sbb 3 --stb 4 --suavb 5 --sub 6 \
+     --sep origMain -H spv.hlslDebugInfo.vert --rsb vert t0 0 0 > $TARGETDIR/spv.hlslDebugInfo.frag.out
+diff -b $BASEDIR/spv.hlslDebugInfo.frag.out $TARGETDIR/spv.hlslDebugInfo.frag.out || HASERROR=1
 
 #
 # Testing Includer
diff --git a/Test/spv.hlslDebugInfo.vert b/Test/spv.hlslDebugInfo.vert
new file mode 100644
index 0000000..b2bc187
--- /dev/null
+++ b/Test/spv.hlslDebugInfo.vert
@@ -0,0 +1,4 @@
+float4 origMain() : SV_Position

+{

+    return (float4)0;

+}

diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp
index d2964e4..2a904f4 100644
--- a/glslang/MachineIndependent/ShaderLang.cpp
+++ b/glslang/MachineIndependent/ShaderLang.cpp
@@ -675,6 +675,22 @@
     }
 }
 
+// Most processes are recorded when set in the intermediate representation,
+// These are the few that are not.
+void RecordProcesses(TIntermediate& intermediate, EShMessages messages, const std::string& sourceEntryPointName)
+{
+    if ((messages & EShMsgRelaxedErrors) != 0)
+        intermediate.addProcess("relaxed-errors");
+    if ((messages & EShMsgSuppressWarnings) != 0)
+        intermediate.addProcess("suppress-warnings");
+    if ((messages & EShMsgKeepUncalled) != 0)
+        intermediate.addProcess("keep-uncalled");
+    if (sourceEntryPointName.size() > 0) {
+        intermediate.addProcess("source-entrypoint");
+        intermediate.addProcessArgument(sourceEntryPointName);
+    }
+}
+
 // This is the common setup and cleanup code for PreprocessDeferred and
 // CompileDeferred.
 // It takes any callable with a signature of
@@ -798,6 +814,7 @@
     intermediate.setVersion(version);
     intermediate.setProfile(profile);
     intermediate.setSpv(spvVersion);
+    RecordProcesses(intermediate, messages, sourceEntryPointName);
     if (spvVersion.vulkan >= 100)
         intermediate.setOriginUpperLeft();
     if ((messages & EShMsgHlslOffsets) || source == EShSourceHlsl)
@@ -1641,6 +1658,11 @@
     sourceEntryPointName = name;
 }
 
+void TShader::addProcesses(const std::vector<std::string>& p)
+{
+    intermediate->addProcesses(p);
+}
+
 // Set binding base for sampler types
 void TShader::setShiftSamplerBinding(unsigned int base) { intermediate->setShiftSamplerBinding(base); }
 // Set binding base for texture types (SRV)
@@ -1658,7 +1680,7 @@
 // Enables binding automapping using TIoMapper
 void TShader::setAutoMapBindings(bool map)              { intermediate->setAutoMapBindings(map); }
 // Fragile: currently within one stage: simple auto-assignment of location
-void TShader::setAutoMapLocations(bool map)              { intermediate->setAutoMapLocations(map); }
+void TShader::setAutoMapLocations(bool map)             { intermediate->setAutoMapLocations(map); }
 // See comment above TDefaultHlslIoMapper in iomapper.cpp:
 void TShader::setHlslIoMapping(bool hlslIoMap)          { intermediate->setHlslIoMapping(hlslIoMap); }
 void TShader::setFlattenUniformArrays(bool flatten)     { intermediate->setFlattenUniformArrays(flatten); }
diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h
index c1daf1b..d3219cc 100644
--- a/glslang/MachineIndependent/localintermediate.h
+++ b/glslang/MachineIndependent/localintermediate.h
@@ -150,6 +150,54 @@
     bool containsDouble;
 };
 
+// Track a set of strings describing how the module was processed.
+// Using the form:
+//   process arg0 arg1 arg2 ...
+//   process arg0 arg1 arg2 ...
+// where everything is textual, and there can be zero or more arguments
+class TProcesses {
+public:
+    TProcesses() {}
+    ~TProcesses() {}
+
+    void addProcess(const char* process)
+    {
+        processes.push_back(process);
+    }
+    void addProcess(const std::string& process)
+    {
+        processes.push_back(process);
+    }
+    void addArgument(int arg)
+    {
+        processes.back().append(" ");
+        std::string argString = std::to_string(arg);
+        processes.back().append(argString);
+    }
+    void addArgument(const char* arg)
+    {
+        processes.back().append(" ");
+        processes.back().append(arg);
+    }
+    void addArgument(const std::string& arg)
+    {
+        processes.back().append(" ");
+        processes.back().append(arg);
+    }
+    void addIfNonZero(const char* process, int value)
+    {
+        if (value != 0) {
+            addProcess(process);
+            addArgument(value);
+        }
+    }
+
+    const std::vector<std::string>& getProcesses() const { return processes; }
+
+private:
+    std::vector<std::string> processes;
+};
+
 class TSymbolTable;
 class TSymbol;
 class TVariable;
@@ -201,46 +249,135 @@
 
     void setSource(EShSource s) { source = s; }
     EShSource getSource() const { return source; }
-    void setEntryPointName(const char* ep) { entryPointName = ep; }
+    void setEntryPointName(const char* ep)
+    {
+        entryPointName = ep;
+        processes.addProcess("entry-point");
+        processes.addArgument(entryPointName);
+    }
     void setEntryPointMangledName(const char* ep) { entryPointMangledName = ep; }
     const std::string& getEntryPointName() const { return entryPointName; }
     const std::string& getEntryPointMangledName() const { return entryPointMangledName; }
 
-    void setShiftSamplerBinding(unsigned int shift) { shiftSamplerBinding = shift; }
+    void setShiftSamplerBinding(unsigned int shift)
+    {
+        shiftSamplerBinding = shift;
+        processes.addIfNonZero("shift-sampler-binding", shift);
+    }
     unsigned int getShiftSamplerBinding() const { return shiftSamplerBinding; }
-    void setShiftTextureBinding(unsigned int shift) { shiftTextureBinding = shift; }
+    void setShiftTextureBinding(unsigned int shift)
+    {
+        shiftTextureBinding = shift;
+        processes.addIfNonZero("shift-texture-binding", shift);
+    }
     unsigned int getShiftTextureBinding() const { return shiftTextureBinding; }
-    void setShiftImageBinding(unsigned int shift) { shiftImageBinding = shift; }
+    void setShiftImageBinding(unsigned int shift)
+    {
+        shiftImageBinding = shift;
+        processes.addIfNonZero("shift-image-binding", shift);
+    }
     unsigned int getShiftImageBinding() const { return shiftImageBinding; }
-    void setShiftUboBinding(unsigned int shift)     { shiftUboBinding = shift; }
-    unsigned int getShiftUboBinding()     const { return shiftUboBinding; }
-    void setShiftSsboBinding(unsigned int shift)     { shiftSsboBinding = shift; }
-    unsigned int getShiftSsboBinding()  const { return shiftSsboBinding; }
-    void setShiftUavBinding(unsigned int shift) { shiftUavBinding = shift; }
-    unsigned int getShiftUavBinding()  const { return shiftUavBinding; }
-    void setResourceSetBinding(const std::vector<std::string>& shift) { resourceSetBinding = shift; }
+    void setShiftUboBinding(unsigned int shift)
+    {
+        shiftUboBinding = shift;
+        processes.addIfNonZero("shift-UBO-binding", shift);
+    }
+    unsigned int getShiftUboBinding() const { return shiftUboBinding; }
+    void setShiftSsboBinding(unsigned int shift)
+    {
+        shiftSsboBinding = shift;
+        processes.addIfNonZero("shift-ssbo-binding", shift);
+    }
+    unsigned int getShiftSsboBinding() const { return shiftSsboBinding; }
+    void setShiftUavBinding(unsigned int shift)
+    {
+        shiftUavBinding = shift;
+        processes.addIfNonZero("shift-uav-binding", shift);
+    }
+    unsigned int getShiftUavBinding() const { return shiftUavBinding; }
+    void setResourceSetBinding(const std::vector<std::string>& shift)
+    {
+        resourceSetBinding = shift;
+        if (shift.size() > 0) {
+            processes.addProcess("resource-set-binding");
+            for (int s = 0; s < (int)shift.size(); ++s)
+                processes.addArgument(shift[s]);
+        }
+    }
     const std::vector<std::string>& getResourceSetBinding() const { return resourceSetBinding; }
-    void setAutoMapBindings(bool map)           { autoMapBindings = map; }
-    bool getAutoMapBindings()             const { return autoMapBindings; }
-    void setAutoMapLocations(bool map)          { autoMapLocations = map; }
-    bool getAutoMapLocations()            const { return autoMapLocations; }
-    void setFlattenUniformArrays(bool flatten)  { flattenUniformArrays = flatten; }
-    bool getFlattenUniformArrays()        const { return flattenUniformArrays; }
-    void setNoStorageFormat(bool b)             { useUnknownFormat = b; }
-    bool getNoStorageFormat()             const { return useUnknownFormat; }
-    void setHlslOffsets()         { hlslOffsets = true; }
+    void setAutoMapBindings(bool map)
+    {
+        autoMapBindings = map;
+        if (autoMapBindings)
+            processes.addProcess("auto-map-bindings");
+    }
+    bool getAutoMapBindings() const { return autoMapBindings; }
+    void setAutoMapLocations(bool map)
+    {
+        autoMapLocations = map;
+        if (autoMapLocations)
+            processes.addProcess("auto-map-locations");
+    }
+    bool getAutoMapLocations() const { return autoMapLocations; }
+    void setFlattenUniformArrays(bool flatten)
+    {
+        flattenUniformArrays = flatten;
+        if (flattenUniformArrays)
+            processes.addProcess("flatten-uniform-arrays");
+    }
+    bool getFlattenUniformArrays() const { return flattenUniformArrays; }
+    void setNoStorageFormat(bool b)
+    {
+        useUnknownFormat = b;
+        if (useUnknownFormat)
+            processes.addProcess("no-storage-format");
+    }
+    bool getNoStorageFormat() const { return useUnknownFormat; }
+    void setHlslOffsets()
+    {
+        hlslOffsets = true;
+        if (hlslOffsets)
+            processes.addProcess("hlsl-offsets");
+    }
     bool usingHlslOFfsets() const { return hlslOffsets; }
-    void setUseStorageBuffer() { useStorageBuffer = true; }
+    void setUseStorageBuffer()
+    {
+        useStorageBuffer = true;
+        processes.addProcess("use-storage-buffer");
+    }
     bool usingStorageBuffer() const { return useStorageBuffer; }
-    void setHlslIoMapping(bool b) { hlslIoMapping = b; }
-    bool usingHlslIoMapping()     { return hlslIoMapping; }
+    void setHlslIoMapping(bool b)
+    {
+        hlslIoMapping = b;
+        if (hlslIoMapping)
+            processes.addProcess("hlsl-iomap");
+    }
+    bool usingHlslIoMapping() { return hlslIoMapping; }
+
     void setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode) { textureSamplerTransformMode = mode; }
 
     void setVersion(int v) { version = v; }
     int getVersion() const { return version; }
     void setProfile(EProfile p) { profile = p; }
     EProfile getProfile() const { return profile; }
-    void setSpv(const SpvVersion& s) { spvVersion = s; }
+    void setSpv(const SpvVersion& s)
+    {
+        spvVersion = s;
+
+        // client processes
+        if (spvVersion.vulkan > 0)
+            processes.addProcess("client vulkan100");
+        if (spvVersion.openGl > 0)
+            processes.addProcess("client opengl100");
+
+        // target-environment processes
+        if (spvVersion.vulkan == 100)
+            processes.addProcess("target-env vulkan1.0");
+        else if (spvVersion.vulkan > 0)
+            processes.addProcess("target-env vulkanUnknown");
+        if (spvVersion.openGl > 0)
+            processes.addProcess("target-env opengl");
+    }
     const SpvVersion& getSpv() const { return spvVersion; }
     EShLanguage getStage() const { return language; }
     void addRequestedExtension(const char* extension) { requestedExtensions.insert(extension); }
@@ -462,6 +599,13 @@
     const std::string& getSourceFile() const { return sourceFile; }
     void addSourceText(const char* text) { sourceText = sourceText + text; }
     const std::string& getSourceText() const { return sourceText; }
+    void addProcesses(const std::vector<std::string>& p) {
+        for (int i = 0; i < (int)p.size(); ++i)
+            processes.addProcess(p[i]);
+    }
+    void addProcess(const std::string& process) { processes.addProcess(process); }
+    void addProcessArgument(const std::string& arg) { processes.addArgument(arg); }
+    const std::vector<std::string>& getProcesses() const { return processes.getProcesses(); }
 
     const char* const implicitThisName = "@this";
 
@@ -558,6 +702,9 @@
     std::string sourceFile;
     std::string sourceText;
 
+    // for OpModuleProcessed, or equivalent
+    TProcesses processes;
+
 private:
     void operator=(TIntermediate&); // prevent assignments
 };
diff --git a/glslang/Public/ShaderLang.h b/glslang/Public/ShaderLang.h
index 12672ee..b968967 100644
--- a/glslang/Public/ShaderLang.h
+++ b/glslang/Public/ShaderLang.h
@@ -346,6 +346,7 @@
     void setPreamble(const char* s) { preamble = s; }
     void setEntryPoint(const char* entryPoint);
     void setSourceEntryPoint(const char* sourceEntryPointName);
+    void addProcesses(const std::vector<std::string>&);
     void setShiftSamplerBinding(unsigned int base);
     void setShiftTextureBinding(unsigned int base);
     void setShiftImageBinding(unsigned int base);