Squashed 'third_party/SPIRV-Tools/' changes from 54cd5e196..1a7f71afb

1a7f71afb clean: constexpr-ify and unify anon namespace use (#4991)
8ea3ae6be Split EliminateDeadInputComponents into safe and unsafe versions. (#4984)
a8647f59c Use Python3 for presubmit (#4986)
68e8327f2 Instrument: Change output buffer offset definitions (#4961)
996d4c021 spirv-val: Multiple interface var with same SC (#4969)
aae7d4132 Fix macos kokoro builds (#4985)
525bc3806 Add pass to eliminate dead output components (#4982)
54d4e77fa spirv-opt: Add const folding for CompositeInsert (#4943)
a5e766b2b spirv-val: Add VUID label for 07703 (#4980)
d35a78db5 Switch SPIRV-Tools to use spirv.hpp11 internally (#4981)
c8e1588cf Add passes to eliminate dead output stores (#4970)
a52de681d Prevent eliminating case constructs in block merging (#4976)
4563d9093 Only validate full layout in Vulkan environments (#4972)
9f3a4afae spirv-val: Label new Vulkan OpPtrAccessChain VUs (#4975)
b49a2caa7 Revert "test" (#4974)
da215f10c test
7326b967a Prevent null pointer from being dereferenced (#4971)
0ebf83057 spirv-val: Add OpPtrAccessChain Base checks (#4965)
eb113f0fd spirv-val: Improve PR 4831 error message (#4968)
ecd5b9c16 spirv-val: Add remaining Component decoration validation (#4966)
b53d3a6be Start SPIRV-Tools v2022.5
eb0a36633 Finalize SPIRV-Tools v2022.4
4a6290b56 Update CHANGES
a9291988d Roll external/spirv-headers/ 4bd8fc0c8..85a1ed200 (4 commits)
a25a9d0b5 Roll external/re2/ 5723bb895..d2836d1b1 (11 commits)
59043d177 Roll external/googletest/ 548b13dc3..d9bb8412d (78 commits)
95ae2da35 Roll external/effcee/ ddf5e2bb9..35912e1b7 (1 commit)
a3350c0ff Update SPIRV-Headers revision (#4962)
1cecf9170 Support Narrow Types in BitCast Folding Rule (#4941)
a6e6454ef spirv-val: Add SPV_ARM_core_builtins validation (#4958)
4dbc66380 spirv-val: Use ostringstream in id validation tests (#4956)
07d361b67 spirv-val: Add an option to use friendly names or not (#4951)
3ec6b3698 spirv-val: Consistently quote ids in messages (#4950)
e1a8b5d60 build: Fix BUILD.gn build error (#4948)
49230a230 spirv-opt: Remove unused folding rule (#4942)
b53d7a8af spirv-val: Add initial SPV_EXT_mesh_shader validation (#4924)
265b455c9 Fix CreatDebugInlinedAt to not invoke def_use_mgr (#4939)
ddbee48f8 spirv-opt: Fix stacked CompositeExtract constant folds (#4932)
f98473cee Remove `spvOpcodeTerminatesExecution` (#4931)
21146c1b4 Fix builtin validator for unimplemented opcodes. (#4940)
aeb1c64d4 spirv-val: Make it legal to use arrays of ray queries (#4938)
11d0d1622 Cleanup code for 272e4b3d0 (#4934)
91c29a197 spirv-val: Fix comment for checking extended alignments (#4937)
0c4ce11b4 spirv-val: Update VUID from 1.3.228 Vulkan spec (#4936)
5f4ce362a spirv-val: Label VUID 07290 (#4927)
8422d8a44 spirv-val: Label ShaderRecordBufferKHR VUID (#4926)
c3f844aec spirv-val: Test file suffix consistency (#4925)
272e4b3d0 Fix missing and incorrect DebugValues (#4929)
49deada73 Also consider EmitMeshTasksEXT terminator in spirv-opt. (#4930)
fb27bbf30 Fix DebugInlinedAt Line operand (#4928)
f5b27b651 spirv-diff: Allow no SpecId (#4904)
59cf5b134 spirv-val: consider OpEmitMeshTasksEXT a terminator instruction (#4923)
934a05978 spirv-val: Label Builtin Array Test VUIDs (#4921)
5f45f793a Support building on OpenBSD (#4912)
529955e03 Improve time to build dominators (#4916)
8eb850983 build: cmake: Add support for GNU/Hurd (#4895)
4386afb05 spirv-opt: Remove unused fold spec const code (#4906)
4c456f7da Implement tool changes for SPV_EXT_mesh_shader. (#4915)
33113abf4 Instrument: Add OpNames to generated functions and variables (#4873)
b5d1040b9 Fix ADCE to mark scope and inlined_at of line instructions as live. (#4910)
d51dc53d2 Improve algorithm to reorder blocks in a function (#4911)
fca39d5cb spirv-val: Better message for using OpTypeBool in input/output (#4901)
66bdbacc9 spirv-val: Use lookup table for Decoration string (#4903)
f76431cba spirv-val: Add SPV_KHR_ray_tracing storage class (#4868)
a98f05d02 tests: Make InstrumentPass tests use SinglePassRunAndMatch<> and stateful pattern matching (#4897)
b41e3e131 Disable DebugInfoMgr during the entire CompactIds pass (#4905)
3c1a14b2b spirv-val: SBT Index for OpExecuteCallableKHR (#4900)
0073a1fa3 spirv-val: Remove ImageWrite Texel todo (#4899)
71b2aee6c Add structs to eliminate dead input components (#4894)
1728c1d40 spirv-opt: fix copy-propagate-arrays index opti on structs. (#4891)
9abacb34a Fix ADCE to not eliminate top level DebugInfo instructions (#4889)
3a8a961cf Fix array copy propagation (#4890)
afbb52b13 Start SPIRV-Tools v2022.4
409e11679 Finalize SPIRV-Tools v2022.3
0a43a84e0 Fix shuffle feeding shuffle with undef literal (#4883)
0ebcdc4d1 Allow spirv-opt print-all to show pretty IDs (#4888)
ed3b9c83b Local access chain convert: check for negative indexes (#4884)
f20e8d05f spirv-val: Add SPV_KHR_ray_tracing instructions (#4871)
5e61ea209 Update CHANGES (#4886)
b362d2b7d spirv-diff: Fix asserts in ComparePreambleInstructions() (#4872)
08c542d34 spirv-val: Label VUID 06997 (#4881)

git-subtree-dir: third_party/SPIRV-Tools
git-subtree-split: 1a7f71afb42983b8b21bef656260964eb3852942
Change-Id: I6b7cf32b13d9ea53b00fed1b1541d4fe34cb01f5
diff --git a/Android.mk b/Android.mk
index cd1d7f8..bf9e580 100644
--- a/Android.mk
+++ b/Android.mk
@@ -61,6 +61,7 @@
 		source/val/validate_instruction.cpp \
 		source/val/validate_memory.cpp \
 		source/val/validate_memory_semantics.cpp \
+		source/val/validate_mesh_shading.cpp \
 		source/val/validate_misc.cpp \
 		source/val/validate_mode_setting.cpp \
 		source/val/validate_layout.cpp \
@@ -69,6 +70,7 @@
 		source/val/validate_non_uniform.cpp \
 		source/val/validate_primitives.cpp \
 		source/val/validate_ray_query.cpp \
+		source/val/validate_ray_tracing.cpp \
 		source/val/validate_scopes.cpp \
 		source/val/validate_small_type_uses.cpp \
 		source/val/validate_type.cpp
@@ -76,6 +78,7 @@
 SPVTOOLS_OPT_SRC_FILES := \
 		source/opt/aggressive_dead_code_elim_pass.cpp \
 		source/opt/amd_ext_to_khr.cpp \
+		source/opt/analyze_live_input_pass.cpp \
 		source/opt/basic_block.cpp \
 		source/opt/block_merge_pass.cpp \
 		source/opt/block_merge_util.cpp \
@@ -109,6 +112,7 @@
 		source/opt/eliminate_dead_functions_util.cpp \
 		source/opt/eliminate_dead_input_components_pass.cpp \
 		source/opt/eliminate_dead_members_pass.cpp \
+		source/opt/eliminate_dead_output_stores_pass.cpp \
 		source/opt/feature_manager.cpp \
 		source/opt/fix_func_call_arguments.cpp \
 		source/opt/fix_storage_class.cpp \
@@ -134,6 +138,7 @@
 		source/opt/ir_context.cpp \
 		source/opt/ir_loader.cpp \
 		source/opt/licm_pass.cpp \
+		source/opt/liveness.cpp \
 		source/opt/local_access_chain_convert_pass.cpp \
 		source/opt/local_redundancy_elimination.cpp \
 		source/opt/local_single_block_elim_pass.cpp \
@@ -215,7 +220,8 @@
 		                --core-insts-output=$(1)/core.insts-unified1.inc \
 		                --glsl-insts-output=$(1)/glsl.std.450.insts.inc \
 		                --opencl-insts-output=$(1)/opencl.std.insts.inc \
-		                --operand-kinds-output=$(1)/operand.kinds-unified1.inc
+		                --operand-kinds-output=$(1)/operand.kinds-unified1.inc \
+										--output-language=c++
 		@echo "[$(TARGET_ARCH_ABI)] Grammar (from unified1)  : instructions & operands <= grammar JSON files"
 $(LOCAL_PATH)/source/opcode.cpp: $(1)/core.insts-unified1.inc
 $(LOCAL_PATH)/source/operand.cpp: $(1)/operand.kinds-unified1.inc
@@ -289,7 +295,8 @@
 		                --extinst-debuginfo-grammar=$(SPV_DEBUGINFO_GRAMMAR) \
 		                --extinst-cldebuginfo100-grammar=$(SPV_CLDEBUGINFO100_GRAMMAR) \
 		                --extension-enum-output=$(1)/extension_enum.inc \
-		                --enum-string-mapping-output=$(1)/enum_string_mapping.inc
+		                --enum-string-mapping-output=$(1)/enum_string_mapping.inc \
+										--output-language=c++
 		@echo "[$(TARGET_ARCH_ABI)] Generate enum<->string mapping <= grammar JSON files"
 # Generated header extension_enum.inc is transitively included by table.h, which is
 # used pervasively.  Capture the pervasive dependency.
diff --git a/BUILD.bazel b/BUILD.bazel
index 35dfd66..0af7700 100644
--- a/BUILD.bazel
+++ b/BUILD.bazel
@@ -137,7 +137,7 @@
     copts = COMMON_COPTS,
     includes = ["source"],
     deps = [
-        "@spirv_headers//:spirv_c_headers",
+        "@spirv_headers//:spirv_cpp11_headers",
     ],
 )
 
@@ -162,7 +162,7 @@
     deps = [
         ":generated_headers",
         ":spirv_tools_headers",
-        "@spirv_headers//:spirv_c_headers",
+        "@spirv_headers//:spirv_cpp11_headers",
         "@spirv_headers//:spirv_common_headers",
     ],
 )
diff --git a/BUILD.gn b/BUILD.gn
index 9e9f6e5..14d431b 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -69,6 +69,8 @@
       rebase_path(cldebuginfo100_insts_file, root_build_dir),
       "--operand-kinds-output",
       rebase_path(operand_kinds_file, root_build_dir),
+      "--output-language",
+      "c++"
     ]
   }
 }
@@ -101,6 +103,8 @@
       rebase_path(extension_enum_file, root_build_dir),
       "--enum-string-mapping-output",
       rebase_path(extension_map_file, root_build_dir),
+      "--output-language",
+      "c++"
     ]
     inputs = [
       core_json_file,
@@ -142,6 +146,8 @@
       rebase_path(glsl_json_file, root_build_dir),
       "--glsl-insts-output",
       rebase_path(glsl_insts_file, root_build_dir),
+      "--output-language",
+      "c++"
     ]
     inputs = [
       core_json_file,
@@ -526,11 +532,13 @@
     "source/val/validate_memory.cpp",
     "source/val/validate_memory_semantics.cpp",
     "source/val/validate_memory_semantics.h",
+    "source/val/validate_mesh_shading.cpp",
     "source/val/validate_misc.cpp",
     "source/val/validate_mode_setting.cpp",
     "source/val/validate_non_uniform.cpp",
     "source/val/validate_primitives.cpp",
     "source/val/validate_ray_query.cpp",
+    "source/val/validate_ray_tracing.cpp",
     "source/val/validate_scopes.cpp",
     "source/val/validate_scopes.h",
     "source/val/validate_small_type_uses.cpp",
@@ -560,6 +568,8 @@
     "source/opt/aggressive_dead_code_elim_pass.h",
     "source/opt/amd_ext_to_khr.cpp",
     "source/opt/amd_ext_to_khr.h",
+    "source/opt/analyze_live_input_pass.cpp",
+    "source/opt/analyze_live_input_pass.h",
     "source/opt/basic_block.cpp",
     "source/opt/basic_block.h",
     "source/opt/block_merge_pass.cpp",
@@ -626,6 +636,8 @@
     "source/opt/eliminate_dead_input_components_pass.h",
     "source/opt/eliminate_dead_members_pass.cpp",
     "source/opt/eliminate_dead_members_pass.h",
+    "source/opt/eliminate_dead_output_stores_pass.cpp",
+    "source/opt/eliminate_dead_output_stores_pass.h",
     "source/opt/empty_pass.h",
     "source/opt/feature_manager.cpp",
     "source/opt/feature_manager.h",
@@ -679,6 +691,8 @@
     "source/opt/iterator.h",
     "source/opt/licm_pass.cpp",
     "source/opt/licm_pass.h",
+    "source/opt/liveness.cpp",
+    "source/opt/liveness.h",
     "source/opt/local_access_chain_convert_pass.cpp",
     "source/opt/local_access_chain_convert_pass.h",
     "source/opt/local_redundancy_elimination.cpp",
diff --git a/CHANGES b/CHANGES
index f5e91cb..384805c 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,18 +1,55 @@
 Revision history for SPIRV-Tools
 
-v2022.3-dev 2022-05-31
+v2022.5-dev 2022-10-12
+   - Start v2022.5-dev
+
+v2022.4 2022-10-12
+  - General
+    - Support Narrow Types in BitCast Folding Rule (#4941)
+    - spirv-diff: Allow no SpecId (#4904)
+    - build: cmake: Add support for GNU/Hurd (#4895)
+    - Implement tool changes for SPV_EXT_mesh_shader. (#4915)
+  - Validator
+    - spirv-val: Add SPV_ARM_core_builtins validation (#4958)
+    - spirv-val: Add an option to use friendly names or not (#4951)
+    - spirv-val: Consistently quote ids in messages (#4950)
+    - spirv-val: Add initial SPV_EXT_mesh_shader validation (#4924)
+    - spirv-val: Make it legal to use arrays of ray queries (#4938)
+    - spirv-val: Better message for using OpTypeBool in input/output (#4901)
+    - spirv-val: Add SPV_KHR_ray_tracing storage class (#4868)
+  - Optimizer
+    - spirv-opt: Fix stacked CompositeExtract constant folds (#4932)
+    - Improve time to build dominators (#4916)
+    - Fix ADCE to mark scope and inlined_at of line instructions as live. (#4910)
+    - Improve algorithm to reorder blocks in a function (#4911)
+    - Add structs to eliminate dead input components (#4894)
+    - spirv-opt: fix copy-propagate-arrays index opti on structs. (#4891)
+    - Fix ADCE to not eliminate top level DebugInfo instructions (#4889)
+    - Fix array copy propagation (#4890)
+
+v2022.3 2022-08-08
   - General
     - Add SPV_KHR_fragment_shader_barycentric support (#4805)
     - Add support for SPV_KHR_subgroup_rotate (#4786)
+    - use exec_tools instead of tools for better RBE compatibility (#4837)
+    - Write binary files to stdout in binary on windows. (#4834)
+    - Allow spirv-opt print-all to show pretty IDs (#4888)
+  - Validator
+    - spirv-val: Add PerVertexKHR (#4807)
+    - spirv-opt : Add FixFuncCallArgumentsPass (#4775)
+    - spirv-val: Add CullMaskKHR support (#4792)
+    - Require ColMajor or RowMajor for matrices (#4878)
+    - spirv-val: Add SPV_KHR_ray_query (#4848)
+    - spirv-val: Add SPV_KHR_ray_tracing instructions (#4871)
+    - Implement SPV_NV_bindless_texture related changes (#4847)
+    - spirv-val: Add OpConvertUToAccelerationStructureKHR (#4838)
+    - spirv-val: Add support for SPV_AMD_shader_early_and_late_fragment_tests (#4812)
   - Optimizer
     - Fold multiply and subtraction into FMA with negation (#4808)
     - Add more folding for composite instructions (#4802)
     - spirv-opt: add pass for interface variable scalar replacement (#4779)
     - Don't try to unroll loop with step count 0. (#4769)
-  - Validator
-    - spirv-val: Add PerVertexKHR (#4807)
-    - spirv-opt : Add FixFuncCallArgumentsPass (#4775)
-    - spirv-val: Add CullMaskKHR support (#4792)
+    - spirv-opt: SPV_NV_bindless_texture related changes (#4870)
   - Linker
     - linker: Recalculate interface variables (#4784)
 
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 76b87d8..7815a29 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -56,8 +56,12 @@
   set(SPIRV_TIMER_ENABLED ${SPIRV_ALLOW_TIMERS})
 elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "FreeBSD")
   add_definitions(-DSPIRV_FREEBSD)
+elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD")
+  add_definitions(-DSPIRV_OPENBSD)
 elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Fuchsia")
   add_definitions(-DSPIRV_FUCHSIA)
+elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "GNU")
+  add_definitions(-DSPIRV_GNU)
 else()
   message(FATAL_ERROR "Your platform '${CMAKE_SYSTEM_NAME}' is not supported!")
 endif()
@@ -196,7 +200,7 @@
     if(NOT "${SPIRV_PERF}" STREQUAL "")
       target_compile_options(${TARGET} PRIVATE -fno-omit-frame-pointer)
     endif()
-    if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+    if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
       set(SPIRV_USE_SANITIZER "" CACHE STRING
         "Use the clang sanitizer [address|memory|thread|...]")
       if(NOT "${SPIRV_USE_SANITIZER}" STREQUAL "")
diff --git a/DEPS b/DEPS
index 78c9dd3..a134582 100644
--- a/DEPS
+++ b/DEPS
@@ -3,10 +3,10 @@
 vars = {
   'github': 'https://github.com',
 
-  'effcee_revision': 'ddf5e2bb92957dc8a12c5392f8495333d6844133',
-  'googletest_revision': '548b13dc3c02b93f60eeff9a0cc6e11c1ea722ca',
-  're2_revision': '5723bb8950318135ed9cf4fc76bed988a087f536',
-  'spirv_headers_revision': 'b2a156e1c0434bc8c99aaebba1c7be98be7ac580',
+  'effcee_revision': '35912e1b7778ec2ddcff7e7188177761539e59e0',
+  'googletest_revision': 'd9bb8412d60b993365abb53f00b6dad9b2c01b62',
+  're2_revision': 'd2836d1b1c34c4e330a85a1006201db474bf2c8a',
+  'spirv_headers_revision': '47f2465ee3e78ec5ec38f00b2c405d9475797228',
 }
 
 deps = {
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index dd3117f..847deb7 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -18,6 +18,8 @@
 for more details about the presubmit API built into depot_tools.
 """
 
+USE_PYTHON3 = True
+
 LINT_FILTERS = [
   "-build/storage_class",
   "-readability/casting",
diff --git a/build_defs.bzl b/build_defs.bzl
index 7189137..ed726ae 100644
--- a/build_defs.bzl
+++ b/build_defs.bzl
@@ -66,7 +66,8 @@
             "--extinst-debuginfo-grammar=$(location {1}) " +
             "--extinst-cldebuginfo100-grammar=$(location {2}) " +
             "--core-insts-output=$(location {3}) " +
-            "--operand-kinds-output=$(location {4})"
+            "--operand-kinds-output=$(location {4}) " +
+            "--output-language=c++"
         ).format(*fmtargs),
         cmd_bat = (
             "$(location :generate_grammar_tables) " +
@@ -74,7 +75,8 @@
             "--extinst-debuginfo-grammar=$(location {1}) " +
             "--extinst-cldebuginfo100-grammar=$(location {2}) " +
             "--core-insts-output=$(location {3}) " +
-            "--operand-kinds-output=$(location {4})"
+            "--operand-kinds-output=$(location {4}) " +
+            "--output-language=c++"
         ).format(*fmtargs),
         exec_tools = [":generate_grammar_tables"],
         visibility = ["//visibility:private"],
@@ -103,7 +105,8 @@
             "--extinst-debuginfo-grammar=$(location {1}) " +
             "--extinst-cldebuginfo100-grammar=$(location {2}) " +
             "--extension-enum-output=$(location {3}) " +
-            "--enum-string-mapping-output=$(location {4})"
+            "--enum-string-mapping-output=$(location {4}) " +
+            "--output-language=c++"
         ).format(*fmtargs),
         cmd_bat = (
             "$(location :generate_grammar_tables) " +
@@ -111,7 +114,8 @@
             "--extinst-debuginfo-grammar=$(location {1}) " +
             "--extinst-cldebuginfo100-grammar=$(location {2}) " +
             "--extension-enum-output=$(location {3}) " +
-            "--enum-string-mapping-output=$(location {4})"
+            "--enum-string-mapping-output=$(location {4}) " +
+            "--output-language=c++"
         ).format(*fmtargs),
         exec_tools = [":generate_grammar_tables"],
         visibility = ["//visibility:private"],
@@ -158,12 +162,14 @@
         cmd = (
             "$(location :generate_grammar_tables) " +
             "--extinst-glsl-grammar=$(location {0}) " +
-            "--glsl-insts-output=$(location {1})"
+            "--glsl-insts-output=$(location {1}) " +
+            "--output-language=c++"
         ).format(*fmtargs),
         cmd_bat = (
             "$(location :generate_grammar_tables) " +
             "--extinst-glsl-grammar=$(location {0}) " +
-            "--glsl-insts-output=$(location {1})"
+            "--glsl-insts-output=$(location {1}) " +
+            "--output-language=c++"
         ).format(*fmtargs),
         exec_tools = [":generate_grammar_tables"],
         visibility = ["//visibility:private"],
diff --git a/include/spirv-tools/instrument.hpp b/include/spirv-tools/instrument.hpp
index a19491f..a75561b 100644
--- a/include/spirv-tools/instrument.hpp
+++ b/include/spirv-tools/instrument.hpp
@@ -36,16 +36,25 @@
 // generated by InstrumentPass::GenDebugStreamWrite. This method is utilized
 // by InstBindlessCheckPass, InstBuffAddrCheckPass, and InstDebugPrintfPass.
 //
-// The first member of the debug output buffer contains the next available word
+// The 1st member of the debug output buffer contains a set of flags
+// controlling the behavior of instrumentation code.
+static const int kDebugOutputFlagsOffset = 0;
+
+// Values stored at kDebugOutputFlagsOffset
+enum kInstFlags : unsigned int {
+  kInstBufferOOBEnable = 0x1,
+};
+
+// The 2nd member of the debug output buffer contains the next available word
 // in the data stream to be written. Shaders will atomically read and update
 // this value so as not to overwrite each others records. This value must be
 // initialized to zero
-static const int kDebugOutputSizeOffset = 0;
+static const int kDebugOutputSizeOffset = 1;
 
-// The second member of the output buffer is the start of the stream of records
+// The 3rd member of the output buffer is the start of the stream of records
 // written by the instrumented shaders. Each record represents a validation
 // error. The format of the records is documented below.
-static const int kDebugOutputDataOffset = 1;
+static const int kDebugOutputDataOffset = 2;
 
 // Common Stream Record Offsets
 //
diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h
index e1b8890..b549efb 100644
--- a/include/spirv-tools/libspirv.h
+++ b/include/spirv-tools/libspirv.h
@@ -670,6 +670,10 @@
 SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetAllowLocalSizeId(
     spv_validator_options options, bool val);
 
+// Whether friendly names should be used in validation error messages.
+SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetFriendlyNames(
+    spv_validator_options options, bool val);
+
 // Creates an optimizer options object with default options. Returns a valid
 // options object. The object remains valid until it is passed into
 // |spvOptimizerOptionsDestroy|.
diff --git a/include/spirv-tools/libspirv.hpp b/include/spirv-tools/libspirv.hpp
index 25eb8a1..408e3eb 100644
--- a/include/spirv-tools/libspirv.hpp
+++ b/include/spirv-tools/libspirv.hpp
@@ -148,6 +148,11 @@
     spvValidatorOptionsSetBeforeHlslLegalization(options_, val);
   }
 
+  // Whether friendly names should be used in validation error messages.
+  void SetFriendlyNames(bool val) {
+    spvValidatorOptionsSetFriendlyNames(options_, val);
+  }
+
  private:
   spv_validator_options options_;
 };
diff --git a/include/spirv-tools/optimizer.hpp b/include/spirv-tools/optimizer.hpp
index 9497356..41752d6 100644
--- a/include/spirv-tools/optimizer.hpp
+++ b/include/spirv-tools/optimizer.hpp
@@ -19,6 +19,7 @@
 #include <ostream>
 #include <string>
 #include <unordered_map>
+#include <unordered_set>
 #include <utility>
 #include <vector>
 
@@ -887,12 +888,59 @@
 Optimizer::PassToken CreateInterpolateFixupPass();
 
 // Removes unused components from composite input variables. Current
-// implementation just removes trailing unused components from input arrays.
-// The pass performs best after maximizing dead code removal. A subsequent dead
-// code elimination pass would be beneficial in removing newly unused component
-// types.
+// implementation just removes trailing unused components from input arrays
+// and structs. The pass performs best after maximizing dead code removal.
+// A subsequent dead code elimination pass would be beneficial in removing
+// newly unused component types.
+//
+// WARNING: This pass can only be safely applied standalone to vertex shaders
+// as it can otherwise cause interface incompatibilities with the preceding
+// shader in the pipeline. If applied to non-vertex shaders, the user should
+// follow by applying EliminateDeadOutputStores and
+// EliminateDeadOutputComponents to the preceding shader.
 Optimizer::PassToken CreateEliminateDeadInputComponentsPass();
 
+// Removes unused components from composite output variables. Current
+// implementation just removes trailing unused components from output arrays
+// and structs. The pass performs best after eliminating dead output stores.
+// A subsequent dead code elimination pass would be beneficial in removing
+// newly unused component types. Currently only supports vertex and fragment
+// shaders.
+//
+// WARNING: This pass cannot be safely applied standalone as it can cause
+// interface incompatibility with the following shader in the pipeline. The
+// user should first apply EliminateDeadInputComponents to the following
+// shader, then apply EliminateDeadOutputStores to this shader.
+Optimizer::PassToken CreateEliminateDeadOutputComponentsPass();
+
+// Removes unused components from composite input variables. This safe
+// version will not cause interface incompatibilities since it only changes
+// vertex shaders. The current implementation just removes trailing unused
+// components from input structs and input arrays. The pass performs best
+// after maximizing dead code removal. A subsequent dead code elimination
+// pass would be beneficial in removing newly unused component types.
+Optimizer::PassToken CreateEliminateDeadInputComponentsSafePass();
+
+// Analyzes shader and populates |live_locs| and |live_builtins|. Best results
+// will be obtained if shader has all dead code eliminated first. |live_locs|
+// and |live_builtins| are subsequently used when calling
+// CreateEliminateDeadOutputStoresPass on the preceding shader. Currently only
+// supports tesc, tese, geom, and frag shaders.
+Optimizer::PassToken CreateAnalyzeLiveInputPass(
+    std::unordered_set<uint32_t>* live_locs,
+    std::unordered_set<uint32_t>* live_builtins);
+
+// Removes stores to output locations not listed in |live_locs| or
+// |live_builtins|. Best results are obtained if constant propagation is
+// performed first. A subsequent call to ADCE will eliminate any dead code
+// created by the removal of the stores. A subsequent call to
+// CreateEliminateDeadOutputComponentsPass will eliminate any dead output
+// components created by the elimination of the stores. Currently only supports
+// vert, tesc, tese, and geom shaders.
+Optimizer::PassToken CreateEliminateDeadOutputStoresPass(
+    std::unordered_set<uint32_t>* live_locs,
+    std::unordered_set<uint32_t>* live_builtins);
+
 // Creates a convert-to-sampled-image pass to convert images and/or
 // samplers with given pairs of descriptor set and binding to sampled image.
 // If a pair of an image and a sampler have the same pair of descriptor set and
diff --git a/kokoro/scripts/macos/build.sh b/kokoro/scripts/macos/build.sh
index 4612823..3618e69 100644
--- a/kokoro/scripts/macos/build.sh
+++ b/kokoro/scripts/macos/build.sh
@@ -43,11 +43,9 @@
 # Invoke the build.
 BUILD_SHA=${KOKORO_GITHUB_COMMIT:-$KOKORO_GITHUB_PULL_REQUEST_COMMIT}
 echo $(date): Starting build...
-# We need Python 3.  At the moment python3.7 is the newest Python on Kokoro.
 cmake \
   -GNinja \
   -DCMAKE_INSTALL_PREFIX=$KOKORO_ARTIFACTS_DIR/install \
-  -DPYTHON_EXECUTABLE:FILEPATH=/usr/local/bin/python3.7 \
   -DCMAKE_C_COMPILER=clang \
   -DCMAKE_CXX_COMPILER=clang++ \
   -DCMAKE_BUILD_TYPE=$BUILD_TYPE \
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
index 1ceb78f..f904024 100644
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -37,6 +37,7 @@
       --extinst-cldebuginfo100-grammar=${CLDEBUGINFO100_GRAMMAR_JSON_FILE}
       --core-insts-output=${GRAMMAR_INSTS_INC_FILE}
       --operand-kinds-output=${GRAMMAR_KINDS_INC_FILE}
+      --output-language=c++
     DEPENDS ${GRAMMAR_PROCESSING_SCRIPT}
             ${GRAMMAR_JSON_FILE}
             ${DEBUGINFO_GRAMMAR_JSON_FILE}
@@ -58,6 +59,7 @@
       --extinst-cldebuginfo100-grammar=${CLDEBUGINFO100_GRAMMAR_JSON_FILE}
       --extension-enum-output=${GRAMMAR_EXTENSION_ENUM_INC_FILE}
       --enum-string-mapping-output=${GRAMMAR_ENUM_STRING_MAPPING_INC_FILE}
+      --output-language=c++
     DEPENDS ${GRAMMAR_PROCESSING_SCRIPT}
             ${GRAMMAR_JSON_FILE}
             ${DEBUGINFO_GRAMMAR_JSON_FILE}
@@ -92,6 +94,7 @@
     COMMAND ${PYTHON_EXECUTABLE} ${GRAMMAR_PROCESSING_SCRIPT}
       --extinst-glsl-grammar=${GLSL_GRAMMAR_JSON_FILE}
       --glsl-insts-output=${GRAMMAR_INC_FILE}
+      --output-language=c++
     DEPENDS ${GRAMMAR_PROCESSING_SCRIPT} ${CORE_GRAMMAR_JSON_FILE} ${GLSL_GRAMMAR_JSON_FILE}
     COMMENT "Generate info tables for GLSL extended instructions and operands v${CONFIG_VERSION}.")
   list(APPEND EXTINST_CPP_DEPENDS ${GRAMMAR_INC_FILE})
@@ -318,11 +321,13 @@
   ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_logicals.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_memory.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_memory_semantics.cpp
+  ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_mesh_shading.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_misc.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_mode_setting.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_non_uniform.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_primitives.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_ray_query.cpp
+  ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_ray_tracing.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_scopes.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_small_type_uses.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_type.cpp
diff --git a/source/assembly_grammar.cpp b/source/assembly_grammar.cpp
index 4f5942a..6df823e 100644
--- a/source/assembly_grammar.cpp
+++ b/source/assembly_grammar.cpp
@@ -78,16 +78,16 @@
 
 // Associates an opcode with its name.
 struct SpecConstantOpcodeEntry {
-  SpvOp opcode;
+  spv::Op opcode;
   const char* name;
 };
 
 // All the opcodes allowed as the operation for OpSpecConstantOp.
-// The name does not have the usual "Op" prefix. For example opcode SpvOpIAdd
-// is associated with the name "IAdd".
+// The name does not have the usual "Op" prefix. For example opcode
+// spv::Op::IAdd is associated with the name "IAdd".
 //
 // clang-format off
-#define CASE(NAME) { SpvOp##NAME, #NAME }
+#define CASE(NAME) { spv::Op::Op##NAME, #NAME }
 const SpecConstantOpcodeEntry kOpSpecConstantOpcodes[] = {
     // Conversion
     CASE(SConvert),
@@ -173,7 +173,7 @@
 }
 
 CapabilitySet AssemblyGrammar::filterCapsAgainstTargetEnv(
-    const SpvCapability* cap_array, uint32_t count) const {
+    const spv::Capability* cap_array, uint32_t count) const {
   CapabilitySet cap_set;
   for (uint32_t i = 0; i < count; ++i) {
     spv_operand_desc cap_desc = {};
@@ -194,7 +194,7 @@
   return spvOpcodeTableNameLookup(target_env_, opcodeTable_, name, desc);
 }
 
-spv_result_t AssemblyGrammar::lookupOpcode(SpvOp opcode,
+spv_result_t AssemblyGrammar::lookupOpcode(spv::Op opcode,
                                            spv_opcode_desc* desc) const {
   return spvOpcodeTableValueLookup(target_env_, opcodeTable_, opcode, desc);
 }
@@ -214,7 +214,7 @@
 }
 
 spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(const char* name,
-                                                       SpvOp* opcode) const {
+                                                       spv::Op* opcode) const {
   const auto* last = kOpSpecConstantOpcodes + kNumOpSpecConstantOpcodes;
   const auto* found =
       std::find_if(kOpSpecConstantOpcodes, last,
@@ -226,7 +226,7 @@
   return SPV_SUCCESS;
 }
 
-spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(SpvOp opcode) const {
+spv_result_t AssemblyGrammar::lookupSpecConstantOpcode(spv::Op opcode) const {
   const auto* last = kOpSpecConstantOpcodes + kNumOpSpecConstantOpcodes;
   const auto* found =
       std::find_if(kOpSpecConstantOpcodes, last,
diff --git a/source/assembly_grammar.h b/source/assembly_grammar.h
index 17c2bd3..36fdd08 100644
--- a/source/assembly_grammar.h
+++ b/source/assembly_grammar.h
@@ -41,7 +41,7 @@
 
   // Removes capabilities not available in the current target environment and
   // returns the rest.
-  CapabilitySet filterCapsAgainstTargetEnv(const SpvCapability* cap_array,
+  CapabilitySet filterCapsAgainstTargetEnv(const spv::Capability* cap_array,
                                            uint32_t count) const;
 
   // Fills in the desc parameter with the information about the opcode
@@ -52,7 +52,7 @@
   // Fills in the desc parameter with the information about the opcode
   // of the valid. Returns SPV_SUCCESS if the opcode was found, and
   // SPV_ERROR_INVALID_LOOKUP if the opcode does not exist.
-  spv_result_t lookupOpcode(SpvOp opcode, spv_opcode_desc* desc) const;
+  spv_result_t lookupOpcode(spv::Op opcode, spv_opcode_desc* desc) const;
 
   // Fills in the desc parameter with the information about the given
   // operand. Returns SPV_SUCCESS if the operand was found, and
@@ -82,11 +82,12 @@
   // the integer add opcode for OpSpecConstantOp.  On success, returns
   // SPV_SUCCESS and sends the discovered operation code through the opcode
   // parameter.  On failure, returns SPV_ERROR_INVALID_LOOKUP.
-  spv_result_t lookupSpecConstantOpcode(const char* name, SpvOp* opcode) const;
+  spv_result_t lookupSpecConstantOpcode(const char* name,
+                                        spv::Op* opcode) const;
 
   // Returns SPV_SUCCESS if the given opcode is valid as the opcode operand
   // to OpSpecConstantOp.
-  spv_result_t lookupSpecConstantOpcode(SpvOp opcode) const;
+  spv_result_t lookupSpecConstantOpcode(spv::Op opcode) const;
 
   // Parses a mask expression string for the given operand type.
   //
diff --git a/source/binary.cpp b/source/binary.cpp
index 24d32f8..beb56be 100644
--- a/source/binary.cpp
+++ b/source/binary.cpp
@@ -156,7 +156,7 @@
   // Issues a diagnostic describing an exhaustion of input condition when
   // trying to decode an instruction operand, and returns
   // SPV_ERROR_INVALID_BINARY.
-  spv_result_t exhaustedInputDiagnostic(size_t inst_offset, SpvOp opcode,
+  spv_result_t exhaustedInputDiagnostic(size_t inst_offset, spv::Op opcode,
                                         spv_operand_type_t type) {
     return diagnostic() << "End of input reached while decoding Op"
                         << spvOpcodeString(opcode) << " starting at word "
@@ -318,7 +318,7 @@
                         << inst_word_count;
   }
   spv_opcode_desc opcode_desc;
-  if (grammar_.lookupOpcode(static_cast<SpvOp>(inst.opcode), &opcode_desc))
+  if (grammar_.lookupOpcode(static_cast<spv::Op>(inst.opcode), &opcode_desc))
     return diagnostic() << "Invalid opcode: " << inst.opcode;
 
   // Advance past the opcode word.  But remember the of the start
@@ -418,7 +418,7 @@
                                   std::vector<uint32_t>* words,
                                   std::vector<spv_parsed_operand_t>* operands,
                                   spv_operand_pattern_t* expected_operands) {
-  const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
+  const spv::Op opcode = static_cast<spv::Op>(inst->opcode);
   // We'll fill in this result as we go along.
   spv_parsed_operand_t parsed_operand;
   parsed_operand.offset = uint16_t(_.word_index - inst_offset);
@@ -473,7 +473,7 @@
       if (!word) return diagnostic(SPV_ERROR_INVALID_ID) << "Id is 0";
       parsed_operand.type = SPV_OPERAND_TYPE_ID;
 
-      if (opcode == SpvOpExtInst && parsed_operand.offset == 3) {
+      if (opcode == spv::Op::OpExtInst && parsed_operand.offset == 3) {
         // The current word is the extended instruction set Id.
         // Set the extended instruction set type for the current instruction.
         auto ext_inst_type_iter = _.import_id_to_ext_inst_type.find(word);
@@ -494,7 +494,7 @@
       break;
 
     case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: {
-      assert(SpvOpExtInst == opcode);
+      assert(spv::Op::OpExtInst == opcode);
       assert(inst->ext_inst_type != SPV_EXT_INST_TYPE_NONE);
       spv_ext_inst_desc ext_inst;
       if (grammar_.lookupExtInst(inst->ext_inst_type, word, &ext_inst) ==
@@ -516,14 +516,14 @@
     } break;
 
     case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: {
-      assert(SpvOpSpecConstantOp == opcode);
-      if (word > static_cast<uint32_t>(SpvOp::SpvOpMax) ||
-          grammar_.lookupSpecConstantOpcode(SpvOp(word))) {
+      assert(spv::Op::OpSpecConstantOp == opcode);
+      if (word > static_cast<uint32_t>(spv::Op::Max) ||
+          grammar_.lookupSpecConstantOpcode(spv::Op(word))) {
         return diagnostic()
                << "Invalid " << spvOperandTypeStr(type) << ": " << word;
       }
       spv_opcode_desc opcode_entry = nullptr;
-      if (grammar_.lookupOpcode(SpvOp(word), &opcode_entry)) {
+      if (grammar_.lookupOpcode(spv::Op(word), &opcode_entry)) {
         return diagnostic(SPV_ERROR_INTERNAL)
                << "OpSpecConstant opcode table out of sync";
       }
@@ -549,7 +549,7 @@
     case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
     case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
       parsed_operand.type = SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER;
-      if (opcode == SpvOpSwitch) {
+      if (opcode == spv::Op::OpSwitch) {
         // The literal operands have the same type as the value
         // referenced by the selector Id.
         const uint32_t selector_id = peekAt(inst_offset + 1);
@@ -575,7 +575,8 @@
                               << " is not a scalar integer";
         }
       } else {
-        assert(opcode == SpvOpConstant || opcode == SpvOpSpecConstant);
+        assert(opcode == spv::Op::OpConstant ||
+               opcode == spv::Op::OpSpecConstant);
         // The literal number type is determined by the type Id for the
         // constant.
         assert(inst->type_id);
@@ -607,7 +608,7 @@
       parsed_operand.num_words = uint16_t(string_num_words);
       parsed_operand.type = SPV_OPERAND_TYPE_LITERAL_STRING;
 
-      if (SpvOpExtInstImport == opcode) {
+      if (spv::Op::OpExtInstImport == opcode) {
         // Record the extended instruction type for the ID for this import.
         // There is only one string literal argument to OpExtInstImport,
         // so it's sufficient to guard this just on the opcode.
@@ -789,14 +790,14 @@
 
 void Parser::recordNumberType(size_t inst_offset,
                               const spv_parsed_instruction_t* inst) {
-  const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
+  const spv::Op opcode = static_cast<spv::Op>(inst->opcode);
   if (spvOpcodeGeneratesType(opcode)) {
     NumberType info = {SPV_NUMBER_NONE, 0};
-    if (SpvOpTypeInt == opcode) {
+    if (spv::Op::OpTypeInt == opcode) {
       const bool is_signed = peekAt(inst_offset + 3) != 0;
       info.type = is_signed ? SPV_NUMBER_SIGNED_INT : SPV_NUMBER_UNSIGNED_INT;
       info.bit_width = peekAt(inst_offset + 2);
-    } else if (SpvOpTypeFloat == opcode) {
+    } else if (spv::Op::OpTypeFloat == opcode) {
       info.type = SPV_NUMBER_FLOATING;
       info.bit_width = peekAt(inst_offset + 2);
     }
diff --git a/source/cfa.h b/source/cfa.h
index f55a7bd..9ae3e39 100644
--- a/source/cfa.h
+++ b/source/cfa.h
@@ -56,8 +56,33 @@
   ///
   /// This function performs a depth first traversal from the \p entry
   /// BasicBlock and calls the pre/postorder functions when it needs to process
+  /// the node in pre order, post order.
+  ///
+  /// @param[in] entry      The root BasicBlock of a CFG
+  /// @param[in] successor_func  A function which will return a pointer to the
+  ///                            successor nodes
+  /// @param[in] preorder   A function that will be called for every block in a
+  ///                       CFG following preorder traversal semantics
+  /// @param[in] postorder  A function that will be called for every block in a
+  ///                       CFG following postorder traversal semantics
+  /// @param[in] terminal   A function that will be called to determine if the
+  ///                       search should stop at the given node.
+  /// NOTE: The @p successor_func and predecessor_func each return a pointer to
+  /// a collection such that iterators to that collection remain valid for the
+  /// lifetime of the algorithm.
+  static void DepthFirstTraversal(const BB* entry,
+                                  get_blocks_func successor_func,
+                                  std::function<void(cbb_ptr)> preorder,
+                                  std::function<void(cbb_ptr)> postorder,
+                                  std::function<bool(cbb_ptr)> terminal);
+
+  /// @brief Depth first traversal starting from the \p entry BasicBlock
+  ///
+  /// This function performs a depth first traversal from the \p entry
+  /// BasicBlock and calls the pre/postorder functions when it needs to process
   /// the node in pre order, post order. It also calls the backedge function
-  /// when a back edge is encountered.
+  /// when a back edge is encountered. The backedge function can be empty.  The
+  /// runtime of the algorithm is improved if backedge is empty.
   ///
   /// @param[in] entry      The root BasicBlock of a CFG
   /// @param[in] successor_func  A function which will return a pointer to the
@@ -67,12 +92,11 @@
   /// @param[in] postorder  A function that will be called for every block in a
   ///                       CFG following postorder traversal semantics
   /// @param[in] backedge   A function that will be called when a backedge is
-  ///                       encountered during a traversal
+  ///                       encountered during a traversal.
   /// @param[in] terminal   A function that will be called to determine if the
   ///                       search should stop at the given node.
   /// NOTE: The @p successor_func and predecessor_func each return a pointer to
-  /// a
-  /// collection such that iterators to that collection remain valid for the
+  /// a collection such that iterators to that collection remain valid for the
   /// lifetime of the algorithm.
   static void DepthFirstTraversal(
       const BB* entry, get_blocks_func successor_func,
@@ -137,12 +161,27 @@
 }
 
 template <class BB>
+void CFA<BB>::DepthFirstTraversal(const BB* entry,
+                                  get_blocks_func successor_func,
+                                  std::function<void(cbb_ptr)> preorder,
+                                  std::function<void(cbb_ptr)> postorder,
+                                  std::function<bool(cbb_ptr)> terminal) {
+  DepthFirstTraversal(entry, successor_func, preorder, postorder,
+                      /* backedge = */ {}, terminal);
+}
+
+template <class BB>
 void CFA<BB>::DepthFirstTraversal(
     const BB* entry, get_blocks_func successor_func,
     std::function<void(cbb_ptr)> preorder,
     std::function<void(cbb_ptr)> postorder,
     std::function<void(cbb_ptr, cbb_ptr)> backedge,
     std::function<bool(cbb_ptr)> terminal) {
+  assert(successor_func && "The successor function cannot be empty.");
+  assert(preorder && "The preorder function cannot be empty.");
+  assert(postorder && "The postorder function cannot be empty.");
+  assert(terminal && "The terminal function cannot be empty.");
+
   std::unordered_set<uint32_t> processed;
 
   /// NOTE: work_list is the sequence of nodes from the root node to the node
@@ -162,7 +201,7 @@
     } else {
       BB* child = *top.iter;
       top.iter++;
-      if (FindInWorkList(work_list, child->id())) {
+      if (backedge && FindInWorkList(work_list, child->id())) {
         backedge(top.block, child);
       }
       if (processed.count(child->id()) == 0) {
@@ -236,10 +275,16 @@
 
   std::vector<std::pair<bb_ptr, bb_ptr>> out;
   for (auto idom : idoms) {
+    // At this point if there is no dominator for the node, just make it
+    // reflexive.
+    auto dominator = std::get<1>(idom).dominator;
+    if (dominator == undefined_dom) {
+      dominator = std::get<1>(idom).postorder_index;
+    }
     // NOTE: performing a const cast for convenient usage with
     // UpdateImmediateDominators
     out.push_back({const_cast<BB*>(std::get<0>(idom)),
-                   const_cast<BB*>(postorder[std::get<1>(idom).dominator])});
+                   const_cast<BB*>(postorder[dominator])});
   }
 
   // Sort by postorder index to generate a deterministic ordering of edges.
@@ -269,14 +314,12 @@
 
   auto mark_visited = [&visited](const BB* b) { visited.insert(b); };
   auto ignore_block = [](const BB*) {};
-  auto ignore_blocks = [](const BB*, const BB*) {};
   auto no_terminal_blocks = [](const BB*) { return false; };
 
   auto traverse_from_root = [&mark_visited, &succ_func, &ignore_block,
-                             &ignore_blocks,
                              &no_terminal_blocks](const BB* entry) {
     DepthFirstTraversal(entry, succ_func, mark_visited, ignore_block,
-                        ignore_blocks, no_terminal_blocks);
+                        no_terminal_blocks);
   };
 
   std::vector<BB*> result;
diff --git a/source/diff/diff.cpp b/source/diff/diff.cpp
index bca31b0..6daed32 100644
--- a/source/diff/diff.cpp
+++ b/source/diff/diff.cpp
@@ -44,8 +44,8 @@
 // different implementations produce identical results.
 using IdGroupMapByName = std::map<std::string, IdGroup>;
 using IdGroupMapByTypeId = std::map<uint32_t, IdGroup>;
-using IdGroupMapByOp = std::map<SpvOp, IdGroup>;
-using IdGroupMapByStorageClass = std::map<SpvStorageClass, IdGroup>;
+using IdGroupMapByOp = std::map<spv::Op, IdGroup>;
+using IdGroupMapByStorageClass = std::map<spv::StorageClass, IdGroup>;
 
 // A set of potential id mappings that haven't been resolved yet.  Any id in src
 // may map in any id in dst.  Note that ids are added in the same order as they
@@ -301,10 +301,10 @@
   // Get various properties from an id.  These Helper functions are passed to
   // `GroupIds` and `GroupIdsAndMatch` below (as the `get_group` argument).
   uint32_t GroupIdsHelperGetTypeId(const IdInstructions& id_to, uint32_t id);
-  SpvStorageClass GroupIdsHelperGetTypePointerStorageClass(
+  spv::StorageClass GroupIdsHelperGetTypePointerStorageClass(
       const IdInstructions& id_to, uint32_t id);
-  SpvOp GroupIdsHelperGetTypePointerTypeOp(const IdInstructions& id_to,
-                                           uint32_t id);
+  spv::Op GroupIdsHelperGetTypePointerTypeOp(const IdInstructions& id_to,
+                                             uint32_t id);
 
   // Given a list of ids, groups them based on some value.  The `get_group`
   // function extracts a piece of information corresponding to each id, and the
@@ -414,8 +414,8 @@
   // Helper functions to retrieve information pertaining to an id
   const opt::Instruction* GetInst(const IdInstructions& id_to, uint32_t id);
   uint32_t GetConstantUint(const IdInstructions& id_to, uint32_t constant_id);
-  SpvExecutionModel GetExecutionModel(const opt::Module* module,
-                                      uint32_t entry_point_id);
+  spv::ExecutionModel GetExecutionModel(const opt::Module* module,
+                                        uint32_t entry_point_id);
   bool HasName(const IdInstructions& id_to, uint32_t id);
   // Get the OpName associated with an id
   std::string GetName(const IdInstructions& id_to, uint32_t id, bool* has_name);
@@ -424,20 +424,21 @@
   // string, and this improves diff between SPIR-V from those tools and others.
   std::string GetSanitizedName(const IdInstructions& id_to, uint32_t id);
   uint32_t GetVarTypeId(const IdInstructions& id_to, uint32_t var_id,
-                        SpvStorageClass* storage_class);
+                        spv::StorageClass* storage_class);
   bool GetDecorationValue(const IdInstructions& id_to, uint32_t id,
-                          SpvDecoration decoration, uint32_t* decoration_value);
+                          spv::Decoration decoration,
+                          uint32_t* decoration_value);
   const opt::Instruction* GetForwardPointerInst(const IdInstructions& id_to,
                                                 uint32_t id);
   bool IsIntType(const IdInstructions& id_to, uint32_t type_id);
   bool IsFloatType(const IdInstructions& id_to, uint32_t type_id);
   bool IsConstantUint(const IdInstructions& id_to, uint32_t id);
   bool IsVariable(const IdInstructions& id_to, uint32_t pointer_id);
-  bool IsOp(const IdInstructions& id_to, uint32_t id, SpvOp opcode);
+  bool IsOp(const IdInstructions& id_to, uint32_t id, spv::Op opcode);
   bool IsPerVertexType(const IdInstructions& id_to, uint32_t type_id);
   bool IsPerVertexVariable(const IdInstructions& id_to, uint32_t type_id);
-  SpvStorageClass GetPerVertexStorageClass(const opt::Module* module,
-                                           uint32_t type_id);
+  spv::StorageClass GetPerVertexStorageClass(const opt::Module* module,
+                                             uint32_t type_id);
   spv_ext_inst_type_t GetExtInstType(const IdInstructions& id_to,
                                      uint32_t set_id);
   spv_number_kind_t GetNumberKind(const IdInstructions& id_to,
@@ -561,19 +562,19 @@
     uint32_t id_operand = 0;
 
     switch (inst.opcode()) {
-      case SpvOpName:
+      case spv::Op::OpName:
         info_map = &name_map_;
         break;
-      case SpvOpMemberName:
+      case spv::Op::OpMemberName:
         info_map = &name_map_;
         break;
-      case SpvOpDecorate:
+      case spv::Op::OpDecorate:
         info_map = &decoration_map_;
         break;
-      case SpvOpMemberDecorate:
+      case spv::Op::OpMemberDecorate:
         info_map = &decoration_map_;
         break;
-      case SpvOpTypeForwardPointer: {
+      case spv::Op::OpTypeForwardPointer: {
         uint32_t id = inst.GetSingleWordOperand(0);
         assert(id != 0);
 
@@ -731,10 +732,10 @@
   // Instead of comparing OpExecutionMode entry point ids as ids, compare them
   // through their corresponding execution model.  This simplifies traversing
   // the sorted list of instructions between src and dst modules.
-  if (a->opcode() == SpvOpExecutionMode) {
-    const SpvExecutionModel src_model =
+  if (a->opcode() == spv::Op::OpExecutionMode) {
+    const spv::ExecutionModel src_model =
         GetExecutionModel(src_inst_module, a->GetSingleWordOperand(0));
-    const SpvExecutionModel dst_model =
+    const spv::ExecutionModel dst_model =
         GetExecutionModel(dst_inst_module, b->GetSingleWordOperand(0));
 
     if (src_model < dst_model) {
@@ -758,9 +759,6 @@
       return 1;
     }
 
-    assert(a_operand.words.size() == 1);
-    assert(b_operand.words.size() == 1);
-
     switch (a_operand.type) {
       case SPV_OPERAND_TYPE_ID:
         // Don't compare ids, there can't be multiple instances of the
@@ -781,6 +779,9 @@
       }
       default:
         // Expect literal values to match.
+        assert(a_operand.words.size() == 1);
+        assert(b_operand.words.size() == 1);
+
         if (a_operand.words[0] < b_operand.words[0]) {
           return -1;
         }
@@ -818,17 +819,17 @@
   return GetInst(id_to, id)->type_id();
 }
 
-SpvStorageClass Differ::GroupIdsHelperGetTypePointerStorageClass(
+spv::StorageClass Differ::GroupIdsHelperGetTypePointerStorageClass(
     const IdInstructions& id_to, uint32_t id) {
   const opt::Instruction* inst = GetInst(id_to, id);
-  assert(inst && inst->opcode() == SpvOpTypePointer);
-  return SpvStorageClass(inst->GetSingleWordInOperand(0));
+  assert(inst && inst->opcode() == spv::Op::OpTypePointer);
+  return spv::StorageClass(inst->GetSingleWordInOperand(0));
 }
 
-SpvOp Differ::GroupIdsHelperGetTypePointerTypeOp(const IdInstructions& id_to,
-                                                 uint32_t id) {
+spv::Op Differ::GroupIdsHelperGetTypePointerTypeOp(const IdInstructions& id_to,
+                                                   uint32_t id) {
   const opt::Instruction* inst = GetInst(id_to, id);
-  assert(inst && inst->opcode() == SpvOpTypePointer);
+  assert(inst && inst->opcode() == spv::Op::OpTypePointer);
 
   const uint32_t type_id = inst->GetSingleWordInOperand(1);
   const opt::Instruction* type_inst = GetInst(id_to, type_id);
@@ -1020,7 +1021,7 @@
   }
   // For external instructions, make sure the set and opcode of the external
   // instruction matches too.
-  if (src_inst->opcode() == SpvOpExtInst) {
+  if (src_inst->opcode() == spv::Op::OpExtInst) {
     if (!DoOperandsMatch(src_inst, dst_inst, 0, 2)) {
       return false;
     }
@@ -1064,26 +1065,26 @@
   }
 
   switch (src_inst->opcode()) {
-    case SpvOpString:
-    case SpvOpSourceExtension:
-    case SpvOpModuleProcessed:
+    case spv::Op::OpString:
+    case spv::Op::OpSourceExtension:
+    case spv::Op::OpModuleProcessed:
       return DoesOperandMatch(src_inst->GetOperand(0), dst_inst->GetOperand(0));
-    case SpvOpSource:
+    case spv::Op::OpSource:
       return DoOperandsMatch(src_inst, dst_inst, 0, 2);
-    case SpvOpSourceContinued:
+    case spv::Op::OpSourceContinued:
       return true;
-    case SpvOpName:
+    case spv::Op::OpName:
       return DoOperandsMatch(src_inst, dst_inst, 0, 1);
-    case SpvOpMemberName:
+    case spv::Op::OpMemberName:
       return DoOperandsMatch(src_inst, dst_inst, 0, 2);
-    case SpvOpDecorate:
+    case spv::Op::OpDecorate:
       return DoOperandsMatch(src_inst, dst_inst, 0, 2);
-    case SpvOpMemberDecorate:
+    case spv::Op::OpMemberDecorate:
       return DoOperandsMatch(src_inst, dst_inst, 0, 3);
-    case SpvOpExtInst:
-    case SpvOpDecorationGroup:
-    case SpvOpGroupDecorate:
-    case SpvOpGroupMemberDecorate:
+    case spv::Op::OpExtInst:
+    case spv::Op::OpDecorationGroup:
+    case spv::Op::OpGroupDecorate:
+    case spv::Op::OpGroupMemberDecorate:
       return false;
     default:
       return false;
@@ -1095,9 +1096,9 @@
   // Variables must match by their built-in decorations.
   uint32_t src_built_in_decoration = 0, dst_built_in_decoration = 0;
   const bool src_is_built_in = GetDecorationValue(
-      src_id_to_, src_id, SpvDecorationBuiltIn, &src_built_in_decoration);
+      src_id_to_, src_id, spv::Decoration::BuiltIn, &src_built_in_decoration);
   const bool dst_is_built_in = GetDecorationValue(
-      dst_id_to_, dst_id, SpvDecorationBuiltIn, &dst_built_in_decoration);
+      dst_id_to_, dst_id, spv::Decoration::BuiltIn, &dst_built_in_decoration);
 
   if (src_is_built_in != dst_is_built_in) {
     return false;
@@ -1107,7 +1108,7 @@
   }
 
   // Check their types and storage classes.
-  SpvStorageClass src_storage_class, dst_storage_class;
+  spv::StorageClass src_storage_class, dst_storage_class;
   const uint32_t src_type_id =
       GetVarTypeId(src_id_to_, src_id, &src_storage_class);
   const uint32_t dst_type_id =
@@ -1127,12 +1128,14 @@
         // Allow one of the two to be Private while the other is Input or
         // Output, this allows matching in/out variables that have been turned
         // global as part of linking two stages (as done in ANGLE).
-        const bool src_is_io = src_storage_class == SpvStorageClassInput ||
-                               src_storage_class == SpvStorageClassOutput;
-        const bool dst_is_io = dst_storage_class == SpvStorageClassInput ||
-                               dst_storage_class == SpvStorageClassOutput;
-        const bool src_is_private = src_storage_class == SpvStorageClassPrivate;
-        const bool dst_is_private = dst_storage_class == SpvStorageClassPrivate;
+        const bool src_is_io = src_storage_class == spv::StorageClass::Input ||
+                               src_storage_class == spv::StorageClass::Output;
+        const bool dst_is_io = dst_storage_class == spv::StorageClass::Input ||
+                               dst_storage_class == spv::StorageClass::Output;
+        const bool src_is_private =
+            src_storage_class == spv::StorageClass::Private;
+        const bool dst_is_private =
+            dst_storage_class == spv::StorageClass::Private;
 
         if (!((src_is_io && dst_is_private) || (src_is_private && dst_is_io))) {
           return false;
@@ -1277,15 +1280,22 @@
   // Otherwise, match them by SpecId.
   uint32_t src_spec_id, dst_spec_id;
 
-  if (GetDecorationValue(src_id_to_, src_id, SpvDecorationSpecId,
+  if (GetDecorationValue(src_id_to_, src_id, spv::Decoration::SpecId,
                          &src_spec_id) &&
-      GetDecorationValue(dst_id_to_, dst_id, SpvDecorationSpecId,
+      GetDecorationValue(dst_id_to_, dst_id, spv::Decoration::SpecId,
                          &dst_spec_id)) {
     return src_spec_id == dst_spec_id;
   }
 
-  // There is no spec id, this is not valid.
-  assert(false && "Unreachable");
+  // There is no SpecId decoration, while not practical, still valid.
+  // SpecConstantOp don't have SpecId and can be matched by operands
+  if (src_inst->opcode() == spv::Op::OpSpecConstantOp) {
+    if (src_inst->NumInOperandWords() == dst_inst->NumInOperandWords()) {
+      return DoOperandsMatch(src_inst, dst_inst, 0,
+                             src_inst->NumInOperandWords());
+    }
+  }
+
   return false;
 }
 
@@ -1320,13 +1330,13 @@
   // built-in decorations.
   uint32_t src_built_in_decoration;
   const bool src_is_built_in = GetDecorationValue(
-      src_id_to_, src_id, SpvDecorationBuiltIn, &src_built_in_decoration);
+      src_id_to_, src_id, spv::Decoration::BuiltIn, &src_built_in_decoration);
 
   if (src_is_built_in && AreVariablesMatchable(src_id, dst_id, flexibility)) {
     return true;
   }
 
-  SpvStorageClass src_storage_class, dst_storage_class;
+  spv::StorageClass src_storage_class, dst_storage_class;
   GetVarTypeId(src_id_to_, src_id, &src_storage_class);
   GetVarTypeId(dst_id_to_, dst_id, &dst_storage_class);
 
@@ -1341,13 +1351,13 @@
     uint32_t src_binding = 0, dst_binding = 0;
 
     const bool src_has_set = GetDecorationValue(
-        src_id_to_, src_id, SpvDecorationDescriptorSet, &src_set);
+        src_id_to_, src_id, spv::Decoration::DescriptorSet, &src_set);
     const bool dst_has_set = GetDecorationValue(
-        dst_id_to_, dst_id, SpvDecorationDescriptorSet, &dst_set);
-    const bool src_has_binding =
-        GetDecorationValue(src_id_to_, src_id, SpvDecorationBinding, &src_set);
-    const bool dst_has_binding =
-        GetDecorationValue(dst_id_to_, dst_id, SpvDecorationBinding, &dst_set);
+        dst_id_to_, dst_id, spv::Decoration::DescriptorSet, &dst_set);
+    const bool src_has_binding = GetDecorationValue(
+        src_id_to_, src_id, spv::Decoration::Binding, &src_set);
+    const bool dst_has_binding = GetDecorationValue(
+        dst_id_to_, dst_id, spv::Decoration::Binding, &dst_set);
 
     if (src_has_set && dst_has_set && src_has_binding && dst_has_binding) {
       return src_set == dst_set && src_binding == dst_binding;
@@ -1360,9 +1370,9 @@
     uint32_t src_location, dst_location;
 
     const bool src_has_location = GetDecorationValue(
-        src_id_to_, src_id, SpvDecorationLocation, &src_location);
+        src_id_to_, src_id, spv::Decoration::Location, &src_location);
     const bool dst_has_location = GetDecorationValue(
-        dst_id_to_, dst_id, SpvDecorationLocation, &dst_location);
+        dst_id_to_, dst_id, spv::Decoration::Location, &dst_location);
 
     if (src_has_location && dst_has_location) {
       return src_location == dst_location;
@@ -1377,25 +1387,25 @@
   // For gl_PerVertex, find the type pointer of this type (array) and make sure
   // the storage classes of src and dst match; geometry and tessellation shaders
   // have two instances of gl_PerVertex.
-  SpvStorageClass src_storage_class =
+  spv::StorageClass src_storage_class =
       GetPerVertexStorageClass(src_, src_type_id);
-  SpvStorageClass dst_storage_class =
+  spv::StorageClass dst_storage_class =
       GetPerVertexStorageClass(dst_, dst_type_id);
 
-  assert(src_storage_class == SpvStorageClassInput ||
-         src_storage_class == SpvStorageClassOutput);
-  assert(dst_storage_class == SpvStorageClassInput ||
-         dst_storage_class == SpvStorageClassOutput);
+  assert(src_storage_class == spv::StorageClass::Input ||
+         src_storage_class == spv::StorageClass::Output);
+  assert(dst_storage_class == spv::StorageClass::Input ||
+         dst_storage_class == spv::StorageClass::Output);
 
   return src_storage_class == dst_storage_class;
 }
 
 bool Differ::MatchPerVertexVariable(const opt::Instruction* src_inst,
                                     const opt::Instruction* dst_inst) {
-  SpvStorageClass src_storage_class =
-      SpvStorageClass(src_inst->GetSingleWordInOperand(0));
-  SpvStorageClass dst_storage_class =
-      SpvStorageClass(dst_inst->GetSingleWordInOperand(0));
+  spv::StorageClass src_storage_class =
+      spv::StorageClass(src_inst->GetSingleWordInOperand(0));
+  spv::StorageClass dst_storage_class =
+      spv::StorageClass(dst_inst->GetSingleWordInOperand(0));
 
   return src_storage_class == dst_storage_class;
 }
@@ -1472,7 +1482,7 @@
   InstructionList body;
   function.WhileEachInst(
       [&body](const opt::Instruction* inst) {
-        if (inst->opcode() == SpvOpLabel) {
+        if (inst->opcode() == spv::Op::OpLabel) {
           return false;
         }
         body.push_back(inst);
@@ -1687,12 +1697,12 @@
     default:
       // TODO: match functions based on OpFunctionCall?
       break;
-    case SpvOpAccessChain:
-    case SpvOpInBoundsAccessChain:
-    case SpvOpPtrAccessChain:
-    case SpvOpInBoundsPtrAccessChain:
-    case SpvOpLoad:
-    case SpvOpStore:
+    case spv::Op::OpAccessChain:
+    case spv::Op::OpInBoundsAccessChain:
+    case spv::Op::OpPtrAccessChain:
+    case spv::Op::OpInBoundsPtrAccessChain:
+    case spv::Op::OpLoad:
+    case spv::Op::OpStore:
       const uint32_t src_pointer_id = src_inst->GetSingleWordInOperand(0);
       const uint32_t dst_pointer_id = dst_inst->GetSingleWordInOperand(0);
       if (IsVariable(src_id_to_, src_pointer_id) &&
@@ -1720,23 +1730,24 @@
 uint32_t Differ::GetConstantUint(const IdInstructions& id_to,
                                  uint32_t constant_id) {
   const opt::Instruction* constant_inst = GetInst(id_to, constant_id);
-  assert(constant_inst->opcode() == SpvOpConstant);
-  assert(GetInst(id_to, constant_inst->type_id())->opcode() == SpvOpTypeInt);
+  assert(constant_inst->opcode() == spv::Op::OpConstant);
+  assert(GetInst(id_to, constant_inst->type_id())->opcode() ==
+         spv::Op::OpTypeInt);
 
   return constant_inst->GetSingleWordInOperand(0);
 }
 
-SpvExecutionModel Differ::GetExecutionModel(const opt::Module* module,
-                                            uint32_t entry_point_id) {
+spv::ExecutionModel Differ::GetExecutionModel(const opt::Module* module,
+                                              uint32_t entry_point_id) {
   for (const opt::Instruction& inst : module->entry_points()) {
-    assert(inst.opcode() == SpvOpEntryPoint);
+    assert(inst.opcode() == spv::Op::OpEntryPoint);
     if (inst.GetSingleWordOperand(1) == entry_point_id) {
-      return SpvExecutionModel(inst.GetSingleWordOperand(0));
+      return spv::ExecutionModel(inst.GetSingleWordOperand(0));
     }
   }
 
   assert(false && "Unreachable");
-  return SpvExecutionModel(0xFFF);
+  return spv::ExecutionModel(0xFFF);
 }
 
 bool Differ::HasName(const IdInstructions& id_to, uint32_t id) {
@@ -1744,7 +1755,7 @@
   assert(id < id_to.name_map_.size());
 
   for (const opt::Instruction* inst : id_to.name_map_[id]) {
-    if (inst->opcode() == SpvOpName) {
+    if (inst->opcode() == spv::Op::OpName) {
       return true;
     }
   }
@@ -1758,7 +1769,7 @@
   assert(id < id_to.name_map_.size());
 
   for (const opt::Instruction* inst : id_to.name_map_[id]) {
-    if (inst->opcode() == SpvOpName) {
+    if (inst->opcode() == spv::Op::OpName) {
       *has_name = true;
       return inst->GetOperand(1).AsString();
     }
@@ -1781,11 +1792,11 @@
 }
 
 uint32_t Differ::GetVarTypeId(const IdInstructions& id_to, uint32_t var_id,
-                              SpvStorageClass* storage_class) {
+                              spv::StorageClass* storage_class) {
   const opt::Instruction* var_inst = GetInst(id_to, var_id);
-  assert(var_inst->opcode() == SpvOpVariable);
+  assert(var_inst->opcode() == spv::Op::OpVariable);
 
-  *storage_class = SpvStorageClass(var_inst->GetSingleWordInOperand(0));
+  *storage_class = spv::StorageClass(var_inst->GetSingleWordInOperand(0));
 
   // Get the type pointer from the variable.
   const uint32_t type_pointer_id = var_inst->type_id();
@@ -1796,15 +1807,15 @@
 }
 
 bool Differ::GetDecorationValue(const IdInstructions& id_to, uint32_t id,
-                                SpvDecoration decoration,
+                                spv::Decoration decoration,
                                 uint32_t* decoration_value) {
   assert(id != 0);
   assert(id < id_to.decoration_map_.size());
 
   for (const opt::Instruction* inst : id_to.decoration_map_[id]) {
-    if (inst->opcode() == SpvOpDecorate &&
+    if (inst->opcode() == spv::Op::OpDecorate &&
         inst->GetSingleWordOperand(0) == id &&
-        inst->GetSingleWordOperand(1) == decoration) {
+        spv::Decoration(inst->GetSingleWordOperand(1)) == decoration) {
       *decoration_value = inst->GetSingleWordOperand(2);
       return true;
     }
@@ -1821,28 +1832,28 @@
 }
 
 bool Differ::IsIntType(const IdInstructions& id_to, uint32_t type_id) {
-  return IsOp(id_to, type_id, SpvOpTypeInt);
+  return IsOp(id_to, type_id, spv::Op::OpTypeInt);
 }
 
 bool Differ::IsFloatType(const IdInstructions& id_to, uint32_t type_id) {
-  return IsOp(id_to, type_id, SpvOpTypeFloat);
+  return IsOp(id_to, type_id, spv::Op::OpTypeFloat);
 }
 
 bool Differ::IsConstantUint(const IdInstructions& id_to, uint32_t id) {
   const opt::Instruction* constant_inst = GetInst(id_to, id);
-  if (constant_inst->opcode() != SpvOpConstant) {
+  if (constant_inst->opcode() != spv::Op::OpConstant) {
     return false;
   }
 
   const opt::Instruction* type_inst = GetInst(id_to, constant_inst->type_id());
-  return type_inst->opcode() == SpvOpTypeInt;
+  return type_inst->opcode() == spv::Op::OpTypeInt;
 }
 
 bool Differ::IsVariable(const IdInstructions& id_to, uint32_t pointer_id) {
-  return IsOp(id_to, pointer_id, SpvOpVariable);
+  return IsOp(id_to, pointer_id, spv::Op::OpVariable);
 }
 
-bool Differ::IsOp(const IdInstructions& id_to, uint32_t id, SpvOp op) {
+bool Differ::IsOp(const IdInstructions& id_to, uint32_t id, spv::Op op) {
   return GetInst(id_to, id)->opcode() == op;
 }
 
@@ -1851,17 +1862,18 @@
   assert(type_id < id_to.decoration_map_.size());
 
   for (const opt::Instruction* inst : id_to.decoration_map_[type_id]) {
-    if (inst->opcode() == SpvOpMemberDecorate &&
+    if (inst->opcode() == spv::Op::OpMemberDecorate &&
         inst->GetSingleWordOperand(0) == type_id &&
-        inst->GetSingleWordOperand(2) == SpvDecorationBuiltIn) {
-      SpvBuiltIn built_in = SpvBuiltIn(inst->GetSingleWordOperand(3));
+        spv::Decoration(inst->GetSingleWordOperand(2)) ==
+            spv::Decoration::BuiltIn) {
+      spv::BuiltIn built_in = spv::BuiltIn(inst->GetSingleWordOperand(3));
 
       // Only gl_PerVertex can have, and it can only have, the following
       // built-in decorations.
-      return built_in == SpvBuiltInPosition ||
-             built_in == SpvBuiltInPointSize ||
-             built_in == SpvBuiltInClipDistance ||
-             built_in == SpvBuiltInCullDistance;
+      return built_in == spv::BuiltIn::Position ||
+             built_in == spv::BuiltIn::PointSize ||
+             built_in == spv::BuiltIn::ClipDistance ||
+             built_in == spv::BuiltIn::CullDistance;
     }
   }
 
@@ -1870,12 +1882,12 @@
 
 bool Differ::IsPerVertexVariable(const IdInstructions& id_to, uint32_t var_id) {
   // Get the type from the type pointer.
-  SpvStorageClass storage_class;
+  spv::StorageClass storage_class;
   uint32_t type_id = GetVarTypeId(id_to, var_id, &storage_class);
   const opt::Instruction* type_inst = GetInst(id_to, type_id);
 
   // If array, get the element type.
-  if (type_inst->opcode() == SpvOpTypeArray) {
+  if (type_inst->opcode() == spv::Op::OpTypeArray) {
     type_id = type_inst->GetSingleWordInOperand(0);
   }
 
@@ -1883,21 +1895,21 @@
   return IsPerVertexType(id_to, type_id);
 }
 
-SpvStorageClass Differ::GetPerVertexStorageClass(const opt::Module* module,
-                                                 uint32_t type_id) {
+spv::StorageClass Differ::GetPerVertexStorageClass(const opt::Module* module,
+                                                   uint32_t type_id) {
   for (const opt::Instruction& inst : module->types_values()) {
     switch (inst.opcode()) {
-      case SpvOpTypeArray:
+      case spv::Op::OpTypeArray:
         // The gl_PerVertex instance could be an array, look for a variable of
         // the array type instead.
         if (inst.GetSingleWordInOperand(0) == type_id) {
           type_id = inst.result_id();
         }
         break;
-      case SpvOpTypePointer:
+      case spv::Op::OpTypePointer:
         // Find the storage class of the pointer to this type.
         if (inst.GetSingleWordInOperand(1) == type_id) {
-          return SpvStorageClass(inst.GetSingleWordInOperand(0));
+          return spv::StorageClass(inst.GetSingleWordInOperand(0));
         }
         break;
       default:
@@ -1908,7 +1920,7 @@
   // gl_PerVertex is declared, but is unused.  Return either of Input or Output
   // classes just so it matches one in the other module.  This should be highly
   // unlikely, perhaps except for ancient GS-used-to-emulate-CS scenarios.
-  return SpvStorageClassOutput;
+  return spv::StorageClass::Output;
 }
 
 spv_ext_inst_type_t Differ::GetExtInstType(const IdInstructions& id_to,
@@ -1934,9 +1946,9 @@
     case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER:
     case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER:
       switch (inst.opcode()) {
-        case SpvOpSwitch:
-        case SpvOpConstant:
-        case SpvOpSpecConstant:
+        case spv::Op::OpSwitch:
+        case spv::Op::OpConstant:
+        case spv::Op::OpSpecConstant:
           // Same kind of number as the selector (OpSwitch) or the type
           // (Op*Constant).
           return GetTypeNumberKind(id_to, inst.GetSingleWordOperand(0),
@@ -1962,12 +1974,12 @@
   }
 
   switch (type_inst->opcode()) {
-    case SpvOpTypeInt:
+    case spv::Op::OpTypeInt:
       *number_bit_width = type_inst->GetSingleWordOperand(1);
       return type_inst->GetSingleWordOperand(2) == 0 ? SPV_NUMBER_UNSIGNED_INT
                                                      : SPV_NUMBER_SIGNED_INT;
       break;
-    case SpvOpTypeFloat:
+    case spv::Op::OpTypeFloat:
       *number_bit_width = type_inst->GetSingleWordOperand(1);
       return SPV_NUMBER_FLOATING;
     default:
@@ -2085,7 +2097,7 @@
     return inst.GetSingleWordOperand(0);
   };
   auto accept_type_forward_pointer_ops = [](const opt::Instruction& inst) {
-    return inst.opcode() == SpvOpTypeForwardPointer;
+    return inst.opcode() == spv::Op::OpTypeForwardPointer;
   };
 
   PoolPotentialIds(src_->types_values(), potential_id_map.src_ids, true,
@@ -2109,17 +2121,17 @@
   //     - If leftover is unique, match
 
   // Group forwarded pointers by storage class first and loop over them.
-  GroupIdsAndMatch<SpvStorageClass>(
-      potential_id_map.src_ids, potential_id_map.dst_ids, SpvStorageClassMax,
-      &Differ::GroupIdsHelperGetTypePointerStorageClass,
+  GroupIdsAndMatch<spv::StorageClass>(
+      potential_id_map.src_ids, potential_id_map.dst_ids,
+      spv::StorageClass::Max, &Differ::GroupIdsHelperGetTypePointerStorageClass,
       [this](const IdGroup& src_group_by_storage_class,
              const IdGroup& dst_group_by_storage_class) {
 
         // Group them further by the type they are pointing to and loop over
         // them.
-        GroupIdsAndMatch<SpvOp>(
-            src_group_by_storage_class, dst_group_by_storage_class, SpvOpMax,
-            &Differ::GroupIdsHelperGetTypePointerTypeOp,
+        GroupIdsAndMatch<spv::Op>(
+            src_group_by_storage_class, dst_group_by_storage_class,
+            spv::Op::Max, &Differ::GroupIdsHelperGetTypePointerTypeOp,
             [this](const IdGroup& src_group_by_type_op,
                    const IdGroup& dst_group_by_type_op) {
 
@@ -2175,8 +2187,8 @@
     MatchIds(potential_id_map, [this, flexibility](
                                    const opt::Instruction* src_inst,
                                    const opt::Instruction* dst_inst) {
-      const SpvOp src_op = src_inst->opcode();
-      const SpvOp dst_op = dst_inst->opcode();
+      const spv::Op src_op = src_inst->opcode();
+      const spv::Op dst_op = dst_inst->opcode();
 
       // Don't match if the opcode is not the same.
       if (src_op != dst_op) {
@@ -2184,26 +2196,26 @@
       }
 
       switch (src_op) {
-        case SpvOpTypeVoid:
-        case SpvOpTypeBool:
-        case SpvOpTypeSampler:
+        case spv::Op::OpTypeVoid:
+        case spv::Op::OpTypeBool:
+        case spv::Op::OpTypeSampler:
           // void, bool and sampler are unique, match them.
           return true;
-        case SpvOpTypeInt:
-        case SpvOpTypeFloat:
-        case SpvOpTypeVector:
-        case SpvOpTypeMatrix:
-        case SpvOpTypeSampledImage:
-        case SpvOpTypeRuntimeArray:
-        case SpvOpTypePointer:
+        case spv::Op::OpTypeInt:
+        case spv::Op::OpTypeFloat:
+        case spv::Op::OpTypeVector:
+        case spv::Op::OpTypeMatrix:
+        case spv::Op::OpTypeSampledImage:
+        case spv::Op::OpTypeRuntimeArray:
+        case spv::Op::OpTypePointer:
           // Match these instructions when all operands match.
           assert(src_inst->NumInOperandWords() ==
                  dst_inst->NumInOperandWords());
           return DoOperandsMatch(src_inst, dst_inst, 0,
                                  src_inst->NumInOperandWords());
 
-        case SpvOpTypeFunction:
-        case SpvOpTypeImage:
+        case spv::Op::OpTypeFunction:
+        case spv::Op::OpTypeImage:
           // Match function types only if they have the same number of operands,
           // and they all match.
           // Match image types similarly, expecting the optional final parameter
@@ -2214,7 +2226,7 @@
           return DoOperandsMatch(src_inst, dst_inst, 0,
                                  src_inst->NumInOperandWords());
 
-        case SpvOpTypeArray:
+        case spv::Op::OpTypeArray:
           // Match arrays only if the element type and length match.  The length
           // is an id of a constant, so the actual constant it's defining is
           // compared instead.
@@ -2231,7 +2243,7 @@
           // example if a spec contant is used).
           return DoOperandsMatch(src_inst, dst_inst, 1, 1);
 
-        case SpvOpTypeStruct:
+        case spv::Op::OpTypeStruct:
           return MatchOpTypeStruct(src_inst, dst_inst, flexibility);
 
         default:
@@ -2263,8 +2275,8 @@
     MatchIds(potential_id_map, [this, flexibility](
                                    const opt::Instruction* src_inst,
                                    const opt::Instruction* dst_inst) {
-      const SpvOp src_op = src_inst->opcode();
-      const SpvOp dst_op = dst_inst->opcode();
+      const spv::Op src_op = src_inst->opcode();
+      const spv::Op dst_op = dst_inst->opcode();
 
       // Don't match if the opcode is not the same.
       if (src_op != dst_op) {
@@ -2272,14 +2284,14 @@
       }
 
       switch (src_op) {
-        case SpvOpConstantTrue:
-        case SpvOpConstantFalse:
+        case spv::Op::OpConstantTrue:
+        case spv::Op::OpConstantFalse:
           // true and false are unique, match them.
           return true;
-        case SpvOpConstant:
+        case spv::Op::OpConstant:
           return MatchOpConstant(src_inst, dst_inst, flexibility);
-        case SpvOpConstantComposite:
-        case SpvOpSpecConstantComposite:
+        case spv::Op::OpConstantComposite:
+        case spv::Op::OpSpecConstantComposite:
           // Composite constants must match in type and value.
           //
           // TODO: match OpConstantNull with OpConstantComposite with all zeros
@@ -2292,7 +2304,7 @@
                                   dst_inst->GetOperand(0)) &&
                  DoOperandsMatch(src_inst, dst_inst, 0,
                                  src_inst->NumInOperandWords());
-        case SpvOpConstantSampler:
+        case spv::Op::OpConstantSampler:
           // Match sampler constants exactly.
           // TODO: Allow flexibility in parameters to better diff shaders where
           // the sampler param has changed.
@@ -2300,15 +2312,15 @@
                  dst_inst->NumInOperandWords());
           return DoOperandsMatch(src_inst, dst_inst, 0,
                                  src_inst->NumInOperandWords());
-        case SpvOpConstantNull:
+        case spv::Op::OpConstantNull:
           // Match null constants as long as the type matches.
           return DoesOperandMatch(src_inst->GetOperand(0),
                                   dst_inst->GetOperand(0));
 
-        case SpvOpSpecConstantTrue:
-        case SpvOpSpecConstantFalse:
-        case SpvOpSpecConstant:
-        case SpvOpSpecConstantOp:
+        case spv::Op::OpSpecConstantTrue:
+        case spv::Op::OpSpecConstantFalse:
+        case spv::Op::OpSpecConstant:
+        case spv::Op::OpSpecConstantOp:
           // Match spec constants by name if available, then by the SpecId
           // decoration.
           return MatchOpSpecConstant(src_inst, dst_inst);
@@ -2327,7 +2339,7 @@
     return inst.result_id();
   };
   auto accept_type_ops = [](const opt::Instruction& inst) {
-    return inst.opcode() == SpvOpVariable;
+    return inst.opcode() == spv::Op::OpVariable;
   };
 
   PoolPotentialIds(src_->types_values(), potential_id_map.src_ids, true,
@@ -2343,8 +2355,8 @@
     MatchIds(potential_id_map,
              [this, flexibility](const opt::Instruction* src_inst,
                                  const opt::Instruction* dst_inst) {
-               assert(src_inst->opcode() == SpvOpVariable);
-               assert(dst_inst->opcode() == SpvOpVariable);
+               assert(src_inst->opcode() == spv::Op::OpVariable);
+               assert(dst_inst->opcode() == spv::Op::OpVariable);
 
                return MatchOpVariable(src_inst, dst_inst, flexibility);
              });
@@ -2590,7 +2602,7 @@
   parsed_inst->num_words = static_cast<uint16_t>(inst_binary.size());
   parsed_inst->opcode = static_cast<uint16_t>(inst.opcode());
   parsed_inst->ext_inst_type =
-      inst.opcode() == SpvOpExtInst
+      inst.opcode() == spv::Op::OpExtInst
           ? GetExtInstType(id_to, original_inst.GetSingleWordInOperand(0))
           : SPV_EXT_INST_TYPE_NONE;
   parsed_inst->type_id =
diff --git a/source/disassemble.cpp b/source/disassemble.cpp
index 1d61b9f..f862efd 100644
--- a/source/disassemble.cpp
+++ b/source/disassemble.cpp
@@ -244,7 +244,7 @@
 
 void InstructionDisassembler::EmitInstruction(
     const spv_parsed_instruction_t& inst, size_t inst_byte_offset) {
-  auto opcode = static_cast<SpvOp>(inst.opcode);
+  auto opcode = static_cast<spv::Op>(inst.opcode);
 
   if (inst.result_id) {
     SetBlue();
@@ -268,7 +268,7 @@
     EmitOperand(inst, i);
   }
 
-  if (comment_ && opcode == SpvOpName) {
+  if (comment_ && opcode == spv::Op::OpName) {
     const spv_parsed_operand_t& operand = inst.operands[0];
     const uint32_t word = inst.words[operand.offset];
     stream_ << "  ; id %" << word;
@@ -290,8 +290,8 @@
 void InstructionDisassembler::EmitSectionComment(
     const spv_parsed_instruction_t& inst, bool& inserted_decoration_space,
     bool& inserted_debug_space, bool& inserted_type_space) {
-  auto opcode = static_cast<SpvOp>(inst.opcode);
-  if (comment_ && opcode == SpvOpFunction) {
+  auto opcode = static_cast<spv::Op>(inst.opcode);
+  if (comment_ && opcode == spv::Op::OpFunction) {
     stream_ << std::endl;
     stream_ << std::string(indent_, ' ');
     stream_ << "; Function " << name_mapper_(inst.result_id) << std::endl;
@@ -351,7 +351,7 @@
     } break;
     case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: {
       spv_opcode_desc opcode_desc;
-      if (grammar_.lookupOpcode(SpvOp(word), &opcode_desc))
+      if (grammar_.lookupOpcode(spv::Op(word), &opcode_desc))
         assert(false && "should have caught this earlier");
       SetRed();
       stream_ << opcode_desc->name;
diff --git a/source/enum_set.h b/source/enum_set.h
index d4d31e3..28ee5fe 100644
--- a/source/enum_set.h
+++ b/source/enum_set.h
@@ -200,8 +200,8 @@
   std::unique_ptr<OverflowSetType> overflow_ = {};
 };
 
-// A set of SpvCapability, optimized for small capability values.
-using CapabilitySet = EnumSet<SpvCapability>;
+// A set of spv::Capability, optimized for small capability values.
+using CapabilitySet = EnumSet<spv::Capability>;
 
 }  // namespace spvtools
 
diff --git a/source/enum_string_mapping.h b/source/enum_string_mapping.h
index af8f56b..b136584 100644
--- a/source/enum_string_mapping.h
+++ b/source/enum_string_mapping.h
@@ -29,7 +29,7 @@
 const char* ExtensionToString(Extension extension);
 
 // Returns text string corresponding to |capability|.
-const char* CapabilityToString(SpvCapability capability);
+const char* CapabilityToString(spv::Capability capability);
 
 }  // namespace spvtools
 
diff --git a/source/extensions.cpp b/source/extensions.cpp
index 049a3ad..ebf6bec 100644
--- a/source/extensions.cpp
+++ b/source/extensions.cpp
@@ -24,7 +24,9 @@
 namespace spvtools {
 
 std::string GetExtensionString(const spv_parsed_instruction_t* inst) {
-  if (inst->opcode != SpvOpExtension) return "ERROR_not_op_extension";
+  if (inst->opcode != static_cast<uint16_t>(spv::Op::OpExtension)) {
+    return "ERROR_not_op_extension";
+  }
 
   assert(inst->num_operands == 1);
 
diff --git a/source/fuzz/added_function_reducer.cpp b/source/fuzz/added_function_reducer.cpp
index e7cb027..95cf9d6 100644
--- a/source/fuzz/added_function_reducer.cpp
+++ b/source/fuzz/added_function_reducer.cpp
@@ -130,7 +130,7 @@
                   binary_under_reduction.size());
   assert(ir_context != nullptr && "The binary should be parsable.");
   for (auto& type_or_value : ir_context->module()->types_values()) {
-    if (type_or_value.opcode() != SpvOpVariable) {
+    if (type_or_value.opcode() != spv::Op::OpVariable) {
       continue;
     }
     if (irrelevant_pointee_global_variables.count(type_or_value.result_id())) {
@@ -202,7 +202,7 @@
   auto* ir_context = replay_result.transformed_module.get();
 
   for (auto& type_or_value : ir_context->module()->types_values()) {
-    if (type_or_value.opcode() != SpvOpVariable) {
+    if (type_or_value.opcode() != spv::Op::OpVariable) {
       continue;
     }
     if (replay_result.transformation_context->GetFactManager()
diff --git a/source/fuzz/call_graph.cpp b/source/fuzz/call_graph.cpp
index c52bc34..d61a5f8 100644
--- a/source/fuzz/call_graph.cpp
+++ b/source/fuzz/call_graph.cpp
@@ -54,7 +54,7 @@
     // Consider every function call instruction in every block.
     for (auto& block : function) {
       for (auto& instruction : block) {
-        if (instruction.opcode() != SpvOpFunctionCall) {
+        if (instruction.opcode() != spv::Op::OpFunctionCall) {
           continue;
         }
         // Get the id of the function being called.
diff --git a/source/fuzz/fact_manager/constant_uniform_facts.cpp b/source/fuzz/fact_manager/constant_uniform_facts.cpp
index a629c0d..461859b 100644
--- a/source/fuzz/fact_manager/constant_uniform_facts.cpp
+++ b/source/fuzz/fact_manager/constant_uniform_facts.cpp
@@ -63,7 +63,7 @@
 bool ConstantUniformFacts::DataMatches(
     const opt::Instruction& constant_instruction,
     const protobufs::FactConstantUniform& constant_uniform_fact) {
-  assert(constant_instruction.opcode() == SpvOpConstant);
+  assert(constant_instruction.opcode() == spv::Op::OpConstant);
   std::vector<uint32_t> data_in_constant;
   for (uint32_t i = 0; i < constant_instruction.NumInOperands(); i++) {
     data_in_constant.push_back(constant_instruction.GetSingleWordInOperand(i));
@@ -95,7 +95,7 @@
     uint32_t constant_id) const {
   std::vector<protobufs::UniformBufferElementDescriptor> result;
   auto constant_inst = ir_context_->get_def_use_mgr()->GetDef(constant_id);
-  assert(constant_inst->opcode() == SpvOpConstant &&
+  assert(constant_inst->opcode() == spv::Op::OpConstant &&
          "The given id must be that of a constant");
   auto type_id = constant_inst->type_id();
   for (auto& fact_and_type_id : facts_and_type_ids_) {
@@ -175,8 +175,9 @@
     return false;
   }
 
-  assert(SpvOpVariable == uniform_variable->opcode());
-  assert(SpvStorageClassUniform == uniform_variable->GetSingleWordInOperand(0));
+  assert(spv::Op::OpVariable == uniform_variable->opcode());
+  assert(spv::StorageClass::Uniform ==
+         spv::StorageClass(uniform_variable->GetSingleWordInOperand(0)));
 
   auto should_be_uniform_pointer_type =
       ir_context_->get_type_mgr()->GetType(uniform_variable->type_id());
@@ -184,7 +185,7 @@
     return false;
   }
   if (should_be_uniform_pointer_type->AsPointer()->storage_class() !=
-      SpvStorageClassUniform) {
+      spv::StorageClass::Uniform) {
     return false;
   }
   auto should_be_uniform_pointer_instruction =
diff --git a/source/fuzz/fact_manager/data_synonym_and_id_equation_facts.cpp b/source/fuzz/fact_manager/data_synonym_and_id_equation_facts.cpp
index a2c1f2c..b43b8ed 100644
--- a/source/fuzz/fact_manager/data_synonym_and_id_equation_facts.cpp
+++ b/source/fuzz/fact_manager/data_synonym_and_id_equation_facts.cpp
@@ -23,7 +23,7 @@
 size_t DataSynonymAndIdEquationFacts::OperationHash::operator()(
     const Operation& operation) const {
   std::u32string hash;
-  hash.push_back(operation.opcode);
+  hash.push_back(uint32_t(operation.opcode));
   for (auto operand : operation.operands) {
     hash.push_back(static_cast<uint32_t>(DataDescriptorHash()(operand)));
   }
@@ -104,7 +104,8 @@
   }
 
   // Now add the fact.
-  AddEquationFactRecursive(lhs_dd, static_cast<SpvOp>(fact.opcode()), rhs_dds);
+  AddEquationFactRecursive(lhs_dd, static_cast<spv::Op>(fact.opcode()),
+                           rhs_dds);
   return true;
 }
 
@@ -119,7 +120,7 @@
 }
 
 void DataSynonymAndIdEquationFacts::AddEquationFactRecursive(
-    const protobufs::DataDescriptor& lhs_dd, SpvOp opcode,
+    const protobufs::DataDescriptor& lhs_dd, spv::Op opcode,
     const std::vector<const protobufs::DataDescriptor*>& rhs_dds) {
   assert(synonymous_.Exists(lhs_dd) &&
          "The LHS must be known to the equivalence relation.");
@@ -155,21 +156,21 @@
   // Now try to work out corollaries implied by the new equation and existing
   // facts.
   switch (opcode) {
-    case SpvOpConvertSToF:
-    case SpvOpConvertUToF:
+    case spv::Op::OpConvertSToF:
+    case spv::Op::OpConvertUToF:
       ComputeConversionDataSynonymFacts(*rhs_dds[0]);
       break;
-    case SpvOpBitcast: {
+    case spv::Op::OpBitcast: {
       assert(DataDescriptorsAreWellFormedAndComparable(lhs_dd, *rhs_dds[0]) &&
              "Operands of OpBitcast equation fact must have compatible types");
       if (!synonymous_.IsEquivalent(lhs_dd, *rhs_dds[0])) {
         AddDataSynonymFactRecursive(lhs_dd, *rhs_dds[0]);
       }
     } break;
-    case SpvOpIAdd: {
+    case spv::Op::OpIAdd: {
       // Equation form: "a = b + c"
       for (const auto& equation : GetEquations(rhs_dds[0])) {
-        if (equation.opcode == SpvOpISub) {
+        if (equation.opcode == spv::Op::OpISub) {
           // Equation form: "a = (d - e) + c"
           if (synonymous_.IsEquivalent(*equation.operands[1], *rhs_dds[1])) {
             // Equation form: "a = (d - c) + c"
@@ -179,7 +180,7 @@
         }
       }
       for (const auto& equation : GetEquations(rhs_dds[1])) {
-        if (equation.opcode == SpvOpISub) {
+        if (equation.opcode == spv::Op::OpISub) {
           // Equation form: "a = b + (d - e)"
           if (synonymous_.IsEquivalent(*equation.operands[1], *rhs_dds[0])) {
             // Equation form: "a = b + (d - b)"
@@ -190,10 +191,10 @@
       }
       break;
     }
-    case SpvOpISub: {
+    case spv::Op::OpISub: {
       // Equation form: "a = b - c"
       for (const auto& equation : GetEquations(rhs_dds[0])) {
-        if (equation.opcode == SpvOpIAdd) {
+        if (equation.opcode == spv::Op::OpIAdd) {
           // Equation form: "a = (d + e) - c"
           if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[1])) {
             // Equation form: "a = (c + e) - c"
@@ -207,34 +208,34 @@
           }
         }
 
-        if (equation.opcode == SpvOpISub) {
+        if (equation.opcode == spv::Op::OpISub) {
           // Equation form: "a = (d - e) - c"
           if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[1])) {
             // Equation form: "a = (c - e) - c"
             // We can thus infer "a = -e"
-            AddEquationFactRecursive(lhs_dd, SpvOpSNegate,
+            AddEquationFactRecursive(lhs_dd, spv::Op::OpSNegate,
                                      {equation.operands[1]});
           }
         }
       }
 
       for (const auto& equation : GetEquations(rhs_dds[1])) {
-        if (equation.opcode == SpvOpIAdd) {
+        if (equation.opcode == spv::Op::OpIAdd) {
           // Equation form: "a = b - (d + e)"
           if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[0])) {
             // Equation form: "a = b - (b + e)"
             // We can thus infer "a = -e"
-            AddEquationFactRecursive(lhs_dd, SpvOpSNegate,
+            AddEquationFactRecursive(lhs_dd, spv::Op::OpSNegate,
                                      {equation.operands[1]});
           }
           if (synonymous_.IsEquivalent(*equation.operands[1], *rhs_dds[0])) {
             // Equation form: "a = b - (d + b)"
             // We can thus infer "a = -d"
-            AddEquationFactRecursive(lhs_dd, SpvOpSNegate,
+            AddEquationFactRecursive(lhs_dd, spv::Op::OpSNegate,
                                      {equation.operands[0]});
           }
         }
-        if (equation.opcode == SpvOpISub) {
+        if (equation.opcode == spv::Op::OpISub) {
           // Equation form: "a = b - (d - e)"
           if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[0])) {
             // Equation form: "a = b - (b - e)"
@@ -245,8 +246,8 @@
       }
       break;
     }
-    case SpvOpLogicalNot:
-    case SpvOpSNegate: {
+    case spv::Op::OpLogicalNot:
+    case spv::Op::OpSNegate: {
       // Equation form: "a = !b" or "a = -b"
       for (const auto& equation : GetEquations(rhs_dds[0])) {
         if (equation.opcode == opcode) {
@@ -321,9 +322,9 @@
 
       for (const auto& equation : fact.second) {
         if (synonymous_.IsEquivalent(*equation.operands[0], dd)) {
-          if (equation.opcode == SpvOpConvertSToF) {
+          if (equation.opcode == spv::Op::OpConvertSToF) {
             convert_s_to_f_lhs.push_back(*dd_it);
-          } else if (equation.opcode == SpvOpConvertUToF) {
+          } else if (equation.opcode == spv::Op::OpConvertUToF) {
             convert_u_to_f_lhs.push_back(*dd_it);
           }
         }
@@ -808,9 +809,9 @@
   }
   // Neither end type is allowed to be void.
   if (ir_context_->get_def_use_mgr()->GetDef(end_type_id_1)->opcode() ==
-          SpvOpTypeVoid ||
+          spv::Op::OpTypeVoid ||
       ir_context_->get_def_use_mgr()->GetDef(end_type_id_2)->opcode() ==
-          SpvOpTypeVoid) {
+          spv::Op::OpTypeVoid) {
     return false;
   }
   // If the end types are the same, the data descriptors are comparable.
diff --git a/source/fuzz/fact_manager/data_synonym_and_id_equation_facts.h b/source/fuzz/fact_manager/data_synonym_and_id_equation_facts.h
index 6652f30..36d92ca 100644
--- a/source/fuzz/fact_manager/data_synonym_and_id_equation_facts.h
+++ b/source/fuzz/fact_manager/data_synonym_and_id_equation_facts.h
@@ -79,7 +79,7 @@
   // This helper struct represents the right hand side of an equation as an
   // operator applied to a number of data descriptor operands.
   struct Operation {
-    SpvOp opcode;
+    spv::Op opcode;
     std::vector<const protobufs::DataDescriptor*> operands;
   };
 
@@ -144,7 +144,7 @@
   // corollaries, in the form of data synonym or equation facts, that follow
   // from this and other known facts.
   void AddEquationFactRecursive(
-      const protobufs::DataDescriptor& lhs_dd, SpvOp opcode,
+      const protobufs::DataDescriptor& lhs_dd, spv::Op opcode,
       const std::vector<const protobufs::DataDescriptor*>& rhs_dds);
 
   // Returns true if and only if |dd.object()| still exists in the module.
diff --git a/source/fuzz/fact_manager/fact_manager.cpp b/source/fuzz/fact_manager/fact_manager.cpp
index 40c0865..c99f690 100644
--- a/source/fuzz/fact_manager/fact_manager.cpp
+++ b/source/fuzz/fact_manager/fact_manager.cpp
@@ -64,7 +64,7 @@
 std::string ToString(const protobufs::FactIdEquation& fact) {
   std::stringstream stream;
   stream << fact.lhs_id();
-  stream << " " << static_cast<SpvOp>(fact.opcode());
+  stream << " " << fact.opcode();
   for (auto rhs_id : fact.rhs_id()) {
     stream << " " << rhs_id;
   }
@@ -255,11 +255,11 @@
   assert(success && "|result_id| is invalid");
 }
 
-void FactManager::AddFactIdEquation(uint32_t lhs_id, SpvOp opcode,
+void FactManager::AddFactIdEquation(uint32_t lhs_id, spv::Op opcode,
                                     const std::vector<uint32_t>& rhs_id) {
   protobufs::FactIdEquation fact;
   fact.set_lhs_id(lhs_id);
-  fact.set_opcode(opcode);
+  fact.set_opcode(uint32_t(opcode));
   for (auto an_rhs_id : rhs_id) {
     fact.add_rhs_id(an_rhs_id);
   }
diff --git a/source/fuzz/fact_manager/fact_manager.h b/source/fuzz/fact_manager/fact_manager.h
index ce28ae4..4453e44 100644
--- a/source/fuzz/fact_manager/fact_manager.h
+++ b/source/fuzz/fact_manager/fact_manager.h
@@ -83,7 +83,7 @@
   //   |lhs_id| = |opcode| |rhs_id[0]| ... |rhs_id[N-1]|
   //
   // Neither |lhs_id| nor any of |rhs_id| may be irrelevant.
-  void AddFactIdEquation(uint32_t lhs_id, SpvOp opcode,
+  void AddFactIdEquation(uint32_t lhs_id, spv::Op opcode,
                          const std::vector<uint32_t>& rhs_id);
 
   // Inspects all known facts and adds corollary facts; e.g. if we know that
diff --git a/source/fuzz/force_render_red.cpp b/source/fuzz/force_render_red.cpp
index 3267487..191fd71 100644
--- a/source/fuzz/force_render_red.cpp
+++ b/source/fuzz/force_render_red.cpp
@@ -36,8 +36,9 @@
   // Check that this is a fragment shader
   bool found_capability_shader = false;
   for (auto& capability : ir_context->capabilities()) {
-    assert(capability.opcode() == SpvOpCapability);
-    if (capability.GetSingleWordInOperand(0) == SpvCapabilityShader) {
+    assert(capability.opcode() == spv::Op::OpCapability);
+    if (spv::Capability(capability.GetSingleWordInOperand(0)) ==
+        spv::Capability::Shader) {
       found_capability_shader = true;
       break;
     }
@@ -51,7 +52,8 @@
 
   opt::Instruction* fragment_entry_point = nullptr;
   for (auto& entry_point : ir_context->module()->entry_points()) {
-    if (entry_point.GetSingleWordInOperand(0) == SpvExecutionModelFragment) {
+    if (spv::ExecutionModel(entry_point.GetSingleWordInOperand(0)) ==
+        spv::ExecutionModel::Fragment) {
       fragment_entry_point = &entry_point;
       break;
     }
@@ -81,8 +83,9 @@
                                          MessageConsumer message_consumer) {
   opt::Instruction* output_variable = nullptr;
   for (auto& inst : ir_context->types_values()) {
-    if (inst.opcode() == SpvOpVariable &&
-        inst.GetSingleWordInOperand(0) == SpvStorageClassOutput) {
+    if (inst.opcode() == spv::Op::OpVariable &&
+        spv::StorageClass(inst.GetSingleWordInOperand(0)) ==
+            spv::StorageClass::Output) {
       if (output_variable != nullptr) {
         message_consumer(SPV_MSG_ERROR, nullptr, {},
                          "Only one output variable can be handled at present; "
@@ -144,10 +147,11 @@
                                uint32_t greater_than_instruction,
                                uint32_t in_operand_index) {
   return MakeUnique<TransformationReplaceConstantWithUniform>(
-      MakeIdUseDescriptor(constant_id,
-                          MakeInstructionDescriptor(greater_than_instruction,
-                                                    SpvOpFOrdGreaterThan, 0),
-                          in_operand_index),
+      MakeIdUseDescriptor(
+          constant_id,
+          MakeInstructionDescriptor(greater_than_instruction,
+                                    spv::Op::OpFOrdGreaterThan, 0),
+          in_operand_index),
       fact_manager.GetUniformDescriptorsForConstant(constant_id)[0],
       ir_context->TakeNextId(), ir_context->TakeNextId());
 }
@@ -204,20 +208,21 @@
   // Make the new exit block
   auto new_exit_block_id = ir_context->TakeNextId();
   {
-    auto label = MakeUnique<opt::Instruction>(ir_context.get(), SpvOpLabel, 0,
-                                              new_exit_block_id,
-                                              opt::Instruction::OperandList());
+    auto label = MakeUnique<opt::Instruction>(
+        ir_context.get(), spv::Op::OpLabel, 0, new_exit_block_id,
+        opt::Instruction::OperandList());
     auto new_exit_block = MakeUnique<opt::BasicBlock>(std::move(label));
-    new_exit_block->AddInstruction(MakeUnique<opt::Instruction>(
-        ir_context.get(), SpvOpReturn, 0, 0, opt::Instruction::OperandList()));
+    new_exit_block->AddInstruction(
+        MakeUnique<opt::Instruction>(ir_context.get(), spv::Op::OpReturn, 0, 0,
+                                     opt::Instruction::OperandList()));
     entry_point_function->AddBasicBlock(std::move(new_exit_block));
   }
 
   // Make the new entry block
   {
-    auto label = MakeUnique<opt::Instruction>(ir_context.get(), SpvOpLabel, 0,
-                                              ir_context->TakeNextId(),
-                                              opt::Instruction::OperandList());
+    auto label = MakeUnique<opt::Instruction>(
+        ir_context.get(), spv::Op::OpLabel, 0, ir_context->TakeNextId(),
+        opt::Instruction::OperandList());
     auto new_entry_block = MakeUnique<opt::BasicBlock>(std::move(label));
 
     // Make an instruction to construct vec4(1.0, 0.0, 0.0, 1.0), representing
@@ -229,7 +234,7 @@
     auto temp_vec4 = opt::analysis::Vector(float_type, 4);
     auto vec4_id = ir_context->get_type_mgr()->GetId(&temp_vec4);
     auto red = MakeUnique<opt::Instruction>(
-        ir_context.get(), SpvOpCompositeConstruct, vec4_id,
+        ir_context.get(), spv::Op::OpCompositeConstruct, vec4_id,
         ir_context->TakeNextId(), op_composite_construct_operands);
     auto red_id = red->result_id();
     new_entry_block->AddInstruction(std::move(red));
@@ -241,7 +246,7 @@
     opt::Instruction::OperandList op_store_operands = {variable_to_store_into,
                                                        value_to_be_stored};
     new_entry_block->AddInstruction(MakeUnique<opt::Instruction>(
-        ir_context.get(), SpvOpStore, 0, 0, op_store_operands));
+        ir_context.get(), spv::Op::OpStore, 0, 0, op_store_operands));
 
     // We are going to attempt to construct 'false' as an expression of the form
     // 'literal1 > literal2'. If we succeed, we will later replace each literal
@@ -313,7 +318,7 @@
               {SPV_OPERAND_TYPE_ID, {smaller_constant}},
               {SPV_OPERAND_TYPE_ID, {larger_constant}}};
           new_entry_block->AddInstruction(MakeUnique<opt::Instruction>(
-              ir_context.get(), SpvOpFOrdGreaterThan,
+              ir_context.get(), spv::Op::OpFOrdGreaterThan,
               ir_context->get_type_mgr()->GetId(registered_bool_type),
               id_guaranteed_to_be_false, greater_than_operands));
 
@@ -344,9 +349,9 @@
     opt::Operand else_block = {SPV_OPERAND_TYPE_ID, {new_exit_block_id}};
     opt::Instruction::OperandList op_branch_conditional_operands = {
         false_condition, then_block, else_block};
-    new_entry_block->AddInstruction(
-        MakeUnique<opt::Instruction>(ir_context.get(), SpvOpBranchConditional,
-                                     0, 0, op_branch_conditional_operands));
+    new_entry_block->AddInstruction(MakeUnique<opt::Instruction>(
+        ir_context.get(), spv::Op::OpBranchConditional, 0, 0,
+        op_branch_conditional_operands));
 
     entry_point_function->InsertBasicBlockBefore(
         std::move(new_entry_block), entry_point_function->entry().get());
diff --git a/source/fuzz/fuzzer_pass.cpp b/source/fuzz/fuzzer_pass.cpp
index 6a87985..02d8aa1 100644
--- a/source/fuzz/fuzzer_pass.cpp
+++ b/source/fuzz/fuzzer_pass.cpp
@@ -131,14 +131,15 @@
     // should skip when searching from 'base' for the desired instruction.
     // (An instruction that has a result id is represented by its own opcode,
     // itself as 'base', and a skip-count of 0.)
-    std::vector<std::tuple<uint32_t, SpvOp, uint32_t>> base_opcode_skip_triples;
+    std::vector<std::tuple<uint32_t, spv::Op, uint32_t>>
+        base_opcode_skip_triples;
 
     // The initial base instruction is the block label.
     uint32_t base = block->id();
 
     // Counts the number of times we have seen each opcode since we reset the
     // base instruction.
-    std::map<SpvOp, uint32_t> skip_count;
+    std::map<spv::Op, uint32_t> skip_count;
 
     // Consider every instruction in the block.  The label is excluded: it is
     // only necessary to consider it as a base in case the first instruction
@@ -151,7 +152,7 @@
         base = inst_it->result_id();
         skip_count.clear();
       }
-      const SpvOp opcode = inst_it->opcode();
+      const spv::Op opcode = inst_it->opcode();
 
       // Invoke the provided function, which might apply a transformation.
       action(block, inst_it,
@@ -330,7 +331,7 @@
 }
 
 uint32_t FuzzerPass::FindOrCreatePointerType(uint32_t base_type_id,
-                                             SpvStorageClass storage_class) {
+                                             spv::StorageClass storage_class) {
   // We do not use the type manager here, due to problems related to isomorphic
   // but distinct structs not being regarded as different.
   auto existing_id = fuzzerutil::MaybeGetPointerType(
@@ -345,7 +346,7 @@
 }
 
 uint32_t FuzzerPass::FindOrCreatePointerToIntegerType(
-    uint32_t width, bool is_signed, SpvStorageClass storage_class) {
+    uint32_t width, bool is_signed, spv::StorageClass storage_class) {
   return FindOrCreatePointerType(FindOrCreateIntegerType(width, is_signed),
                                  storage_class);
 }
@@ -432,7 +433,7 @@
 
 uint32_t FuzzerPass::FindOrCreateGlobalUndef(uint32_t type_id) {
   for (auto& inst : GetIRContext()->types_values()) {
-    if (inst.opcode() == SpvOpUndef && inst.type_id() == type_id) {
+    if (inst.opcode() == spv::Op::OpUndef && inst.type_id() == type_id) {
       return inst.result_id();
     }
   }
@@ -464,7 +465,7 @@
 
 std::pair<std::vector<uint32_t>, std::map<uint32_t, std::vector<uint32_t>>>
 FuzzerPass::GetAvailableBasicTypesAndPointers(
-    SpvStorageClass storage_class) const {
+    spv::StorageClass storage_class) const {
   // Records all of the basic types available in the module.
   std::set<uint32_t> basic_types;
 
@@ -480,23 +481,23 @@
     // For pointer types with basic pointee types, associate the pointer type
     // with the basic type.
     switch (inst.opcode()) {
-      case SpvOpTypeBool:
-      case SpvOpTypeFloat:
-      case SpvOpTypeInt:
-      case SpvOpTypeMatrix:
-      case SpvOpTypeVector:
+      case spv::Op::OpTypeBool:
+      case spv::Op::OpTypeFloat:
+      case spv::Op::OpTypeInt:
+      case spv::Op::OpTypeMatrix:
+      case spv::Op::OpTypeVector:
         // These are all basic types.
         basic_types.insert(inst.result_id());
         basic_type_to_pointers.insert({inst.result_id(), {}});
         break;
-      case SpvOpTypeArray:
+      case spv::Op::OpTypeArray:
         // An array type is basic if its base type is basic.
         if (basic_types.count(inst.GetSingleWordInOperand(0))) {
           basic_types.insert(inst.result_id());
           basic_type_to_pointers.insert({inst.result_id(), {}});
         }
         break;
-      case SpvOpTypeStruct: {
+      case spv::Op::OpTypeStruct: {
         // A struct type is basic if it does not have the Block/BufferBlock
         // decoration, and if all of its members are basic.
         if (!fuzzerutil::HasBlockOrBufferBlockDecoration(GetIRContext(),
@@ -515,11 +516,12 @@
         }
         break;
       }
-      case SpvOpTypePointer: {
+      case spv::Op::OpTypePointer: {
         // We are interested in the pointer if its pointee type is basic and it
         // has the right storage class.
         auto pointee_type = inst.GetSingleWordInOperand(1);
-        if (inst.GetSingleWordInOperand(0) == storage_class &&
+        if (spv::StorageClass(inst.GetSingleWordInOperand(0)) ==
+                storage_class &&
             basic_types.count(pointee_type)) {
           // The pointer has the desired storage class, and its pointee type is
           // a basic type, so we are interested in it.  Associate it with its
@@ -541,22 +543,22 @@
       GetIRContext()->get_def_use_mgr()->GetDef(scalar_or_composite_type_id);
   assert(type_instruction && "The type instruction must exist.");
   switch (type_instruction->opcode()) {
-    case SpvOpTypeBool:
+    case spv::Op::OpTypeBool:
       return FindOrCreateBoolConstant(false, is_irrelevant);
-    case SpvOpTypeFloat: {
+    case spv::Op::OpTypeFloat: {
       auto width = type_instruction->GetSingleWordInOperand(0);
       auto num_words = (width + 32 - 1) / 32;
       return FindOrCreateFloatConstant(std::vector<uint32_t>(num_words, 0),
                                        width, is_irrelevant);
     }
-    case SpvOpTypeInt: {
+    case spv::Op::OpTypeInt: {
       auto width = type_instruction->GetSingleWordInOperand(0);
       auto num_words = (width + 32 - 1) / 32;
       return FindOrCreateIntegerConstant(
           std::vector<uint32_t>(num_words, 0), width,
           type_instruction->GetSingleWordInOperand(1), is_irrelevant);
     }
-    case SpvOpTypeArray: {
+    case spv::Op::OpTypeArray: {
       auto component_type_id = type_instruction->GetSingleWordInOperand(0);
       auto num_components =
           fuzzerutil::GetArraySize(*type_instruction, GetIRContext());
@@ -566,8 +568,8 @@
               FindOrCreateZeroConstant(component_type_id, is_irrelevant)),
           scalar_or_composite_type_id, is_irrelevant);
     }
-    case SpvOpTypeMatrix:
-    case SpvOpTypeVector: {
+    case spv::Op::OpTypeMatrix:
+    case spv::Op::OpTypeVector: {
       auto component_type_id = type_instruction->GetSingleWordInOperand(0);
       auto num_components = type_instruction->GetSingleWordInOperand(1);
       return FindOrCreateCompositeConstant(
@@ -576,7 +578,7 @@
               FindOrCreateZeroConstant(component_type_id, is_irrelevant)),
           scalar_or_composite_type_id, is_irrelevant);
     }
-    case SpvOpTypeStruct: {
+    case spv::Op::OpTypeStruct: {
       assert(!fuzzerutil::HasBlockOrBufferBlockDecoration(
                  GetIRContext(), scalar_or_composite_type_id) &&
              "We do not construct constants of struct types decorated with "
@@ -646,7 +648,7 @@
 
     // |maybe_preheader| is a preheader if it branches unconditionally to
     // the header. We also require it not to be a loop header.
-    if (maybe_preheader->terminator()->opcode() == SpvOpBranch &&
+    if (maybe_preheader->terminator()->opcode() == spv::Op::OpBranch &&
         !maybe_preheader->IsLoopHeader()) {
       return maybe_preheader;
     }
@@ -683,8 +685,8 @@
 
   // Find the first non-OpPhi and non-OpVariable instruction.
   auto non_phi_or_var_inst = &*block->begin();
-  while (non_phi_or_var_inst->opcode() == SpvOpPhi ||
-         non_phi_or_var_inst->opcode() == SpvOpVariable) {
+  while (non_phi_or_var_inst->opcode() == spv::Op::OpPhi ||
+         non_phi_or_var_inst->opcode() == spv::Op::OpVariable) {
     non_phi_or_var_inst = non_phi_or_var_inst->NextNode();
   }
 
@@ -706,7 +708,7 @@
   (void)pointer_type;
   assert(pointer_type && pointer_type->AsPointer() &&
          pointer_type->AsPointer()->storage_class() ==
-             SpvStorageClassFunction &&
+             spv::StorageClass::Function &&
          "The pointer_type_id must refer to a defined pointer type with "
          "storage class Function");
   auto function = fuzzerutil::FindFunction(GetIRContext(), function_id);
@@ -715,7 +717,7 @@
   // First we try to find a suitable existing variable.
   // All of the local variable declarations are located in the first block.
   for (auto& instruction : *function->begin()) {
-    if (instruction.opcode() != SpvOpVariable) {
+    if (instruction.opcode() != spv::Op::OpVariable) {
       continue;
     }
     // The existing OpVariable must have type |pointer_type_id|.
@@ -749,15 +751,16 @@
   (void)pointer_type;
   assert(
       pointer_type && pointer_type->AsPointer() &&
-      (pointer_type->AsPointer()->storage_class() == SpvStorageClassPrivate ||
+      (pointer_type->AsPointer()->storage_class() ==
+           spv::StorageClass::Private ||
        pointer_type->AsPointer()->storage_class() ==
-           SpvStorageClassWorkgroup) &&
+           spv::StorageClass::Workgroup) &&
       "The pointer_type_id must refer to a defined pointer type with storage "
       "class Private or Workgroup");
 
   // First we try to find a suitable existing variable.
   for (auto& instruction : GetIRContext()->module()->types_values()) {
-    if (instruction.opcode() != SpvOpVariable) {
+    if (instruction.opcode() != spv::Op::OpVariable) {
       continue;
     }
     // The existing OpVariable must have type |pointer_type_id|.
@@ -781,13 +784,13 @@
   uint32_t result_id = GetFuzzerContext()->GetFreshId();
 
   // A variable with storage class Workgroup shouldn't have an initializer.
-  if (storage_class == SpvStorageClassWorkgroup) {
+  if (storage_class == spv::StorageClass::Workgroup) {
     ApplyTransformation(TransformationAddGlobalVariable(
-        result_id, pointer_type_id, SpvStorageClassWorkgroup, 0,
+        result_id, pointer_type_id, spv::StorageClass::Workgroup, 0,
         pointee_value_is_irrelevant));
   } else {
     ApplyTransformation(TransformationAddGlobalVariable(
-        result_id, pointer_type_id, SpvStorageClassPrivate,
+        result_id, pointer_type_id, spv::StorageClass::Private,
         FindOrCreateZeroConstant(pointee_type_id, pointee_value_is_irrelevant),
         pointee_value_is_irrelevant));
   }
diff --git a/source/fuzz/fuzzer_pass.h b/source/fuzz/fuzzer_pass.h
index 2655b54..5c76be1 100644
--- a/source/fuzz/fuzzer_pass.h
+++ b/source/fuzz/fuzzer_pass.h
@@ -159,14 +159,14 @@
   // already exist) and storage class |storage_class|.  A transformation is
   // applied to add the pointer if it does not already exist.
   uint32_t FindOrCreatePointerType(uint32_t base_type_id,
-                                   SpvStorageClass storage_class);
+                                   spv::StorageClass storage_class);
 
   // Returns the id of an OpTypePointer instruction, with a integer base
   // type of width and signedness specified by |width| and |is_signed|,
   // respectively.  If the pointer type or required integer base type do not
   // exist, transformations are applied to add them.
   uint32_t FindOrCreatePointerToIntegerType(uint32_t width, bool is_signed,
-                                            SpvStorageClass storage_class);
+                                            spv::StorageClass storage_class);
 
   // Returns the id of an OpConstant instruction, with a integer type of
   // width and signedness specified by |width| and |is_signed|, respectively,
@@ -239,7 +239,7 @@
   //   storage class, and the sequence will have multiple elements if there are
   //   repeated pointer declarations for the same basic type and storage class.
   std::pair<std::vector<uint32_t>, std::map<uint32_t, std::vector<uint32_t>>>
-  GetAvailableBasicTypesAndPointers(SpvStorageClass storage_class) const;
+  GetAvailableBasicTypesAndPointers(spv::StorageClass storage_class) const;
 
   // Given a type id, |scalar_or_composite_type_id|, which must correspond to
   // some scalar or composite type, returns the result id of an instruction
diff --git a/source/fuzz/fuzzer_pass_add_access_chains.cpp b/source/fuzz/fuzzer_pass_add_access_chains.cpp
index 39f193d..85ca57d 100644
--- a/source/fuzz/fuzzer_pass_add_access_chains.cpp
+++ b/source/fuzz/fuzzer_pass_add_access_chains.cpp
@@ -34,15 +34,16 @@
              opt::BasicBlock::iterator inst_it,
              const protobufs::InstructionDescriptor& instruction_descriptor)
           -> void {
-        assert(inst_it->opcode() ==
-                   instruction_descriptor.target_instruction_opcode() &&
-               "The opcode of the instruction we might insert before must be "
-               "the same as the opcode in the descriptor for the instruction");
+        assert(
+            inst_it->opcode() ==
+                spv::Op(instruction_descriptor.target_instruction_opcode()) &&
+            "The opcode of the instruction we might insert before must be "
+            "the same as the opcode in the descriptor for the instruction");
 
         // Check whether it is legitimate to insert an access chain
         // instruction before this instruction.
-        if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpAccessChain,
-                                                          inst_it)) {
+        if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
+                spv::Op::OpAccessChain, inst_it)) {
           return;
         }
 
@@ -64,8 +65,8 @@
                     return false;
                   }
                   switch (instruction->opcode()) {
-                    case SpvOpConstantNull:
-                    case SpvOpUndef:
+                    case spv::Op::OpConstantNull:
+                    case spv::Op::OpUndef:
                       // Do not allow making an access chain from a null or
                       // undefined pointer.  (We can eliminate these cases
                       // before actually checking that the instruction is a
@@ -78,7 +79,7 @@
                   // make an access chain from it.
                   return context->get_def_use_mgr()
                              ->GetDef(instruction->type_id())
-                             ->opcode() == SpvOpTypePointer;
+                             ->opcode() == spv::Op::OpTypePointer;
                 });
 
         // At this point, |relevant_instructions| contains all the pointers
@@ -112,14 +113,14 @@
           }
           uint32_t bound;
           switch (subobject_type->opcode()) {
-            case SpvOpTypeArray:
+            case spv::Op::OpTypeArray:
               bound = fuzzerutil::GetArraySize(*subobject_type, GetIRContext());
               break;
-            case SpvOpTypeMatrix:
-            case SpvOpTypeVector:
+            case spv::Op::OpTypeMatrix:
+            case spv::Op::OpTypeVector:
               bound = subobject_type->GetSingleWordInOperand(1);
               break;
-            case SpvOpTypeStruct:
+            case spv::Op::OpTypeStruct:
               bound = fuzzerutil::GetNumberOfStructMembers(*subobject_type);
               break;
             default:
@@ -140,9 +141,9 @@
               GetFuzzerContext()->GetRandomIndexForAccessChain(bound);
 
           switch (subobject_type->opcode()) {
-            case SpvOpTypeArray:
-            case SpvOpTypeMatrix:
-            case SpvOpTypeVector: {
+            case spv::Op::OpTypeArray:
+            case spv::Op::OpTypeMatrix:
+            case spv::Op::OpTypeVector: {
               // The index will be clamped
 
               bool is_signed = GetFuzzerContext()->ChooseEven();
@@ -164,7 +165,7 @@
               subobject_type_id = subobject_type->GetSingleWordInOperand(0);
 
             } break;
-            case SpvOpTypeStruct:
+            case spv::Op::OpTypeStruct:
               index_ids.push_back(FindOrCreateIntegerConstant(
                   {index_value}, 32, GetFuzzerContext()->ChooseEven(), false));
               subobject_type_id =
@@ -178,7 +179,7 @@
         // pointer suitable for the access chain's result type exists, so we
         // create one if it does not.
         FindOrCreatePointerType(subobject_type_id,
-                                static_cast<SpvStorageClass>(
+                                static_cast<spv::StorageClass>(
                                     pointer_type->GetSingleWordInOperand(0)));
         // Apply the transformation to add an access chain.
         ApplyTransformation(TransformationAccessChain(
diff --git a/source/fuzz/fuzzer_pass_add_composite_extract.cpp b/source/fuzz/fuzzer_pass_add_composite_extract.cpp
index dbbec0c..c33ae44 100644
--- a/source/fuzz/fuzzer_pass_add_composite_extract.cpp
+++ b/source/fuzz/fuzzer_pass_add_composite_extract.cpp
@@ -53,8 +53,8 @@
           opt::Function* /*unused*/, opt::BasicBlock* /*unused*/,
           opt::BasicBlock::iterator inst_it,
           const protobufs::InstructionDescriptor& instruction_descriptor) {
-        if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCompositeExtract,
-                                                          inst_it)) {
+        if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
+                spv::Op::OpCompositeExtract, inst_it)) {
           return;
         }
 
@@ -97,15 +97,15 @@
             assert(type_inst && "Composite instruction has invalid type id");
 
             switch (type_inst->opcode()) {
-              case SpvOpTypeArray:
+              case spv::Op::OpTypeArray:
                 number_of_members =
                     fuzzerutil::GetArraySize(*type_inst, GetIRContext());
                 break;
-              case SpvOpTypeVector:
-              case SpvOpTypeMatrix:
+              case spv::Op::OpTypeVector:
+              case spv::Op::OpTypeMatrix:
                 number_of_members = type_inst->GetSingleWordInOperand(1);
                 break;
-              case SpvOpTypeStruct:
+              case spv::Op::OpTypeStruct:
                 number_of_members = type_inst->NumInOperands();
                 break;
               default:
@@ -122,12 +122,12 @@
                     number_of_members));
 
             switch (type_inst->opcode()) {
-              case SpvOpTypeArray:
-              case SpvOpTypeVector:
-              case SpvOpTypeMatrix:
+              case spv::Op::OpTypeArray:
+              case spv::Op::OpTypeVector:
+              case spv::Op::OpTypeMatrix:
                 type_id = type_inst->GetSingleWordInOperand(0);
                 break;
-              case SpvOpTypeStruct:
+              case spv::Op::OpTypeStruct:
                 type_id = type_inst->GetSingleWordInOperand(indices.back());
                 break;
               default:
diff --git a/source/fuzz/fuzzer_pass_add_composite_inserts.cpp b/source/fuzz/fuzzer_pass_add_composite_inserts.cpp
index 2ac12de..048cdfd 100644
--- a/source/fuzz/fuzzer_pass_add_composite_inserts.cpp
+++ b/source/fuzz/fuzzer_pass_add_composite_inserts.cpp
@@ -36,10 +36,11 @@
              opt::BasicBlock::iterator instruction_iterator,
              const protobufs::InstructionDescriptor& instruction_descriptor)
           -> void {
-        assert(instruction_iterator->opcode() ==
-                   instruction_descriptor.target_instruction_opcode() &&
-               "The opcode of the instruction we might insert before must be "
-               "the same as the opcode in the descriptor for the instruction");
+        assert(
+            instruction_iterator->opcode() ==
+                spv::Op(instruction_descriptor.target_instruction_opcode()) &&
+            "The opcode of the instruction we might insert before must be "
+            "the same as the opcode in the descriptor for the instruction");
 
         // Randomly decide whether to try adding an OpCompositeInsert
         // instruction.
@@ -51,7 +52,7 @@
         // It must be possible to insert an OpCompositeInsert instruction
         // before |instruction_iterator|.
         if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
-                SpvOpCompositeInsert, instruction_iterator)) {
+                spv::Op::OpCompositeInsert, instruction_iterator)) {
           return;
         }
 
diff --git a/source/fuzz/fuzzer_pass_add_composite_types.cpp b/source/fuzz/fuzzer_pass_add_composite_types.cpp
index af36ad0..bb90991 100644
--- a/source/fuzz/fuzzer_pass_add_composite_types.cpp
+++ b/source/fuzz/fuzzer_pass_add_composite_types.cpp
@@ -114,15 +114,15 @@
   std::vector<uint32_t> candidates;
   for (auto& inst : GetIRContext()->types_values()) {
     switch (inst.opcode()) {
-      case SpvOpTypeArray:
-      case SpvOpTypeBool:
-      case SpvOpTypeFloat:
-      case SpvOpTypeInt:
-      case SpvOpTypeMatrix:
-      case SpvOpTypeVector:
+      case spv::Op::OpTypeArray:
+      case spv::Op::OpTypeBool:
+      case spv::Op::OpTypeFloat:
+      case spv::Op::OpTypeInt:
+      case spv::Op::OpTypeMatrix:
+      case spv::Op::OpTypeVector:
         candidates.push_back(inst.result_id());
         break;
-      case SpvOpTypeStruct: {
+      case spv::Op::OpTypeStruct: {
         if (!fuzzerutil::MembersHaveBuiltInDecoration(GetIRContext(),
                                                       inst.result_id()) &&
             !fuzzerutil::HasBlockOrBufferBlockDecoration(GetIRContext(),
diff --git a/source/fuzz/fuzzer_pass_add_copy_memory.cpp b/source/fuzz/fuzzer_pass_add_copy_memory.cpp
index 6551f49..d54d4ad 100644
--- a/source/fuzz/fuzzer_pass_add_copy_memory.cpp
+++ b/source/fuzz/fuzzer_pass_add_copy_memory.cpp
@@ -36,7 +36,7 @@
              opt::BasicBlock::iterator inst_it,
              const protobufs::InstructionDescriptor& instruction_descriptor) {
         // Check that we can insert an OpCopyMemory before this instruction.
-        if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCopyMemory,
+        if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpCopyMemory,
                                                           inst_it)) {
           return;
         }
@@ -61,8 +61,8 @@
 
         // Decide whether to create global or local variable.
         auto storage_class = GetFuzzerContext()->ChooseEven()
-                                 ? SpvStorageClassPrivate
-                                 : SpvStorageClassFunction;
+                                 ? spv::StorageClass::Private
+                                 : spv::StorageClass::Function;
 
         auto pointee_type_id = fuzzerutil::GetPointeeTypeIdFromPointerType(
             GetIRContext(), inst->type_id());
diff --git a/source/fuzz/fuzzer_pass_add_equation_instructions.cpp b/source/fuzz/fuzzer_pass_add_equation_instructions.cpp
index 4bbded8..e720c4e 100644
--- a/source/fuzz/fuzzer_pass_add_equation_instructions.cpp
+++ b/source/fuzz/fuzzer_pass_add_equation_instructions.cpp
@@ -29,12 +29,14 @@
       return true;
     case 64:
       return ir_context->get_feature_mgr()->HasCapability(
-                 SpvCapabilityFloat64) &&
-             ir_context->get_feature_mgr()->HasCapability(SpvCapabilityInt64);
+                 spv::Capability::Float64) &&
+             ir_context->get_feature_mgr()->HasCapability(
+                 spv::Capability::Int64);
     case 16:
       return ir_context->get_feature_mgr()->HasCapability(
-                 SpvCapabilityFloat16) &&
-             ir_context->get_feature_mgr()->HasCapability(SpvCapabilityInt16);
+                 spv::Capability::Float16) &&
+             ir_context->get_feature_mgr()->HasCapability(
+                 spv::Capability::Int16);
     default:
       return false;
   }
@@ -66,7 +68,8 @@
         // as an example opcode for this check, to be representative of *some*
         // opcode that defines an equation, even though we may choose a
         // different opcode below.
-        if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpIAdd, inst_it)) {
+        if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpIAdd,
+                                                          inst_it)) {
           return;
         }
 
@@ -78,7 +81,7 @@
                 [this](opt::IRContext* /*unused*/,
                        opt::Instruction* instruction) -> bool {
                   return instruction->result_id() && instruction->type_id() &&
-                         instruction->opcode() != SpvOpUndef &&
+                         instruction->opcode() != spv::Op::OpUndef &&
                          !GetTransformationContext()
                               ->GetFactManager()
                               ->IdIsIrrelevant(instruction->result_id());
@@ -86,15 +89,16 @@
 
         // Try the opcodes for which we know how to make ids at random until
         // something works.
-        std::vector<SpvOp> candidate_opcodes = {
-            SpvOpIAdd,        SpvOpISub,        SpvOpLogicalNot, SpvOpSNegate,
-            SpvOpConvertUToF, SpvOpConvertSToF, SpvOpBitcast};
+        std::vector<spv::Op> candidate_opcodes = {
+            spv::Op::OpIAdd,    spv::Op::OpISub,        spv::Op::OpLogicalNot,
+            spv::Op::OpSNegate, spv::Op::OpConvertUToF, spv::Op::OpConvertSToF,
+            spv::Op::OpBitcast};
         do {
           auto opcode =
               GetFuzzerContext()->RemoveAtRandomIndex(&candidate_opcodes);
           switch (opcode) {
-            case SpvOpConvertSToF:
-            case SpvOpConvertUToF: {
+            case spv::Op::OpConvertSToF:
+            case spv::Op::OpConvertUToF: {
               std::vector<const opt::Instruction*> candidate_instructions;
               for (const auto* inst :
                    GetIntegerInstructions(available_instructions)) {
@@ -144,7 +148,7 @@
                   {operand->result_id()}, instruction_descriptor));
               return;
             }
-            case SpvOpBitcast: {
+            case spv::Op::OpBitcast: {
               const auto candidate_instructions =
                   GetNumericalInstructions(available_instructions);
 
@@ -197,8 +201,8 @@
                 return;
               }
             } break;
-            case SpvOpIAdd:
-            case SpvOpISub: {
+            case spv::Op::OpIAdd:
+            case spv::Op::OpISub: {
               // Instructions of integer (scalar or vector) result type are
               // suitable for these opcodes.
               auto integer_instructions =
@@ -251,7 +255,7 @@
               }
               break;
             }
-            case SpvOpLogicalNot: {
+            case spv::Op::OpLogicalNot: {
               // Choose any available instruction of boolean scalar/vector
               // result type and equate its negation with a fresh id.
               auto boolean_instructions =
@@ -268,7 +272,7 @@
               }
               break;
             }
-            case SpvOpSNegate: {
+            case spv::Op::OpSNegate: {
               // Similar to OpLogicalNot, but for signed integer negation.
               auto integer_instructions =
                   GetIntegerInstructions(available_instructions);
diff --git a/source/fuzz/fuzzer_pass_add_function_calls.cpp b/source/fuzz/fuzzer_pass_add_function_calls.cpp
index 033f4a2..70b8657 100644
--- a/source/fuzz/fuzzer_pass_add_function_calls.cpp
+++ b/source/fuzz/fuzzer_pass_add_function_calls.cpp
@@ -39,8 +39,8 @@
           -> void {
         // Check whether it is legitimate to insert a function call before the
         // instruction.
-        if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpFunctionCall,
-                                                          inst_it)) {
+        if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
+                spv::Op::OpFunctionCall, inst_it)) {
           return;
         }
 
@@ -112,8 +112,8 @@
   auto available_pointers = FindAvailableInstructions(
       caller_function, caller_block, caller_inst_it,
       [this, caller_block](opt::IRContext* /*unused*/, opt::Instruction* inst) {
-        if (inst->opcode() != SpvOpVariable ||
-            inst->opcode() != SpvOpFunctionParameter) {
+        if (inst->opcode() != spv::Op::OpVariable ||
+            inst->opcode() != spv::Op::OpFunctionParameter) {
           // Function parameters and variables are the only
           // kinds of pointer that can be used as actual
           // parameters.
@@ -172,15 +172,15 @@
     auto storage_class = param_type->AsPointer()->storage_class();
     auto pointee_type_id = fuzzerutil::GetPointeeTypeIdFromPointerType(
         GetIRContext(), param->type_id());
-    if (storage_class == SpvStorageClassFunction) {
+    if (storage_class == spv::StorageClass::Function) {
       // Add a new zero-initialized local variable to the current
       // function, noting that its pointee value is irrelevant.
       ApplyTransformation(TransformationAddLocalVariable(
           fresh_variable_id, param->type_id(), caller_function->result_id(),
           FindOrCreateZeroConstant(pointee_type_id, false), true));
     } else {
-      assert((storage_class == SpvStorageClassPrivate ||
-              storage_class == SpvStorageClassWorkgroup) &&
+      assert((storage_class == spv::StorageClass::Private ||
+              storage_class == spv::StorageClass::Workgroup) &&
              "Only Function, Private and Workgroup storage classes are "
              "supported at present.");
       // Add a new global variable to the module, zero-initializing it if
@@ -188,7 +188,7 @@
       // irrelevant.
       ApplyTransformation(TransformationAddGlobalVariable(
           fresh_variable_id, param->type_id(), storage_class,
-          storage_class == SpvStorageClassPrivate
+          storage_class == spv::StorageClass::Private
               ? FindOrCreateZeroConstant(pointee_type_id, false)
               : 0,
           true));
diff --git a/source/fuzz/fuzzer_pass_add_global_variables.cpp b/source/fuzz/fuzzer_pass_add_global_variables.cpp
index 061f44d..4106856 100644
--- a/source/fuzz/fuzzer_pass_add_global_variables.cpp
+++ b/source/fuzz/fuzzer_pass_add_global_variables.cpp
@@ -29,16 +29,17 @@
                  transformations, ignore_inapplicable_transformations) {}
 
 void FuzzerPassAddGlobalVariables::Apply() {
-  SpvStorageClass variable_storage_class = SpvStorageClassPrivate;
+  spv::StorageClass variable_storage_class = spv::StorageClass::Private;
   for (auto& entry_point : GetIRContext()->module()->entry_points()) {
     // If the execution model of some entry point is GLCompute,
     // then the variable storage class may be Workgroup.
-    if (entry_point.GetSingleWordInOperand(0) == SpvExecutionModelGLCompute) {
+    if (spv::ExecutionModel(entry_point.GetSingleWordInOperand(0)) ==
+        spv::ExecutionModel::GLCompute) {
       variable_storage_class =
           GetFuzzerContext()->ChoosePercentage(
               GetFuzzerContext()->GetChanceOfChoosingWorkgroupStorageClass())
-              ? SpvStorageClassWorkgroup
-              : SpvStorageClassPrivate;
+              ? spv::StorageClass::Workgroup
+              : spv::StorageClass::Private;
       break;
     }
   }
@@ -87,7 +88,7 @@
     ApplyTransformation(TransformationAddGlobalVariable(
         GetFuzzerContext()->GetFreshId(), pointer_type_id,
         variable_storage_class,
-        variable_storage_class == SpvStorageClassPrivate
+        variable_storage_class == spv::StorageClass::Private
             ? FindOrCreateZeroConstant(basic_type, false)
             : 0,
         true));
diff --git a/source/fuzz/fuzzer_pass_add_loads.cpp b/source/fuzz/fuzzer_pass_add_loads.cpp
index ab91543..3660328 100644
--- a/source/fuzz/fuzzer_pass_add_loads.cpp
+++ b/source/fuzz/fuzzer_pass_add_loads.cpp
@@ -34,10 +34,11 @@
              opt::BasicBlock::iterator inst_it,
              const protobufs::InstructionDescriptor& instruction_descriptor)
           -> void {
-        assert(inst_it->opcode() ==
-                   instruction_descriptor.target_instruction_opcode() &&
-               "The opcode of the instruction we might insert before must be "
-               "the same as the opcode in the descriptor for the instruction");
+        assert(
+            inst_it->opcode() ==
+                spv::Op(instruction_descriptor.target_instruction_opcode()) &&
+            "The opcode of the instruction we might insert before must be "
+            "the same as the opcode in the descriptor for the instruction");
 
         // Randomly decide whether to try inserting a load here.
         if (!GetFuzzerContext()->ChoosePercentage(
@@ -47,10 +48,11 @@
 
         // Check whether it is legitimate to insert a load or atomic load before
         // this instruction.
-        if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLoad, inst_it)) {
+        if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpLoad,
+                                                          inst_it)) {
           return;
         }
-        if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpAtomicLoad,
+        if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpAtomicLoad,
                                                           inst_it)) {
           return;
         }
@@ -64,8 +66,8 @@
                     return false;
                   }
                   switch (instruction->opcode()) {
-                    case SpvOpConstantNull:
-                    case SpvOpUndef:
+                    case spv::Op::OpConstantNull:
+                    case spv::Op::OpUndef:
                       // Do not allow loading from a null or undefined pointer;
                       // this might be OK if the block is dead, but for now we
                       // conservatively avoid it.
@@ -75,7 +77,7 @@
                   }
                   return context->get_def_use_mgr()
                              ->GetDef(instruction->type_id())
-                             ->opcode() == SpvOpTypePointer;
+                             ->opcode() == spv::Op::OpTypePointer;
                 });
 
         // At this point, |relevant_instructions| contains all the pointers
@@ -92,25 +94,25 @@
         uint32_t memory_scope_id = 0;
         uint32_t memory_semantics_id = 0;
 
-        auto storage_class = static_cast<SpvStorageClass>(
+        auto storage_class = static_cast<spv::StorageClass>(
             GetIRContext()
                 ->get_def_use_mgr()
                 ->GetDef(chosen_instruction->type_id())
                 ->GetSingleWordInOperand(0));
 
         switch (storage_class) {
-          case SpvStorageClassStorageBuffer:
-          case SpvStorageClassPhysicalStorageBuffer:
-          case SpvStorageClassWorkgroup:
-          case SpvStorageClassCrossWorkgroup:
-          case SpvStorageClassAtomicCounter:
-          case SpvStorageClassImage:
+          case spv::StorageClass::StorageBuffer:
+          case spv::StorageClass::PhysicalStorageBuffer:
+          case spv::StorageClass::Workgroup:
+          case spv::StorageClass::CrossWorkgroup:
+          case spv::StorageClass::AtomicCounter:
+          case spv::StorageClass::Image:
             if (GetFuzzerContext()->ChoosePercentage(
                     GetFuzzerContext()->GetChanceOfAddingAtomicLoad())) {
               is_atomic_load = true;
 
               memory_scope_id = FindOrCreateConstant(
-                  {SpvScopeInvocation},
+                  {uint32_t(spv::Scope::Invocation)},
                   FindOrCreateIntegerType(32, GetFuzzerContext()->ChooseEven()),
                   false);
 
diff --git a/source/fuzz/fuzzer_pass_add_local_variables.cpp b/source/fuzz/fuzzer_pass_add_local_variables.cpp
index a4e739f..f467f46 100644
--- a/source/fuzz/fuzzer_pass_add_local_variables.cpp
+++ b/source/fuzz/fuzzer_pass_add_local_variables.cpp
@@ -31,7 +31,7 @@
 
 void FuzzerPassAddLocalVariables::Apply() {
   auto basic_type_ids_and_pointers =
-      GetAvailableBasicTypesAndPointers(SpvStorageClassFunction);
+      GetAvailableBasicTypesAndPointers(spv::StorageClass::Function);
 
   // These are the basic types that are available to this fuzzer pass.
   auto& basic_types = basic_type_ids_and_pointers.first;
@@ -64,7 +64,7 @@
         // use it.
         pointer_type = GetFuzzerContext()->GetFreshId();
         ApplyTransformation(TransformationAddTypePointer(
-            pointer_type, SpvStorageClassFunction, basic_type));
+            pointer_type, spv::StorageClass::Function, basic_type));
         available_pointers_to_basic_type.push_back(pointer_type);
       } else {
         // There is - grab one.
diff --git a/source/fuzz/fuzzer_pass_add_opphi_synonyms.cpp b/source/fuzz/fuzzer_pass_add_opphi_synonyms.cpp
index 73b6b0a..d0b1275 100644
--- a/source/fuzz/fuzzer_pass_add_opphi_synonyms.cpp
+++ b/source/fuzz/fuzzer_pass_add_opphi_synonyms.cpp
@@ -176,8 +176,8 @@
     // - OpFunction does not yield a value;
     // - OpUndef yields an undefined value at each use, so it should never be a
     //   synonym of another id.
-    if (pair.second->opcode() == SpvOpFunction ||
-        pair.second->opcode() == SpvOpUndef) {
+    if (pair.second->opcode() == spv::Op::OpFunction ||
+        pair.second->opcode() == spv::Op::OpUndef) {
       continue;
     }
 
diff --git a/source/fuzz/fuzzer_pass_add_parameters.cpp b/source/fuzz/fuzzer_pass_add_parameters.cpp
index 1cb6a79..e663d89 100644
--- a/source/fuzz/fuzzer_pass_add_parameters.cpp
+++ b/source/fuzz/fuzzer_pass_add_parameters.cpp
@@ -79,7 +79,7 @@
         auto storage_class = fuzzerutil::GetStorageClassFromPointerType(
             GetIRContext(), current_type_id);
         switch (storage_class) {
-          case SpvStorageClassFunction: {
+          case spv::StorageClass::Function: {
             // In every caller find or create a local variable that has the
             // selected type.
             for (auto* instr :
@@ -91,8 +91,8 @@
               call_parameter_ids[instr->result_id()] = variable_id;
             }
           } break;
-          case SpvStorageClassPrivate:
-          case SpvStorageClassWorkgroup: {
+          case spv::StorageClass::Private:
+          case spv::StorageClass::Workgroup: {
             // If there exists at least one caller, find or create a global
             // variable that has the selected type.
             std::vector<opt::Instruction*> callers =
diff --git a/source/fuzz/fuzzer_pass_add_stores.cpp b/source/fuzz/fuzzer_pass_add_stores.cpp
index 606e4a6..0de02a5 100644
--- a/source/fuzz/fuzzer_pass_add_stores.cpp
+++ b/source/fuzz/fuzzer_pass_add_stores.cpp
@@ -34,10 +34,11 @@
              opt::BasicBlock::iterator inst_it,
              const protobufs::InstructionDescriptor& instruction_descriptor)
           -> void {
-        assert(inst_it->opcode() ==
-                   instruction_descriptor.target_instruction_opcode() &&
-               "The opcode of the instruction we might insert before must be "
-               "the same as the opcode in the descriptor for the instruction");
+        assert(
+            inst_it->opcode() ==
+                spv::Op(instruction_descriptor.target_instruction_opcode()) &&
+            "The opcode of the instruction we might insert before must be "
+            "the same as the opcode in the descriptor for the instruction");
 
         // Randomly decide whether to try inserting a store here.
         if (!GetFuzzerContext()->ChoosePercentage(
@@ -47,12 +48,12 @@
 
         // Check whether it is legitimate to insert a store before this
         // instruction.
-        if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpStore,
+        if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpStore,
                                                           inst_it)) {
           return;
         }
-        if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpAtomicStore,
-                                                          inst_it)) {
+        if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
+                spv::Op::OpAtomicStore, inst_it)) {
           return;
         }
 
@@ -67,7 +68,7 @@
                   }
                   auto type_inst = context->get_def_use_mgr()->GetDef(
                       instruction->type_id());
-                  if (type_inst->opcode() != SpvOpTypePointer) {
+                  if (type_inst->opcode() != spv::Op::OpTypePointer) {
                     // Not a pointer.
                     return false;
                   }
@@ -76,8 +77,8 @@
                     return false;
                   }
                   switch (instruction->opcode()) {
-                    case SpvOpConstantNull:
-                    case SpvOpUndef:
+                    case spv::Op::OpConstantNull:
+                    case spv::Op::OpUndef:
                       // Do not allow storing to a null or undefined pointer;
                       // this might be OK if the block is dead, but for now we
                       // conservatively avoid it.
@@ -126,24 +127,24 @@
         uint32_t memory_semantics_id = 0;
 
         auto storage_class =
-            static_cast<SpvStorageClass>(GetIRContext()
-                                             ->get_def_use_mgr()
-                                             ->GetDef(pointer->type_id())
-                                             ->GetSingleWordInOperand(0));
+            static_cast<spv::StorageClass>(GetIRContext()
+                                               ->get_def_use_mgr()
+                                               ->GetDef(pointer->type_id())
+                                               ->GetSingleWordInOperand(0));
 
         switch (storage_class) {
-          case SpvStorageClassStorageBuffer:
-          case SpvStorageClassPhysicalStorageBuffer:
-          case SpvStorageClassWorkgroup:
-          case SpvStorageClassCrossWorkgroup:
-          case SpvStorageClassAtomicCounter:
-          case SpvStorageClassImage:
+          case spv::StorageClass::StorageBuffer:
+          case spv::StorageClass::PhysicalStorageBuffer:
+          case spv::StorageClass::Workgroup:
+          case spv::StorageClass::CrossWorkgroup:
+          case spv::StorageClass::AtomicCounter:
+          case spv::StorageClass::Image:
             if (GetFuzzerContext()->ChoosePercentage(
                     GetFuzzerContext()->GetChanceOfAddingAtomicStore())) {
               is_atomic_store = true;
 
               memory_scope_id = FindOrCreateConstant(
-                  {SpvScopeInvocation},
+                  {uint32_t(spv::Scope::Invocation)},
                   FindOrCreateIntegerType(32, GetFuzzerContext()->ChooseEven()),
                   false);
 
diff --git a/source/fuzz/fuzzer_pass_add_synonyms.cpp b/source/fuzz/fuzzer_pass_add_synonyms.cpp
index 1d188de..5782732 100644
--- a/source/fuzz/fuzzer_pass_add_synonyms.cpp
+++ b/source/fuzz/fuzzer_pass_add_synonyms.cpp
@@ -44,7 +44,8 @@
         // Skip |inst_it| if we can't insert anything above it. OpIAdd is just
         // a representative of some instruction that might be produced by the
         // transformation.
-        if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpIAdd, inst_it)) {
+        if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpIAdd,
+                                                          inst_it)) {
           return;
         }
 
diff --git a/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.cpp b/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.cpp
index a29d1d3..4cddf55 100644
--- a/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.cpp
+++ b/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.cpp
@@ -35,10 +35,11 @@
              opt::BasicBlock::iterator instruction_iterator,
              const protobufs::InstructionDescriptor& instruction_descriptor)
           -> void {
-        assert(instruction_iterator->opcode() ==
-                   instruction_descriptor.target_instruction_opcode() &&
-               "The opcode of the instruction we might insert before must be "
-               "the same as the opcode in the descriptor for the instruction");
+        assert(
+            instruction_iterator->opcode() ==
+                spv::Op(instruction_descriptor.target_instruction_opcode()) &&
+            "The opcode of the instruction we might insert before must be "
+            "the same as the opcode in the descriptor for the instruction");
 
         // Randomly decide whether to try adding an OpVectorShuffle instruction.
         if (!GetFuzzerContext()->ChoosePercentage(
@@ -49,7 +50,7 @@
         // It must be valid to insert an OpVectorShuffle instruction
         // before |instruction_iterator|.
         if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
-                SpvOpVectorShuffle, instruction_iterator)) {
+                spv::Op::OpVectorShuffle, instruction_iterator)) {
           return;
         }
 
diff --git a/source/fuzz/fuzzer_pass_adjust_branch_weights.cpp b/source/fuzz/fuzzer_pass_adjust_branch_weights.cpp
index 94428f7..6bf46e1 100644
--- a/source/fuzz/fuzzer_pass_adjust_branch_weights.cpp
+++ b/source/fuzz/fuzzer_pass_adjust_branch_weights.cpp
@@ -33,7 +33,7 @@
   // For all OpBranchConditional instructions,
   // randomly applies the transformation.
   GetIRContext()->module()->ForEachInst([this](opt::Instruction* instruction) {
-    if (instruction->opcode() == SpvOpBranchConditional &&
+    if (instruction->opcode() == spv::Op::OpBranchConditional &&
         GetFuzzerContext()->ChoosePercentage(
             GetFuzzerContext()->GetChanceOfAdjustingBranchWeights())) {
       ApplyTransformation(TransformationAdjustBranchWeights(
diff --git a/source/fuzz/fuzzer_pass_adjust_function_controls.cpp b/source/fuzz/fuzzer_pass_adjust_function_controls.cpp
index 1c2bc8c..363edc7 100644
--- a/source/fuzz/fuzzer_pass_adjust_function_controls.cpp
+++ b/source/fuzz/fuzzer_pass_adjust_function_controls.cpp
@@ -40,21 +40,21 @@
       // For the new mask, we first randomly select one of three basic masks:
       // None, Inline or DontInline.  These are always valid (and are mutually
       // exclusive).
-      std::vector<uint32_t> basic_function_control_masks = {
-          SpvFunctionControlMaskNone, SpvFunctionControlInlineMask,
-          SpvFunctionControlDontInlineMask};
+      std::vector<spv::FunctionControlMask> basic_function_control_masks = {
+          spv::FunctionControlMask::MaskNone, spv::FunctionControlMask::Inline,
+          spv::FunctionControlMask::DontInline};
       uint32_t new_function_control_mask =
-          basic_function_control_masks[GetFuzzerContext()->RandomIndex(
-              basic_function_control_masks)];
+          uint32_t(basic_function_control_masks[GetFuzzerContext()->RandomIndex(
+              basic_function_control_masks)]);
 
       // We now consider the Pure and Const mask bits.  If these are already
       // set on the function then it's OK to keep them, but also interesting
       // to consider dropping them, so we decide randomly in each case.
       for (auto mask_bit :
-           {SpvFunctionControlPureMask, SpvFunctionControlConstMask}) {
-        if ((existing_function_control_mask & mask_bit) &&
+           {spv::FunctionControlMask::Pure, spv::FunctionControlMask::Const}) {
+        if ((existing_function_control_mask & uint32_t(mask_bit)) &&
             GetFuzzerContext()->ChooseEven()) {
-          new_function_control_mask |= mask_bit;
+          new_function_control_mask |= uint32_t(mask_bit);
         }
       }
 
diff --git a/source/fuzz/fuzzer_pass_adjust_loop_controls.cpp b/source/fuzz/fuzzer_pass_adjust_loop_controls.cpp
index fe855ca..53dbe54 100644
--- a/source/fuzz/fuzzer_pass_adjust_loop_controls.cpp
+++ b/source/fuzz/fuzzer_pass_adjust_loop_controls.cpp
@@ -34,7 +34,7 @@
     for (auto& block : function) {
       if (auto merge_inst = block.GetMergeInst()) {
         // Ignore the instruction if it is not a loop merge.
-        if (merge_inst->opcode() != SpvOpLoopMerge) {
+        if (merge_inst->opcode() != spv::Op::OpLoopMerge) {
           continue;
         }
 
@@ -48,9 +48,10 @@
             TransformationSetLoopControl::kLoopControlMaskInOperandIndex);
 
         // First, set the new mask to one of None, Unroll or DontUnroll.
-        std::vector<uint32_t> basic_masks = {SpvLoopControlMaskNone,
-                                             SpvLoopControlUnrollMask,
-                                             SpvLoopControlDontUnrollMask};
+        std::vector<uint32_t> basic_masks = {
+            uint32_t(spv::LoopControlMask::MaskNone),
+            uint32_t(spv::LoopControlMask::Unroll),
+            uint32_t(spv::LoopControlMask::DontUnroll)};
         uint32_t new_mask =
             basic_masks[GetFuzzerContext()->RandomIndex(basic_masks)];
 
@@ -58,19 +59,20 @@
         // does, check which of these were present in the existing mask and
         // randomly decide whether to keep them.  They are just hints, so
         // removing them should not change the semantics of the module.
-        for (auto mask_bit :
-             {SpvLoopControlDependencyInfiniteMask,
-              SpvLoopControlDependencyLengthMask,
-              SpvLoopControlMinIterationsMask, SpvLoopControlMaxIterationsMask,
-              SpvLoopControlIterationMultipleMask}) {
-          if ((existing_mask & mask_bit) && GetFuzzerContext()->ChooseEven()) {
+        for (auto mask_bit : {spv::LoopControlMask::DependencyInfinite,
+                              spv::LoopControlMask::DependencyLength,
+                              spv::LoopControlMask::MinIterations,
+                              spv::LoopControlMask::MaxIterations,
+                              spv::LoopControlMask::IterationMultiple}) {
+          if ((existing_mask & uint32_t(mask_bit)) &&
+              GetFuzzerContext()->ChooseEven()) {
             // The mask bits we are considering are not available in all SPIR-V
             // versions.  However, we only include a mask bit if it was present
             // in the original loop control mask, and we work under the
             // assumption that we are transforming a valid module, thus we don't
             // need to actually check whether the SPIR-V version being used
             // supports these loop control mask bits.
-            new_mask |= mask_bit;
+            new_mask |= uint32_t(mask_bit);
           }
         }
 
@@ -81,14 +83,14 @@
 
         // PeelCount and PartialCount are not compatible with DontUnroll, so
         // we check whether DontUnroll is set.
-        if (!(new_mask & SpvLoopControlDontUnrollMask)) {
+        if (!(new_mask & uint32_t(spv::LoopControlMask::DontUnroll))) {
           // If PeelCount is supported by this SPIR-V version, randomly choose
           // whether to set it.  If it was set in the original mask and is not
           // selected for setting here, that amounts to dropping it.
           if (TransformationSetLoopControl::PeelCountIsSupported(
                   GetIRContext()) &&
               GetFuzzerContext()->ChooseEven()) {
-            new_mask |= SpvLoopControlPeelCountMask;
+            new_mask |= uint32_t(spv::LoopControlMask::PeelCount);
             // The peel count is chosen randomly - if PeelCount was already set
             // this will overwrite whatever peel count was previously used.
             peel_count = GetFuzzerContext()->GetRandomLoopControlPeelCount();
@@ -97,7 +99,7 @@
           if (TransformationSetLoopControl::PartialCountIsSupported(
                   GetIRContext()) &&
               GetFuzzerContext()->ChooseEven()) {
-            new_mask |= SpvLoopControlPartialCountMask;
+            new_mask |= uint32_t(spv::LoopControlMask::PartialCount);
             partial_count =
                 GetFuzzerContext()->GetRandomLoopControlPartialCount();
           }
diff --git a/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.cpp b/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.cpp
index d2ff40e..efae7d6 100644
--- a/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.cpp
+++ b/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.cpp
@@ -47,8 +47,8 @@
         // From SPIR-V 1.4 onwards, OpCopyMemory and OpCopyMemorySized have a
         // second mask.
         switch (inst_it->opcode()) {
-          case SpvOpCopyMemory:
-          case SpvOpCopyMemorySized:
+          case spv::Op::OpCopyMemory:
+          case spv::Op::OpCopyMemorySized:
             if (TransformationSetMemoryOperandsMask::
                     MultipleMemoryOperandMasksAreSupported(GetIRContext())) {
               indices_of_available_masks_to_adjust.push_back(1);
@@ -75,24 +75,26 @@
               existing_mask_in_operand_index < inst_it->NumInOperands()
                   ? inst_it->GetSingleWordInOperand(
                         existing_mask_in_operand_index)
-                  : static_cast<uint32_t>(SpvMemoryAccessMaskNone);
+                  : static_cast<uint32_t>(spv::MemoryAccessMask::MaskNone);
 
           // There are two things we can do to a mask:
           // - add Volatile if not already present
           // - toggle Nontemporal
           // The following ensures that we do at least one of these
-          bool add_volatile = !(existing_mask & SpvMemoryAccessVolatileMask) &&
-                              GetFuzzerContext()->ChooseEven();
+          bool add_volatile =
+              !(existing_mask & uint32_t(spv::MemoryAccessMask::Volatile)) &&
+              GetFuzzerContext()->ChooseEven();
           bool toggle_nontemporal =
               !add_volatile || GetFuzzerContext()->ChooseEven();
 
           // These bitwise operations use '|' to add Volatile if desired, and
           // '^' to toggle Nontemporal if desired.
           uint32_t new_mask =
-              (existing_mask | (add_volatile ? SpvMemoryAccessVolatileMask
-                                             : SpvMemoryAccessMaskNone)) ^
-              (toggle_nontemporal ? SpvMemoryAccessNontemporalMask
-                                  : SpvMemoryAccessMaskNone);
+              (existing_mask |
+               (add_volatile ? uint32_t(spv::MemoryAccessMask::Volatile)
+                             : uint32_t(spv::MemoryAccessMask::MaskNone))) ^
+              (toggle_nontemporal ? uint32_t(spv::MemoryAccessMask::Nontemporal)
+                                  : uint32_t(spv::MemoryAccessMask::MaskNone));
 
           TransformationSetMemoryOperandsMask transformation(
               MakeInstructionDescriptor(block, inst_it), new_mask, mask_index);
diff --git a/source/fuzz/fuzzer_pass_adjust_selection_controls.cpp b/source/fuzz/fuzzer_pass_adjust_selection_controls.cpp
index 7d8e6b5..fe0cf7a 100644
--- a/source/fuzz/fuzzer_pass_adjust_selection_controls.cpp
+++ b/source/fuzz/fuzzer_pass_adjust_selection_controls.cpp
@@ -34,7 +34,7 @@
     for (auto& block : function) {
       if (auto merge_inst = block.GetMergeInst()) {
         // Ignore the instruction if it is not a selection merge.
-        if (merge_inst->opcode() != SpvOpSelectionMerge) {
+        if (merge_inst->opcode() != spv::Op::OpSelectionMerge) {
           continue;
         }
 
@@ -48,13 +48,14 @@
         // The choices to change the selection control to are the set of valid
         // controls, minus the current control.
         std::vector<uint32_t> choices;
-        for (auto control :
-             {SpvSelectionControlMaskNone, SpvSelectionControlFlattenMask,
-              SpvSelectionControlDontFlattenMask}) {
-          if (control == merge_inst->GetSingleWordOperand(1)) {
+        for (auto control : {spv::SelectionControlMask::MaskNone,
+                             spv::SelectionControlMask::Flatten,
+                             spv::SelectionControlMask::DontFlatten}) {
+          if (control ==
+              spv::SelectionControlMask(merge_inst->GetSingleWordOperand(1))) {
             continue;
           }
-          choices.push_back(control);
+          choices.push_back(uint32_t(control));
         }
 
         // Apply the transformation and add it to the output transformation
diff --git a/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp b/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp
index 5c3b86b..0367a26 100644
--- a/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp
+++ b/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp
@@ -107,9 +107,9 @@
         // which case we need to be able to add an extract instruction to get
         // that element out.
         if (synonym_to_try->index_size() > 0 &&
-            !fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCompositeExtract,
-                                                          use_inst) &&
-            use_inst->opcode() != SpvOpPhi) {
+            !fuzzerutil::CanInsertOpcodeBeforeInstruction(
+                spv::Op::OpCompositeExtract, use_inst) &&
+            use_inst->opcode() != spv::Op::OpPhi) {
           // We cannot insert an extract before this instruction, so this
           // synonym is no good.
           continue;
@@ -132,7 +132,7 @@
           id_with_which_to_replace_use = GetFuzzerContext()->GetFreshId();
           opt::Instruction* instruction_to_insert_before = nullptr;
 
-          if (use_inst->opcode() != SpvOpPhi) {
+          if (use_inst->opcode() != spv::Op::OpPhi) {
             instruction_to_insert_before = use_inst;
           } else {
             auto parent_block_id =
@@ -182,7 +182,7 @@
 }
 
 bool FuzzerPassApplyIdSynonyms::DataDescriptorsHaveCompatibleTypes(
-    SpvOp opcode, uint32_t use_in_operand_index,
+    spv::Op opcode, uint32_t use_in_operand_index,
     const protobufs::DataDescriptor& dd1,
     const protobufs::DataDescriptor& dd2) {
   auto base_object_type_id_1 =
diff --git a/source/fuzz/fuzzer_pass_apply_id_synonyms.h b/source/fuzz/fuzzer_pass_apply_id_synonyms.h
index 3da9c5d..d1a0e1a 100644
--- a/source/fuzz/fuzzer_pass_apply_id_synonyms.h
+++ b/source/fuzz/fuzzer_pass_apply_id_synonyms.h
@@ -38,7 +38,7 @@
   // with respect to the type. Concretely, returns true if |dd1| and |dd2| have
   // the same type or both |dd1| and |dd2| are either a numerical or a vector
   // type of integral components with possibly different signedness.
-  bool DataDescriptorsHaveCompatibleTypes(SpvOp opcode,
+  bool DataDescriptorsHaveCompatibleTypes(spv::Op opcode,
                                           uint32_t use_in_operand_index,
                                           const protobufs::DataDescriptor& dd1,
                                           const protobufs::DataDescriptor& dd2);
diff --git a/source/fuzz/fuzzer_pass_construct_composites.cpp b/source/fuzz/fuzzer_pass_construct_composites.cpp
index ff022fc..0ad630c 100644
--- a/source/fuzz/fuzzer_pass_construct_composites.cpp
+++ b/source/fuzz/fuzzer_pass_construct_composites.cpp
@@ -81,7 +81,7 @@
         // Check whether it is legitimate to insert a composite construction
         // before the instruction.
         if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
-                SpvOpCompositeConstruct, inst_it)) {
+                spv::Op::OpCompositeConstruct, inst_it)) {
           return;
         }
 
@@ -121,19 +121,19 @@
         auto composite_type_inst =
             GetIRContext()->get_def_use_mgr()->GetDef(chosen_composite_type);
         switch (composite_type_inst->opcode()) {
-          case SpvOpTypeArray:
+          case spv::Op::OpTypeArray:
             constructor_arguments = FindComponentsToConstructArray(
                 *composite_type_inst, type_id_to_available_instructions);
             break;
-          case SpvOpTypeMatrix:
+          case spv::Op::OpTypeMatrix:
             constructor_arguments = FindComponentsToConstructMatrix(
                 *composite_type_inst, type_id_to_available_instructions);
             break;
-          case SpvOpTypeStruct:
+          case spv::Op::OpTypeStruct:
             constructor_arguments = FindComponentsToConstructStruct(
                 *composite_type_inst, type_id_to_available_instructions);
             break;
-          case SpvOpTypeVector:
+          case spv::Op::OpTypeVector:
             constructor_arguments = FindComponentsToConstructVector(
                 *composite_type_inst, type_id_to_available_instructions);
             break;
@@ -156,7 +156,7 @@
 FuzzerPassConstructComposites::FindComponentsToConstructArray(
     const opt::Instruction& array_type_instruction,
     const TypeIdToInstructions& type_id_to_available_instructions) {
-  assert(array_type_instruction.opcode() == SpvOpTypeArray &&
+  assert(array_type_instruction.opcode() == spv::Op::OpTypeArray &&
          "Precondition: instruction must be an array type.");
 
   // Get the element type for the array.
@@ -191,7 +191,7 @@
 FuzzerPassConstructComposites::FindComponentsToConstructMatrix(
     const opt::Instruction& matrix_type_instruction,
     const TypeIdToInstructions& type_id_to_available_instructions) {
-  assert(matrix_type_instruction.opcode() == SpvOpTypeMatrix &&
+  assert(matrix_type_instruction.opcode() == spv::Op::OpTypeMatrix &&
          "Precondition: instruction must be a matrix type.");
 
   // Get the element type for the matrix.
@@ -221,7 +221,7 @@
 FuzzerPassConstructComposites::FindComponentsToConstructStruct(
     const opt::Instruction& struct_type_instruction,
     const TypeIdToInstructions& type_id_to_available_instructions) {
-  assert(struct_type_instruction.opcode() == SpvOpTypeStruct &&
+  assert(struct_type_instruction.opcode() == spv::Op::OpTypeStruct &&
          "Precondition: instruction must be a struct type.");
   std::vector<uint32_t> result;
   // Consider the type of each field of the struct.
@@ -251,7 +251,7 @@
 FuzzerPassConstructComposites::FindComponentsToConstructVector(
     const opt::Instruction& vector_type_instruction,
     const TypeIdToInstructions& type_id_to_available_instructions) {
-  assert(vector_type_instruction.opcode() == SpvOpTypeVector &&
+  assert(vector_type_instruction.opcode() == spv::Op::OpTypeVector &&
          "Precondition: instruction must be a vector type.");
 
   // Get details of the type underlying the vector, and the width of the vector,
diff --git a/source/fuzz/fuzzer_pass_copy_objects.cpp b/source/fuzz/fuzzer_pass_copy_objects.cpp
index 80cc2a5..725c33e 100644
--- a/source/fuzz/fuzzer_pass_copy_objects.cpp
+++ b/source/fuzz/fuzzer_pass_copy_objects.cpp
@@ -35,10 +35,11 @@
              opt::BasicBlock::iterator inst_it,
              const protobufs::InstructionDescriptor& instruction_descriptor)
           -> void {
-        assert(inst_it->opcode() ==
-                   instruction_descriptor.target_instruction_opcode() &&
-               "The opcode of the instruction we might insert before must be "
-               "the same as the opcode in the descriptor for the instruction");
+        assert(
+            inst_it->opcode() ==
+                spv::Op(instruction_descriptor.target_instruction_opcode()) &&
+            "The opcode of the instruction we might insert before must be "
+            "the same as the opcode in the descriptor for the instruction");
 
         if (GetTransformationContext()->GetFactManager()->BlockIsDead(
                 block->id())) {
@@ -48,7 +49,7 @@
 
         // Check whether it is legitimate to insert a copy before this
         // instruction.
-        if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCopyObject,
+        if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpCopyObject,
                                                           inst_it)) {
           return;
         }
diff --git a/source/fuzz/fuzzer_pass_donate_modules.cpp b/source/fuzz/fuzzer_pass_donate_modules.cpp
index 29ede58..1696c74 100644
--- a/source/fuzz/fuzzer_pass_donate_modules.cpp
+++ b/source/fuzz/fuzzer_pass_donate_modules.cpp
@@ -88,7 +88,7 @@
   // module.
   for (const auto& capability_inst : donor_ir_context->capabilities()) {
     auto capability =
-        static_cast<SpvCapability>(capability_inst.GetSingleWordInOperand(0));
+        static_cast<spv::Capability>(capability_inst.GetSingleWordInOperand(0));
     if (!GetIRContext()->get_feature_mgr()->HasCapability(capability)) {
       return;
     }
@@ -122,27 +122,27 @@
   //  kinds of decoration.
 }
 
-SpvStorageClass FuzzerPassDonateModules::AdaptStorageClass(
-    SpvStorageClass donor_storage_class) {
+spv::StorageClass FuzzerPassDonateModules::AdaptStorageClass(
+    spv::StorageClass donor_storage_class) {
   switch (donor_storage_class) {
-    case SpvStorageClassFunction:
-    case SpvStorageClassPrivate:
-    case SpvStorageClassWorkgroup:
+    case spv::StorageClass::Function:
+    case spv::StorageClass::Private:
+    case spv::StorageClass::Workgroup:
       // We leave these alone
       return donor_storage_class;
-    case SpvStorageClassInput:
-    case SpvStorageClassOutput:
-    case SpvStorageClassUniform:
-    case SpvStorageClassUniformConstant:
-    case SpvStorageClassPushConstant:
-    case SpvStorageClassImage:
-    case SpvStorageClassStorageBuffer:
+    case spv::StorageClass::Input:
+    case spv::StorageClass::Output:
+    case spv::StorageClass::Uniform:
+    case spv::StorageClass::UniformConstant:
+    case spv::StorageClass::PushConstant:
+    case spv::StorageClass::Image:
+    case spv::StorageClass::StorageBuffer:
       // We change these to Private
-      return SpvStorageClassPrivate;
+      return spv::StorageClass::Private;
     default:
       // Handle other cases on demand.
       assert(false && "Currently unsupported storage class.");
-      return SpvStorageClassMax;
+      return spv::StorageClass::Max;
   }
 }
 
@@ -200,14 +200,14 @@
   // that its component types will have been considered previously, and that
   // |original_id_to_donated_id| will already contain an entry for them.
   switch (type_or_value.opcode()) {
-    case SpvOpTypeImage:
-    case SpvOpTypeSampledImage:
-    case SpvOpTypeSampler:
+    case spv::Op::OpTypeImage:
+    case spv::Op::OpTypeSampledImage:
+    case spv::Op::OpTypeSampler:
       // We do not donate types and variables that relate to images and
       // samplers, so we skip these types and subsequently skip anything that
       // depends on them.
       return;
-    case SpvOpTypeVoid: {
+    case spv::Op::OpTypeVoid: {
       // Void has to exist already in order for us to have an entry point.
       // Get the existing id of void.
       opt::analysis::Void void_type;
@@ -216,7 +216,7 @@
              "The module being transformed will always have 'void' type "
              "declared.");
     } break;
-    case SpvOpTypeBool: {
+    case spv::Op::OpTypeBool: {
       // Bool cannot be declared multiple times, so use its existing id if
       // present, or add a declaration of Bool with a fresh id if not.
       opt::analysis::Bool bool_type;
@@ -228,7 +228,7 @@
         ApplyTransformation(TransformationAddTypeBoolean(new_result_id));
       }
     } break;
-    case SpvOpTypeInt: {
+    case spv::Op::OpTypeInt: {
       // Int cannot be declared multiple times with the same width and
       // signedness, so check whether an existing identical Int type is
       // present and use its id if so.  Otherwise add a declaration of the
@@ -246,8 +246,8 @@
             TransformationAddTypeInt(new_result_id, width, is_signed));
       }
     } break;
-    case SpvOpTypeFloat: {
-      // Similar to SpvOpTypeInt.
+    case spv::Op::OpTypeFloat: {
+      // Similar to spv::Op::OpTypeInt.
       const uint32_t width = type_or_value.GetSingleWordInOperand(0);
       opt::analysis::Float float_type(width);
       auto float_type_id = GetIRContext()->get_type_mgr()->GetId(&float_type);
@@ -258,7 +258,7 @@
         ApplyTransformation(TransformationAddTypeFloat(new_result_id, width));
       }
     } break;
-    case SpvOpTypeVector: {
+    case spv::Op::OpTypeVector: {
       // It is not legal to have two Vector type declarations with identical
       // element types and element counts, so check whether an existing
       // identical Vector type is present and use its id if so.  Otherwise add
@@ -282,8 +282,8 @@
             new_result_id, component_type_id, component_count));
       }
     } break;
-    case SpvOpTypeMatrix: {
-      // Similar to SpvOpTypeVector.
+    case spv::Op::OpTypeMatrix: {
+      // Similar to spv::Op::OpTypeVector.
       uint32_t column_type_id = original_id_to_donated_id->at(
           type_or_value.GetSingleWordInOperand(0));
       auto column_type =
@@ -302,7 +302,7 @@
       }
 
     } break;
-    case SpvOpTypeArray: {
+    case spv::Op::OpTypeArray: {
       // It is OK to have multiple structurally identical array types, so
       // we go ahead and add a remapped version of the type declared by the
       // donor.
@@ -318,7 +318,7 @@
           original_id_to_donated_id->at(
               type_or_value.GetSingleWordInOperand(1))));
     } break;
-    case SpvOpTypeRuntimeArray: {
+    case spv::Op::OpTypeRuntimeArray: {
       // A runtime array is allowed as the final member of an SSBO.  During
       // donation we turn runtime arrays into fixed-size arrays.  For dead
       // code donations this is OK because the array is never indexed into at
@@ -341,8 +341,8 @@
               {GetFuzzerContext()->GetRandomSizeForNewArray()}, 32, false,
               false)));
     } break;
-    case SpvOpTypeStruct: {
-      // Similar to SpvOpTypeArray.
+    case spv::Op::OpTypeStruct: {
+      // Similar to spv::Op::OpTypeArray.
       std::vector<uint32_t> member_type_ids;
       for (uint32_t i = 0; i < type_or_value.NumInOperands(); i++) {
         auto component_type_id = type_or_value.GetSingleWordInOperand(i);
@@ -358,8 +358,8 @@
       ApplyTransformation(
           TransformationAddTypeStruct(new_result_id, member_type_ids));
     } break;
-    case SpvOpTypePointer: {
-      // Similar to SpvOpTypeArray.
+    case spv::Op::OpTypePointer: {
+      // Similar to spv::Op::OpTypeArray.
       uint32_t pointee_type_id = type_or_value.GetSingleWordInOperand(1);
       if (!original_id_to_donated_id->count(pointee_type_id)) {
         // We did not donate the pointee type for this pointer type, so we
@@ -369,11 +369,11 @@
       new_result_id = GetFuzzerContext()->GetFreshId();
       ApplyTransformation(TransformationAddTypePointer(
           new_result_id,
-          AdaptStorageClass(static_cast<SpvStorageClass>(
+          AdaptStorageClass(static_cast<spv::StorageClass>(
               type_or_value.GetSingleWordInOperand(0))),
           original_id_to_donated_id->at(pointee_type_id)));
     } break;
-    case SpvOpTypeFunction: {
+    case spv::Op::OpTypeFunction: {
       // It is not OK to have multiple function types that use identical ids
       // for their return and parameter types.  We thus go through all
       // existing function types to look for a match.  We do not use the
@@ -425,10 +425,11 @@
             argument_type_ids));
       }
     } break;
-    case SpvOpSpecConstantOp: {
+    case spv::Op::OpSpecConstantOp: {
       new_result_id = GetFuzzerContext()->GetFreshId();
       auto type_id = original_id_to_donated_id->at(type_or_value.type_id());
-      auto opcode = static_cast<SpvOp>(type_or_value.GetSingleWordInOperand(0));
+      auto opcode =
+          static_cast<spv::Op>(type_or_value.GetSingleWordInOperand(0));
 
       // Make sure we take into account |original_id_to_donated_id| when
       // computing operands for OpSpecConstantOp.
@@ -447,20 +448,20 @@
       ApplyTransformation(TransformationAddSpecConstantOp(
           new_result_id, type_id, opcode, std::move(operands)));
     } break;
-    case SpvOpSpecConstantTrue:
-    case SpvOpSpecConstantFalse:
-    case SpvOpConstantTrue:
-    case SpvOpConstantFalse: {
+    case spv::Op::OpSpecConstantTrue:
+    case spv::Op::OpSpecConstantFalse:
+    case spv::Op::OpConstantTrue:
+    case spv::Op::OpConstantFalse: {
       // It is OK to have duplicate definitions of True and False, so add
       // these to the module, using a remapped Bool type.
       new_result_id = GetFuzzerContext()->GetFreshId();
-      auto value = type_or_value.opcode() == SpvOpConstantTrue ||
-                   type_or_value.opcode() == SpvOpSpecConstantTrue;
+      auto value = type_or_value.opcode() == spv::Op::OpConstantTrue ||
+                   type_or_value.opcode() == spv::Op::OpSpecConstantTrue;
       ApplyTransformation(
           TransformationAddConstantBoolean(new_result_id, value, false));
     } break;
-    case SpvOpSpecConstant:
-    case SpvOpConstant: {
+    case spv::Op::OpSpecConstant:
+    case spv::Op::OpConstant: {
       // It is OK to have duplicate constant definitions, so add this to the
       // module using a remapped result type.
       new_result_id = GetFuzzerContext()->GetFreshId();
@@ -472,8 +473,8 @@
           new_result_id, original_id_to_donated_id->at(type_or_value.type_id()),
           data_words, false));
     } break;
-    case SpvOpSpecConstantComposite:
-    case SpvOpConstantComposite: {
+    case spv::Op::OpSpecConstantComposite:
+    case spv::Op::OpConstantComposite: {
       assert(original_id_to_donated_id->count(type_or_value.type_id()) &&
              "Composite types for which it is possible to create a constant "
              "should have been donated.");
@@ -495,7 +496,7 @@
           new_result_id, original_id_to_donated_id->at(type_or_value.type_id()),
           constituent_ids, false));
     } break;
-    case SpvOpConstantNull: {
+    case spv::Op::OpConstantNull: {
       if (!original_id_to_donated_id->count(type_or_value.type_id())) {
         // We did not donate the type associated with this null constant, so
         // we cannot donate the null constant.
@@ -509,7 +510,7 @@
           new_result_id,
           original_id_to_donated_id->at(type_or_value.type_id())));
     } break;
-    case SpvOpVariable: {
+    case spv::Op::OpVariable: {
       if (!original_id_to_donated_id->count(type_or_value.type_id())) {
         // We did not donate the pointer type associated with this variable,
         // so we cannot donate the variable.
@@ -536,11 +537,11 @@
       uint32_t remapped_pointer_type =
           original_id_to_donated_id->at(type_or_value.type_id());
       uint32_t initializer_id;
-      SpvStorageClass storage_class =
-          static_cast<SpvStorageClass>(type_or_value.GetSingleWordInOperand(
-              0)) == SpvStorageClassWorkgroup
-              ? SpvStorageClassWorkgroup
-              : SpvStorageClassPrivate;
+      spv::StorageClass storage_class =
+          static_cast<spv::StorageClass>(type_or_value.GetSingleWordInOperand(
+              0)) == spv::StorageClass::Workgroup
+              ? spv::StorageClass::Workgroup
+              : spv::StorageClass::Private;
       if (type_or_value.NumInOperands() == 1) {
         // The variable did not have an initializer.  Initialize it to zero
         // if it has Private storage class (to limit problems associated with
@@ -551,7 +552,7 @@
         //  could initialize Workgroup variables at the start of an entry
         //  point, and should do so if their uninitialized nature proves
         //  problematic.
-        initializer_id = storage_class == SpvStorageClassWorkgroup
+        initializer_id = storage_class == spv::StorageClass::Workgroup
                              ? 0
                              : FindOrCreateZeroConstant(
                                    fuzzerutil::GetPointeeTypeIdFromPointerType(
@@ -566,7 +567,7 @@
           TransformationAddGlobalVariable(new_result_id, remapped_pointer_type,
                                           storage_class, initializer_id, true));
     } break;
-    case SpvOpUndef: {
+    case spv::Op::OpUndef: {
       if (!original_id_to_donated_id->count(type_or_value.type_id())) {
         // We did not donate the type associated with this undef, so we cannot
         // donate the undef.
@@ -638,7 +639,7 @@
         [this, &donated_instructions, donor_ir_context,
          &original_id_to_donated_id,
          &skipped_instructions](const opt::Instruction* instruction) {
-          if (instruction->opcode() == SpvOpArrayLength) {
+          if (instruction->opcode() == spv::Op::OpArrayLength) {
             // We treat OpArrayLength specially.
             HandleOpArrayLength(*instruction, original_id_to_donated_id,
                                 &donated_instructions);
@@ -682,70 +683,70 @@
   // Now consider instructions we specifically want to skip because we do not
   // yet support them.
   switch (instruction.opcode()) {
-    case SpvOpAtomicLoad:
-    case SpvOpAtomicStore:
-    case SpvOpAtomicExchange:
-    case SpvOpAtomicCompareExchange:
-    case SpvOpAtomicCompareExchangeWeak:
-    case SpvOpAtomicIIncrement:
-    case SpvOpAtomicIDecrement:
-    case SpvOpAtomicIAdd:
-    case SpvOpAtomicISub:
-    case SpvOpAtomicSMin:
-    case SpvOpAtomicUMin:
-    case SpvOpAtomicSMax:
-    case SpvOpAtomicUMax:
-    case SpvOpAtomicAnd:
-    case SpvOpAtomicOr:
-    case SpvOpAtomicXor:
+    case spv::Op::OpAtomicLoad:
+    case spv::Op::OpAtomicStore:
+    case spv::Op::OpAtomicExchange:
+    case spv::Op::OpAtomicCompareExchange:
+    case spv::Op::OpAtomicCompareExchangeWeak:
+    case spv::Op::OpAtomicIIncrement:
+    case spv::Op::OpAtomicIDecrement:
+    case spv::Op::OpAtomicIAdd:
+    case spv::Op::OpAtomicISub:
+    case spv::Op::OpAtomicSMin:
+    case spv::Op::OpAtomicUMin:
+    case spv::Op::OpAtomicSMax:
+    case spv::Op::OpAtomicUMax:
+    case spv::Op::OpAtomicAnd:
+    case spv::Op::OpAtomicOr:
+    case spv::Op::OpAtomicXor:
       // We conservatively ignore all atomic instructions at present.
       // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3276): Consider
       //  being less conservative here.
-    case SpvOpImageSampleImplicitLod:
-    case SpvOpImageSampleExplicitLod:
-    case SpvOpImageSampleDrefImplicitLod:
-    case SpvOpImageSampleDrefExplicitLod:
-    case SpvOpImageSampleProjImplicitLod:
-    case SpvOpImageSampleProjExplicitLod:
-    case SpvOpImageSampleProjDrefImplicitLod:
-    case SpvOpImageSampleProjDrefExplicitLod:
-    case SpvOpImageFetch:
-    case SpvOpImageGather:
-    case SpvOpImageDrefGather:
-    case SpvOpImageRead:
-    case SpvOpImageWrite:
-    case SpvOpImageSparseSampleImplicitLod:
-    case SpvOpImageSparseSampleExplicitLod:
-    case SpvOpImageSparseSampleDrefImplicitLod:
-    case SpvOpImageSparseSampleDrefExplicitLod:
-    case SpvOpImageSparseSampleProjImplicitLod:
-    case SpvOpImageSparseSampleProjExplicitLod:
-    case SpvOpImageSparseSampleProjDrefImplicitLod:
-    case SpvOpImageSparseSampleProjDrefExplicitLod:
-    case SpvOpImageSparseFetch:
-    case SpvOpImageSparseGather:
-    case SpvOpImageSparseDrefGather:
-    case SpvOpImageSparseRead:
-    case SpvOpImageSampleFootprintNV:
-    case SpvOpImage:
-    case SpvOpImageQueryFormat:
-    case SpvOpImageQueryLevels:
-    case SpvOpImageQueryLod:
-    case SpvOpImageQueryOrder:
-    case SpvOpImageQuerySamples:
-    case SpvOpImageQuerySize:
-    case SpvOpImageQuerySizeLod:
-    case SpvOpSampledImage:
+    case spv::Op::OpImageSampleImplicitLod:
+    case spv::Op::OpImageSampleExplicitLod:
+    case spv::Op::OpImageSampleDrefImplicitLod:
+    case spv::Op::OpImageSampleDrefExplicitLod:
+    case spv::Op::OpImageSampleProjImplicitLod:
+    case spv::Op::OpImageSampleProjExplicitLod:
+    case spv::Op::OpImageSampleProjDrefImplicitLod:
+    case spv::Op::OpImageSampleProjDrefExplicitLod:
+    case spv::Op::OpImageFetch:
+    case spv::Op::OpImageGather:
+    case spv::Op::OpImageDrefGather:
+    case spv::Op::OpImageRead:
+    case spv::Op::OpImageWrite:
+    case spv::Op::OpImageSparseSampleImplicitLod:
+    case spv::Op::OpImageSparseSampleExplicitLod:
+    case spv::Op::OpImageSparseSampleDrefImplicitLod:
+    case spv::Op::OpImageSparseSampleDrefExplicitLod:
+    case spv::Op::OpImageSparseSampleProjImplicitLod:
+    case spv::Op::OpImageSparseSampleProjExplicitLod:
+    case spv::Op::OpImageSparseSampleProjDrefImplicitLod:
+    case spv::Op::OpImageSparseSampleProjDrefExplicitLod:
+    case spv::Op::OpImageSparseFetch:
+    case spv::Op::OpImageSparseGather:
+    case spv::Op::OpImageSparseDrefGather:
+    case spv::Op::OpImageSparseRead:
+    case spv::Op::OpImageSampleFootprintNV:
+    case spv::Op::OpImage:
+    case spv::Op::OpImageQueryFormat:
+    case spv::Op::OpImageQueryLevels:
+    case spv::Op::OpImageQueryLod:
+    case spv::Op::OpImageQueryOrder:
+    case spv::Op::OpImageQuerySamples:
+    case spv::Op::OpImageQuerySize:
+    case spv::Op::OpImageQuerySizeLod:
+    case spv::Op::OpSampledImage:
       // We ignore all instructions related to accessing images, since we do not
       // donate images.
       return false;
-    case SpvOpLoad:
+    case spv::Op::OpLoad:
       switch (donor_ir_context->get_def_use_mgr()
                   ->GetDef(instruction.type_id())
                   ->opcode()) {
-        case SpvOpTypeImage:
-        case SpvOpTypeSampledImage:
-        case SpvOpTypeSampler:
+        case spv::Op::OpTypeImage:
+        case spv::Op::OpTypeSampledImage:
+        case spv::Op::OpTypeSampler:
           // Again, we ignore instructions that relate to accessing images.
           return false;
         default:
@@ -783,13 +784,13 @@
 bool FuzzerPassDonateModules::IsBasicType(
     const opt::Instruction& instruction) const {
   switch (instruction.opcode()) {
-    case SpvOpTypeArray:
-    case SpvOpTypeBool:
-    case SpvOpTypeFloat:
-    case SpvOpTypeInt:
-    case SpvOpTypeMatrix:
-    case SpvOpTypeStruct:
-    case SpvOpTypeVector:
+    case spv::Op::OpTypeArray:
+    case spv::Op::OpTypeBool:
+    case spv::Op::OpTypeFloat:
+    case spv::Op::OpTypeInt:
+    case spv::Op::OpTypeMatrix:
+    case spv::Op::OpTypeStruct:
+    case spv::Op::OpTypeVector:
       return true;
     default:
       return false;
@@ -800,7 +801,7 @@
     const opt::Instruction& instruction,
     std::map<uint32_t, uint32_t>* original_id_to_donated_id,
     std::vector<protobufs::Instruction>* donated_instructions) const {
-  assert(instruction.opcode() == SpvOpArrayLength &&
+  assert(instruction.opcode() == spv::Op::OpArrayLength &&
          "Precondition: instruction must be OpArrayLength.");
   uint32_t donated_variable_id =
       original_id_to_donated_id->at(instruction.GetSingleWordInOperand(0));
@@ -809,12 +810,12 @@
   auto pointer_to_struct_instruction =
       GetIRContext()->get_def_use_mgr()->GetDef(
           donated_variable_instruction->type_id());
-  assert(pointer_to_struct_instruction->opcode() == SpvOpTypePointer &&
+  assert(pointer_to_struct_instruction->opcode() == spv::Op::OpTypePointer &&
          "Type of variable must be pointer.");
   auto donated_struct_type_instruction =
       GetIRContext()->get_def_use_mgr()->GetDef(
           pointer_to_struct_instruction->GetSingleWordInOperand(1));
-  assert(donated_struct_type_instruction->opcode() == SpvOpTypeStruct &&
+  assert(donated_struct_type_instruction->opcode() == spv::Op::OpTypeStruct &&
          "Pointee type of pointer used by OpArrayLength must be struct.");
   assert(donated_struct_type_instruction->NumInOperands() ==
              instruction.GetSingleWordInOperand(1) + 1 &&
@@ -825,7 +826,7 @@
           donated_struct_type_instruction->NumInOperands() - 1);
   auto fixed_size_array_type_instruction =
       GetIRContext()->get_def_use_mgr()->GetDef(fixed_size_array_type_id);
-  assert(fixed_size_array_type_instruction->opcode() == SpvOpTypeArray &&
+  assert(fixed_size_array_type_instruction->opcode() == spv::Op::OpTypeArray &&
          "The donated array type must be fixed-size.");
   auto array_size_id =
       fixed_size_array_type_instruction->GetSingleWordInOperand(1);
@@ -837,7 +838,8 @@
   }
 
   donated_instructions->push_back(MakeInstructionMessage(
-      SpvOpCopyObject, original_id_to_donated_id->at(instruction.type_id()),
+      spv::Op::OpCopyObject,
+      original_id_to_donated_id->at(instruction.type_id()),
       original_id_to_donated_id->at(instruction.result_id()),
       opt::Instruction::OperandList({{SPV_OPERAND_TYPE_ID, {array_size_id}}})));
 }
@@ -892,7 +894,7 @@
   // more interesting value later.
   auto zero_constant = FindOrCreateZeroConstant(remapped_type_id, true);
   donated_instructions->push_back(MakeInstructionMessage(
-      SpvOpCopyObject, remapped_type_id,
+      spv::Op::OpCopyObject, remapped_type_id,
       original_id_to_donated_id->at(instruction.result_id()),
       opt::Instruction::OperandList({{SPV_OPERAND_TYPE_ID, {zero_constant}}})));
 }
@@ -926,8 +928,8 @@
         (void)(donor_ir_context);
         assert((donor_ir_context->get_def_use_mgr()
                         ->GetDef(operand_id)
-                        ->opcode() == SpvOpLabel ||
-                instruction.opcode() == SpvOpPhi) &&
+                        ->opcode() == spv::Op::OpLabel ||
+                instruction.opcode() == spv::Op::OpPhi) &&
                "Unsupported forward reference.");
         original_id_to_donated_id->insert(
             {operand_id, GetFuzzerContext()->GetFreshId()});
@@ -942,7 +944,7 @@
     input_operands.push_back({in_operand.type, operand_data});
   }
 
-  if (instruction.opcode() == SpvOpVariable &&
+  if (instruction.opcode() == spv::Op::OpVariable &&
       instruction.NumInOperands() == 1) {
     // This is an uninitialized local variable.  Initialize it to zero.
     input_operands.push_back(
@@ -1017,7 +1019,7 @@
 
   // Adjust OpPhi instructions in the |merge_block|.
   for (const auto& inst : *merge_block) {
-    if (inst.opcode() != SpvOpPhi) {
+    if (inst.opcode() != spv::Op::OpPhi) {
       break;
     }
 
@@ -1070,7 +1072,8 @@
   // live-safe.  Add them if not already present.
   FindOrCreateBoolType();  // Needed for comparisons
   FindOrCreatePointerToIntegerType(
-      32, false, SpvStorageClassFunction);  // Needed for adding loop limiters
+      32, false,
+      spv::StorageClass::Function);  // Needed for adding loop limiters
   FindOrCreateIntegerConstant({0}, 32, false,
                               false);  // Needed for initializing loop limiters
   FindOrCreateIntegerConstant({1}, 32, false,
@@ -1107,8 +1110,8 @@
   for (auto& block : function_to_donate) {
     for (auto& inst : block) {
       switch (inst.opcode()) {
-        case SpvOpAccessChain:
-        case SpvOpInBoundsAccessChain: {
+        case spv::Op::OpAccessChain:
+        case spv::Op::OpInBoundsAccessChain: {
           protobufs::AccessChainClampingInfo clamping_info;
           clamping_info.set_access_chain_id(
               original_id_to_donated_id.at(inst.result_id()));
@@ -1118,7 +1121,8 @@
           assert(base_object && "The base object must exist.");
           auto pointer_type = donor_ir_context->get_def_use_mgr()->GetDef(
               base_object->type_id());
-          assert(pointer_type && pointer_type->opcode() == SpvOpTypePointer &&
+          assert(pointer_type &&
+                 pointer_type->opcode() == spv::Op::OpTypePointer &&
                  "The base object must have pointer type.");
 
           auto should_be_composite_type =
@@ -1138,7 +1142,8 @@
 
             // Get the bound for the component being indexed into.
             uint32_t bound;
-            if (should_be_composite_type->opcode() == SpvOpTypeRuntimeArray) {
+            if (should_be_composite_type->opcode() ==
+                spv::Op::OpTypeRuntimeArray) {
               // The donor is indexing into a runtime array.  We do not
               // donate runtime arrays.  Instead, we donate a corresponding
               // fixed-size array for every runtime array.  We should thus
@@ -1148,7 +1153,7 @@
                   GetIRContext()->get_def_use_mgr()->GetDef(
                       original_id_to_donated_id.at(
                           should_be_composite_type->result_id()));
-              assert(fixed_size_array_type->opcode() == SpvOpTypeArray &&
+              assert(fixed_size_array_type->opcode() == spv::Op::OpTypeArray &&
                      "A runtime array type in the donor should have been "
                      "replaced by a fixed-sized array in the recipient.");
               // The size of this fixed-size array is a suitable bound.
@@ -1163,12 +1168,12 @@
                 donor_ir_context->get_def_use_mgr()->GetDef(index_id);
             auto index_type_inst = donor_ir_context->get_def_use_mgr()->GetDef(
                 index_inst->type_id());
-            assert(index_type_inst->opcode() == SpvOpTypeInt);
+            assert(index_type_inst->opcode() == spv::Op::OpTypeInt);
             opt::analysis::Integer* index_int_type =
                 donor_ir_context->get_type_mgr()
                     ->GetType(index_type_inst->result_id())
                     ->AsInteger();
-            if (index_inst->opcode() != SpvOpConstant) {
+            if (index_inst->opcode() != spv::Op::OpConstant) {
               // We will have to clamp this index, so we need a constant
               // whose value is one less than the bound, to compare
               // against and to use as the clamped value.
@@ -1194,7 +1199,7 @@
   uint32_t kill_unreachable_return_value_id = 0;
   auto function_return_type_inst =
       donor_ir_context->get_def_use_mgr()->GetDef(function_to_donate.type_id());
-  if (function_return_type_inst->opcode() != SpvOpTypeVoid &&
+  if (function_return_type_inst->opcode() != spv::Op::OpTypeVoid &&
       fuzzerutil::FunctionContainsOpKillOrUnreachable(function_to_donate)) {
     kill_unreachable_return_value_id = FindOrCreateZeroConstant(
         original_id_to_donated_id.at(function_return_type_inst->result_id()),
diff --git a/source/fuzz/fuzzer_pass_donate_modules.h b/source/fuzz/fuzzer_pass_donate_modules.h
index 924dd35..004f158 100644
--- a/source/fuzz/fuzzer_pass_donate_modules.h
+++ b/source/fuzz/fuzzer_pass_donate_modules.h
@@ -45,7 +45,8 @@
  private:
   // Adapts a storage class coming from a donor module so that it will work
   // in a recipient module, e.g. by changing Uniform to Private.
-  static SpvStorageClass AdaptStorageClass(SpvStorageClass donor_storage_class);
+  static spv::StorageClass AdaptStorageClass(
+      spv::StorageClass donor_storage_class);
 
   // Identifies all external instruction set imports in |donor_ir_context| and
   // populates |original_id_to_donated_id| with a mapping from the donor's id
diff --git a/source/fuzz/fuzzer_pass_expand_vector_reductions.cpp b/source/fuzz/fuzzer_pass_expand_vector_reductions.cpp
index 5bf0461..fecd82e 100644
--- a/source/fuzz/fuzzer_pass_expand_vector_reductions.cpp
+++ b/source/fuzz/fuzzer_pass_expand_vector_reductions.cpp
@@ -40,8 +40,8 @@
         }
 
         // |instruction| must be OpAny or OpAll.
-        if (instruction.opcode() != SpvOpAny &&
-            instruction.opcode() != SpvOpAll) {
+        if (instruction.opcode() != spv::Op::OpAny &&
+            instruction.opcode() != spv::Op::OpAll) {
           continue;
         }
 
diff --git a/source/fuzz/fuzzer_pass_flatten_conditional_branches.cpp b/source/fuzz/fuzzer_pass_flatten_conditional_branches.cpp
index 70fa6a1..86ffff4 100644
--- a/source/fuzz/fuzzer_pass_flatten_conditional_branches.cpp
+++ b/source/fuzz/fuzzer_pass_flatten_conditional_branches.cpp
@@ -48,8 +48,8 @@
       // Only consider this block if it is the header of a conditional, with a
       // non-irrelevant condition.
       if (block.GetMergeInst() &&
-          block.GetMergeInst()->opcode() == SpvOpSelectionMerge &&
-          block.terminator()->opcode() == SpvOpBranchConditional &&
+          block.GetMergeInst()->opcode() == spv::Op::OpSelectionMerge &&
+          block.terminator()->opcode() == spv::Op::OpBranchConditional &&
           !GetTransformationContext()->GetFactManager()->IdIsIrrelevant(
               block.terminator()->GetSingleWordInOperand(0))) {
         selection_headers.emplace_back(&block);
@@ -94,11 +94,11 @@
                                    ->get_def_use_mgr()
                                    ->GetDef(phi_instruction->type_id())
                                    ->opcode()) {
-                         case SpvOpTypeBool:
-                         case SpvOpTypeInt:
-                         case SpvOpTypeFloat:
-                         case SpvOpTypePointer:
-                         case SpvOpTypeVector:
+                         case spv::Op::OpTypeBool:
+                         case spv::Op::OpTypeInt:
+                         case spv::Op::OpTypeFloat:
+                         case spv::Op::OpTypePointer:
+                         case spv::Op::OpTypeVector:
                            return true;
                          default:
                            return false;
@@ -143,7 +143,7 @@
                 GetIRContext()->get_def_use_mgr()->GetDef(
                     phi_instruction->type_id());
             switch (type_instruction->opcode()) {
-              case SpvOpTypeVector: {
+              case spv::Op::OpTypeVector: {
                 uint32_t dimension =
                     type_instruction->GetSingleWordInOperand(1);
                 switch (dimension) {
diff --git a/source/fuzz/fuzzer_pass_inline_functions.cpp b/source/fuzz/fuzzer_pass_inline_functions.cpp
index 4024096..6839bbe 100644
--- a/source/fuzz/fuzzer_pass_inline_functions.cpp
+++ b/source/fuzz/fuzzer_pass_inline_functions.cpp
@@ -64,7 +64,7 @@
     auto* function_call_block =
         GetIRContext()->get_instr_block(function_call_instruction);
     if ((function_call_instruction != &*--function_call_block->tail() ||
-         function_call_block->terminator()->opcode() != SpvOpBranch) &&
+         function_call_block->terminator()->opcode() != spv::Op::OpBranch) &&
         !MaybeApplyTransformation(TransformationSplitBlock(
             MakeInstructionDescriptor(GetIRContext(),
                                       function_call_instruction->NextNode()),
diff --git a/source/fuzz/fuzzer_pass_make_vector_operations_dynamic.cpp b/source/fuzz/fuzzer_pass_make_vector_operations_dynamic.cpp
index b755d23..ec5fc4b 100644
--- a/source/fuzz/fuzzer_pass_make_vector_operations_dynamic.cpp
+++ b/source/fuzz/fuzzer_pass_make_vector_operations_dynamic.cpp
@@ -47,18 +47,20 @@
         }
 
         // Make sure |instruction| has only one indexing operand.
-        assert(instruction.NumInOperands() ==
-                   (instruction.opcode() == SpvOpCompositeExtract ? 2 : 3) &&
-               "FuzzerPassMakeVectorOperationsDynamic: the composite "
-               "instruction must have "
-               "only one indexing operand.");
+        assert(
+            instruction.NumInOperands() ==
+                (instruction.opcode() == spv::Op::OpCompositeExtract ? 2 : 3) &&
+            "FuzzerPassMakeVectorOperationsDynamic: the composite "
+            "instruction must have "
+            "only one indexing operand.");
 
         // Applies the make vector operation dynamic transformation.
         ApplyTransformation(TransformationMakeVectorOperationDynamic(
             instruction.result_id(),
             FindOrCreateIntegerConstant(
                 {instruction.GetSingleWordInOperand(
-                    instruction.opcode() == SpvOpCompositeExtract ? 1 : 2)},
+                    instruction.opcode() == spv::Op::OpCompositeExtract ? 1
+                                                                        : 2)},
                 32, GetFuzzerContext()->ChooseEven(), false)));
       }
     }
diff --git a/source/fuzz/fuzzer_pass_merge_function_returns.cpp b/source/fuzz/fuzzer_pass_merge_function_returns.cpp
index 220f707..48c1861 100644
--- a/source/fuzz/fuzzer_pass_merge_function_returns.cpp
+++ b/source/fuzz/fuzzer_pass_merge_function_returns.cpp
@@ -64,11 +64,11 @@
         [this, function](
             opt::BasicBlock* /*unused*/, opt::BasicBlock::iterator inst_it,
             const protobufs::InstructionDescriptor& instruction_descriptor) {
-          const SpvOp opcode = inst_it->opcode();
+          const spv::Op opcode = inst_it->opcode();
           switch (opcode) {
-            case SpvOpKill:
-            case SpvOpUnreachable:
-            case SpvOpTerminateInvocation: {
+            case spv::Op::OpKill:
+            case spv::Op::OpUnreachable:
+            case spv::Op::OpTerminateInvocation: {
               // This is an early termination instruction - we need to wrap it
               // so that it becomes a return.
               if (TransformationWrapEarlyTerminatorInFunction::
@@ -85,7 +85,7 @@
                   GetIRContext()->get_def_use_mgr()->GetDef(
                       function->type_id());
               uint32_t returned_value_id;
-              if (function_return_type->opcode() == SpvOpTypeVoid) {
+              if (function_return_type->opcode() == spv::Op::OpTypeVoid) {
                 // No value is needed.
                 returned_value_id = 0;
               } else if (fuzzerutil::CanCreateConstant(
@@ -130,7 +130,7 @@
 
     // If the entry block does not branch unconditionally to another block,
     // split it.
-    if (function->entry()->terminator()->opcode() != SpvOpBranch) {
+    if (function->entry()->terminator()->opcode() != spv::Op::OpBranch) {
       SplitBlockAfterOpPhiOrOpVariable(function->entry()->id());
     }
 
@@ -149,9 +149,9 @@
       if (GetIRContext()
               ->get_instr_block(merge_block)
               ->WhileEachInst([](opt::Instruction* inst) {
-                return inst->opcode() == SpvOpLabel ||
-                       inst->opcode() == SpvOpPhi ||
-                       inst->opcode() == SpvOpBranch;
+                return inst->opcode() == spv::Op::OpLabel ||
+                       inst->opcode() == spv::Op::OpPhi ||
+                       inst->opcode() == spv::Op::OpBranch;
               })) {
         actual_merge_blocks.emplace_back(merge_block);
         continue;
@@ -324,7 +324,8 @@
 
 bool FuzzerPassMergeFunctionReturns::IsEarlyTerminatorWrapper(
     const opt::Function& function) const {
-  for (SpvOp opcode : {SpvOpKill, SpvOpUnreachable, SpvOpTerminateInvocation}) {
+  for (spv::Op opcode : {spv::Op::OpKill, spv::Op::OpUnreachable,
+                         spv::Op::OpTerminateInvocation}) {
     if (TransformationWrapEarlyTerminatorInFunction::MaybeGetWrapperFunction(
             GetIRContext(), opcode) == &function) {
       return true;
diff --git a/source/fuzz/fuzzer_pass_mutate_pointers.cpp b/source/fuzz/fuzzer_pass_mutate_pointers.cpp
index bbe0540..a7e9fdc 100644
--- a/source/fuzz/fuzzer_pass_mutate_pointers.cpp
+++ b/source/fuzz/fuzzer_pass_mutate_pointers.cpp
@@ -39,7 +39,8 @@
           return;
         }
 
-        if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLoad, inst_it)) {
+        if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpLoad,
+                                                          inst_it)) {
           return;
         }
 
diff --git a/source/fuzz/fuzzer_pass_obfuscate_constants.cpp b/source/fuzz/fuzzer_pass_obfuscate_constants.cpp
index f60c1b4..48ac589 100644
--- a/source/fuzz/fuzzer_pass_obfuscate_constants.cpp
+++ b/source/fuzz/fuzzer_pass_obfuscate_constants.cpp
@@ -37,21 +37,21 @@
 
 void FuzzerPassObfuscateConstants::ObfuscateBoolConstantViaConstantPair(
     uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use,
-    const std::vector<SpvOp>& greater_than_opcodes,
-    const std::vector<SpvOp>& less_than_opcodes, uint32_t constant_id_1,
+    const std::vector<spv::Op>& greater_than_opcodes,
+    const std::vector<spv::Op>& less_than_opcodes, uint32_t constant_id_1,
     uint32_t constant_id_2, bool first_constant_is_larger) {
   auto bool_constant_opcode = GetIRContext()
                                   ->get_def_use_mgr()
                                   ->GetDef(bool_constant_use.id_of_interest())
                                   ->opcode();
-  assert((bool_constant_opcode == SpvOpConstantFalse ||
-          bool_constant_opcode == SpvOpConstantTrue) &&
+  assert((bool_constant_opcode == spv::Op::OpConstantFalse ||
+          bool_constant_opcode == spv::Op::OpConstantTrue) &&
          "Precondition: this must be a usage of a boolean constant.");
 
   // Pick an opcode at random.  First randomly decide whether to generate
   // a 'greater than' or 'less than' kind of opcode, and then select a
   // random opcode from the resulting subset.
-  SpvOp comparison_opcode;
+  spv::Op comparison_opcode;
   if (GetFuzzerContext()->ChooseEven()) {
     comparison_opcode = greater_than_opcodes[GetFuzzerContext()->RandomIndex(
         greater_than_opcodes)];
@@ -68,9 +68,9 @@
                 comparison_opcode) != greater_than_opcodes.end();
   uint32_t lhs_id;
   uint32_t rhs_id;
-  if ((bool_constant_opcode == SpvOpConstantTrue &&
+  if ((bool_constant_opcode == spv::Op::OpConstantTrue &&
        first_constant_is_larger == is_greater_than_opcode) ||
-      (bool_constant_opcode == SpvOpConstantFalse &&
+      (bool_constant_opcode == spv::Op::OpConstantFalse &&
        first_constant_is_larger != is_greater_than_opcode)) {
     lhs_id = constant_id_1;
     rhs_id = constant_id_2;
@@ -147,12 +147,12 @@
     first_constant_is_larger =
         float_constant_1->GetDouble() > float_constant_2->GetDouble();
   }
-  std::vector<SpvOp> greater_than_opcodes{
-      SpvOpFOrdGreaterThan, SpvOpFOrdGreaterThanEqual, SpvOpFUnordGreaterThan,
-      SpvOpFUnordGreaterThanEqual};
-  std::vector<SpvOp> less_than_opcodes{
-      SpvOpFOrdGreaterThan, SpvOpFOrdGreaterThanEqual, SpvOpFUnordGreaterThan,
-      SpvOpFUnordGreaterThanEqual};
+  std::vector<spv::Op> greater_than_opcodes{
+      spv::Op::OpFOrdGreaterThan, spv::Op::OpFOrdGreaterThanEqual,
+      spv::Op::OpFUnordGreaterThan, spv::Op::OpFUnordGreaterThanEqual};
+  std::vector<spv::Op> less_than_opcodes{
+      spv::Op::OpFOrdGreaterThan, spv::Op::OpFOrdGreaterThanEqual,
+      spv::Op::OpFUnordGreaterThan, spv::Op::OpFUnordGreaterThanEqual};
 
   ObfuscateBoolConstantViaConstantPair(
       depth, bool_constant_use, greater_than_opcodes, less_than_opcodes,
@@ -190,9 +190,10 @@
     first_constant_is_larger =
         signed_int_constant_1->GetS64() > signed_int_constant_2->GetS64();
   }
-  std::vector<SpvOp> greater_than_opcodes{SpvOpSGreaterThan,
-                                          SpvOpSGreaterThanEqual};
-  std::vector<SpvOp> less_than_opcodes{SpvOpSLessThan, SpvOpSLessThanEqual};
+  std::vector<spv::Op> greater_than_opcodes{spv::Op::OpSGreaterThan,
+                                            spv::Op::OpSGreaterThanEqual};
+  std::vector<spv::Op> less_than_opcodes{spv::Op::OpSLessThan,
+                                         spv::Op::OpSLessThanEqual};
 
   ObfuscateBoolConstantViaConstantPair(
       depth, bool_constant_use, greater_than_opcodes, less_than_opcodes,
@@ -232,9 +233,10 @@
     first_constant_is_larger =
         unsigned_int_constant_1->GetU64() > unsigned_int_constant_2->GetU64();
   }
-  std::vector<SpvOp> greater_than_opcodes{SpvOpUGreaterThan,
-                                          SpvOpUGreaterThanEqual};
-  std::vector<SpvOp> less_than_opcodes{SpvOpULessThan, SpvOpULessThanEqual};
+  std::vector<spv::Op> greater_than_opcodes{spv::Op::OpUGreaterThan,
+                                            spv::Op::OpUGreaterThanEqual};
+  std::vector<spv::Op> less_than_opcodes{spv::Op::OpULessThan,
+                                         spv::Op::OpULessThanEqual};
 
   ObfuscateBoolConstantViaConstantPair(
       depth, bool_constant_use, greater_than_opcodes, less_than_opcodes,
@@ -379,7 +381,7 @@
       uniform_descriptor.index());
   assert(element_type_id && "Type of uniform variable is invalid");
 
-  FindOrCreatePointerType(element_type_id, SpvStorageClassUniform);
+  FindOrCreatePointerType(element_type_id, spv::StorageClass::Uniform);
 
   // Create, apply and record a transformation to replace the constant use with
   // the result of a load from the chosen uniform.
@@ -394,11 +396,11 @@
               ->get_def_use_mgr()
               ->GetDef(constant_use.id_of_interest())
               ->opcode()) {
-    case SpvOpConstantTrue:
-    case SpvOpConstantFalse:
+    case spv::Op::OpConstantTrue:
+    case spv::Op::OpConstantFalse:
       ObfuscateBoolConstant(depth, constant_use);
       break;
-    case SpvOpConstant:
+    case spv::Op::OpConstant:
       ObfuscateScalarConstant(depth, constant_use);
       break;
     default:
@@ -410,7 +412,7 @@
 void FuzzerPassObfuscateConstants::MaybeAddConstantIdUse(
     const opt::Instruction& inst, uint32_t in_operand_index,
     uint32_t base_instruction_result_id,
-    const std::map<SpvOp, uint32_t>& skipped_opcode_count,
+    const std::map<spv::Op, uint32_t>& skipped_opcode_count,
     std::vector<protobufs::IdUseDescriptor>* constant_uses) {
   if (inst.GetInOperand(in_operand_index).type != SPV_OPERAND_TYPE_ID) {
     // The operand is not an id, so it cannot be a constant id.
@@ -420,15 +422,15 @@
   auto operand_definition =
       GetIRContext()->get_def_use_mgr()->GetDef(operand_id);
   switch (operand_definition->opcode()) {
-    case SpvOpConstantFalse:
-    case SpvOpConstantTrue:
-    case SpvOpConstant: {
+    case spv::Op::OpConstantFalse:
+    case spv::Op::OpConstantTrue:
+    case spv::Op::OpConstant: {
       // The operand is a constant id, so make an id use descriptor and record
       // it.
       protobufs::IdUseDescriptor id_use_descriptor;
       id_use_descriptor.set_id_of_interest(operand_id);
       id_use_descriptor.mutable_enclosing_instruction()
-          ->set_target_instruction_opcode(inst.opcode());
+          ->set_target_instruction_opcode(uint32_t(inst.opcode()));
       id_use_descriptor.mutable_enclosing_instruction()
           ->set_base_instruction_result_id(base_instruction_result_id);
       id_use_descriptor.mutable_enclosing_instruction()
@@ -461,7 +463,7 @@
       // opcode need to be skipped in order to find the instruction of interest
       // from the base instruction. We maintain a mapping that records a skip
       // count for each relevant opcode.
-      std::map<SpvOp, uint32_t> skipped_opcode_count;
+      std::map<spv::Op, uint32_t> skipped_opcode_count;
 
       // Go through each instruction in the block.
       for (auto& inst : block) {
@@ -478,7 +480,7 @@
         // The instruction must not be an OpVariable, the only id that an
         // OpVariable uses is an initializer id, which has to remain
         // constant.
-        if (inst.opcode() != SpvOpVariable) {
+        if (inst.opcode() != spv::Op::OpVariable) {
           // Consider each operand of the instruction, and add a constant id
           // use for the operand if relevant.
           for (uint32_t in_operand_index = 0;
diff --git a/source/fuzz/fuzzer_pass_obfuscate_constants.h b/source/fuzz/fuzzer_pass_obfuscate_constants.h
index 30e64d2..bfef597 100644
--- a/source/fuzz/fuzzer_pass_obfuscate_constants.h
+++ b/source/fuzz/fuzzer_pass_obfuscate_constants.h
@@ -85,8 +85,8 @@
   // (similar for |less_than_opcodes|).
   void ObfuscateBoolConstantViaConstantPair(
       uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use,
-      const std::vector<SpvOp>& greater_than_opcodes,
-      const std::vector<SpvOp>& less_than_opcodes, uint32_t constant_id_1,
+      const std::vector<spv::Op>& greater_than_opcodes,
+      const std::vector<spv::Op>& less_than_opcodes, uint32_t constant_id_1,
       uint32_t constant_id_2, bool first_constant_is_larger);
 
   // A helper method to determine whether input operand |in_operand_index| of
@@ -96,7 +96,7 @@
   void MaybeAddConstantIdUse(
       const opt::Instruction& inst, uint32_t in_operand_index,
       uint32_t base_instruction_result_id,
-      const std::map<SpvOp, uint32_t>& skipped_opcode_count,
+      const std::map<spv::Op, uint32_t>& skipped_opcode_count,
       std::vector<protobufs::IdUseDescriptor>* constant_uses);
 
   // Returns a vector of unique words that denote constants. Every such constant
diff --git a/source/fuzz/fuzzer_pass_outline_functions.cpp b/source/fuzz/fuzzer_pass_outline_functions.cpp
index b90c12d..e64373a 100644
--- a/source/fuzz/fuzzer_pass_outline_functions.cpp
+++ b/source/fuzz/fuzzer_pass_outline_functions.cpp
@@ -137,12 +137,12 @@
          "The entry block cannot be a loop header at this point.");
 
   // If the entry block starts with OpPhi or OpVariable, try to split it.
-  if (entry_block->begin()->opcode() == SpvOpPhi ||
-      entry_block->begin()->opcode() == SpvOpVariable) {
+  if (entry_block->begin()->opcode() == spv::Op::OpPhi ||
+      entry_block->begin()->opcode() == spv::Op::OpVariable) {
     // Find the first non-OpPhi and non-OpVariable instruction.
     auto non_phi_or_var_inst = &*entry_block->begin();
-    while (non_phi_or_var_inst->opcode() == SpvOpPhi ||
-           non_phi_or_var_inst->opcode() == SpvOpVariable) {
+    while (non_phi_or_var_inst->opcode() == spv::Op::OpPhi ||
+           non_phi_or_var_inst->opcode() == spv::Op::OpVariable) {
       non_phi_or_var_inst = non_phi_or_var_inst->NextNode();
     }
 
@@ -175,7 +175,7 @@
 
     // Find the first non-OpPhi instruction, after which to split.
     auto split_before = &*exit_block->begin();
-    while (split_before->opcode() == SpvOpPhi) {
+    while (split_before->opcode() == spv::Op::OpPhi) {
       split_before = split_before->NextNode();
     }
 
diff --git a/source/fuzz/fuzzer_pass_permute_function_variables.cpp b/source/fuzz/fuzzer_pass_permute_function_variables.cpp
index f8b9b45..2313f42 100644
--- a/source/fuzz/fuzzer_pass_permute_function_variables.cpp
+++ b/source/fuzz/fuzzer_pass_permute_function_variables.cpp
@@ -47,7 +47,7 @@
 
     std::vector<opt::Instruction*> variables;
     for (auto& instruction : *first_block) {
-      if (instruction.opcode() == SpvOpVariable) {
+      if (instruction.opcode() == spv::Op::OpVariable) {
         variables.push_back(&instruction);
       }
     }
diff --git a/source/fuzz/fuzzer_pass_permute_phi_operands.cpp b/source/fuzz/fuzzer_pass_permute_phi_operands.cpp
index 5fac981..7fbdd3b 100644
--- a/source/fuzz/fuzzer_pass_permute_phi_operands.cpp
+++ b/source/fuzz/fuzzer_pass_permute_phi_operands.cpp
@@ -40,7 +40,7 @@
              const protobufs::InstructionDescriptor& /*unused*/) {
         const auto& inst = *inst_it;
 
-        if (inst.opcode() != SpvOpPhi) {
+        if (inst.opcode() != spv::Op::OpPhi) {
           return;
         }
 
diff --git a/source/fuzz/fuzzer_pass_push_ids_through_variables.cpp b/source/fuzz/fuzzer_pass_push_ids_through_variables.cpp
index a6c07b4..c0397e1 100644
--- a/source/fuzz/fuzzer_pass_push_ids_through_variables.cpp
+++ b/source/fuzz/fuzzer_pass_push_ids_through_variables.cpp
@@ -35,10 +35,11 @@
              opt::BasicBlock::iterator instruction_iterator,
              const protobufs::InstructionDescriptor& instruction_descriptor)
           -> void {
-        assert(instruction_iterator->opcode() ==
-                   instruction_descriptor.target_instruction_opcode() &&
-               "The opcode of the instruction we might insert before must be "
-               "the same as the opcode in the descriptor for the instruction");
+        assert(
+            instruction_iterator->opcode() ==
+                spv::Op(instruction_descriptor.target_instruction_opcode()) &&
+            "The opcode of the instruction we might insert before must be "
+            "the same as the opcode in the descriptor for the instruction");
 
         // Randomly decide whether to try pushing an id through a variable.
         if (!GetFuzzerContext()->ChoosePercentage(
@@ -55,16 +56,16 @@
         // It must be valid to insert OpStore and OpLoad instructions
         // before the instruction to insert before.
         if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
-                SpvOpStore, instruction_iterator) ||
+                spv::Op::OpStore, instruction_iterator) ||
             !fuzzerutil::CanInsertOpcodeBeforeInstruction(
-                SpvOpLoad, instruction_iterator)) {
+                spv::Op::OpLoad, instruction_iterator)) {
           return;
         }
 
         // Randomly decides whether a global or local variable will be added.
         auto variable_storage_class = GetFuzzerContext()->ChooseEven()
-                                          ? SpvStorageClassPrivate
-                                          : SpvStorageClassFunction;
+                                          ? spv::StorageClass::Private
+                                          : spv::StorageClass::Function;
 
         // Gets the available basic and pointer types.
         auto basic_type_ids_and_pointers =
@@ -127,13 +128,13 @@
             GetIRContext()->get_def_use_mgr()->GetDef(basic_type_id);
         assert(type_inst);
         switch (type_inst->opcode()) {
-          case SpvOpTypeBool:
-          case SpvOpTypeFloat:
-          case SpvOpTypeInt:
-          case SpvOpTypeArray:
-          case SpvOpTypeMatrix:
-          case SpvOpTypeVector:
-          case SpvOpTypeStruct:
+          case spv::Op::OpTypeBool:
+          case spv::Op::OpTypeFloat:
+          case spv::Op::OpTypeInt:
+          case spv::Op::OpTypeArray:
+          case spv::Op::OpTypeMatrix:
+          case spv::Op::OpTypeVector:
+          case spv::Op::OpTypeStruct:
             break;
           default:
             return;
@@ -150,7 +151,8 @@
                                    value_instructions)]
                 ->result_id(),
             GetFuzzerContext()->GetFreshId(), GetFuzzerContext()->GetFreshId(),
-            variable_storage_class, initializer_id, instruction_descriptor));
+            uint32_t(variable_storage_class), initializer_id,
+            instruction_descriptor));
       });
 }
 
diff --git a/source/fuzz/fuzzer_pass_replace_branches_from_dead_blocks_with_exits.cpp b/source/fuzz/fuzzer_pass_replace_branches_from_dead_blocks_with_exits.cpp
index 995657c..52c0381 100644
--- a/source/fuzz/fuzzer_pass_replace_branches_from_dead_blocks_with_exits.cpp
+++ b/source/fuzz/fuzzer_pass_replace_branches_from_dead_blocks_with_exits.cpp
@@ -38,13 +38,13 @@
   // to be executed with the Fragment execution model.  We conservatively only
   // allow OpKill if every entry point in the module has the Fragment execution
   // model.
-  auto fragment_execution_model_guaranteed =
-      std::all_of(GetIRContext()->module()->entry_points().begin(),
-                  GetIRContext()->module()->entry_points().end(),
-                  [](const opt::Instruction& entry_point) -> bool {
-                    return entry_point.GetSingleWordInOperand(0) ==
-                           SpvExecutionModelFragment;
-                  });
+  auto fragment_execution_model_guaranteed = std::all_of(
+      GetIRContext()->module()->entry_points().begin(),
+      GetIRContext()->module()->entry_points().end(),
+      [](const opt::Instruction& entry_point) -> bool {
+        return spv::ExecutionModel(entry_point.GetSingleWordInOperand(0)) ==
+               spv::ExecutionModel::Fragment;
+      });
 
   // Transformations of this type can disable one another.  To avoid ordering
   // bias, we therefore build a set of candidate transformations to apply, and
@@ -71,20 +71,20 @@
       // Whether we can use OpKill depends on the execution model, and which of
       // OpReturn and OpReturnValue we can use depends on the return type of the
       // enclosing function.
-      std::vector<SpvOp> opcodes = {SpvOpUnreachable};
+      std::vector<spv::Op> opcodes = {spv::Op::OpUnreachable};
       if (fragment_execution_model_guaranteed) {
-        opcodes.emplace_back(SpvOpKill);
+        opcodes.emplace_back(spv::Op::OpKill);
       }
       auto function_return_type =
           GetIRContext()->get_type_mgr()->GetType(function.type_id());
       if (function_return_type->AsVoid()) {
-        opcodes.emplace_back(SpvOpReturn);
+        opcodes.emplace_back(spv::Op::OpReturn);
       } else if (fuzzerutil::CanCreateConstant(GetIRContext(),
                                                function.type_id())) {
         // For simplicity we only allow OpReturnValue if the function return
         // type is a type for which we can create a constant.  This allows us a
         // zero of the given type as a default return value.
-        opcodes.emplace_back(SpvOpReturnValue);
+        opcodes.emplace_back(spv::Op::OpReturnValue);
       }
       // Choose one of the available terminator opcodes at random and create a
       // candidate transformation.
@@ -92,7 +92,7 @@
       candidate_transformations.emplace_back(
           TransformationReplaceBranchFromDeadBlockWithExit(
               block.id(), opcode,
-              opcode == SpvOpReturnValue
+              opcode == spv::Op::OpReturnValue
                   ? FindOrCreateZeroConstant(function.type_id(), true)
                   : 0));
     }
diff --git a/source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.cpp b/source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.cpp
index af1aace..aabc6bc 100644
--- a/source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.cpp
+++ b/source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.cpp
@@ -41,7 +41,7 @@
     }
 
     // The instruction must be OpCopyMemory.
-    if (instruction->opcode() != SpvOpCopyMemory) {
+    if (instruction->opcode() != spv::Op::OpCopyMemory) {
       return;
     }
 
diff --git a/source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.cpp b/source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.cpp
index d0992a3..c1892be 100644
--- a/source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.cpp
+++ b/source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.cpp
@@ -40,7 +40,7 @@
       return;
     }
     // The instruction must be OpCopyObject.
-    if (instruction->opcode() != SpvOpCopyObject) {
+    if (instruction->opcode() != spv::Op::OpCopyObject) {
       return;
     }
     // The opcode of the type_id instruction cannot be a OpTypePointer,
@@ -48,21 +48,22 @@
     if (GetIRContext()
             ->get_def_use_mgr()
             ->GetDef(instruction->type_id())
-            ->opcode() == SpvOpTypePointer) {
+            ->opcode() == spv::Op::OpTypePointer) {
       return;
     }
     // It must be valid to insert OpStore and OpLoad instructions
     // before the instruction OpCopyObject.
-    if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpStore,
+    if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpStore,
                                                       instruction) ||
-        !fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLoad, instruction)) {
+        !fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpLoad,
+                                                      instruction)) {
       return;
     }
 
     // Randomly decides whether a global or local variable will be added.
     auto variable_storage_class = GetFuzzerContext()->ChooseEven()
-                                      ? SpvStorageClassPrivate
-                                      : SpvStorageClassFunction;
+                                      ? spv::StorageClass::Private
+                                      : spv::StorageClass::Function;
 
     // Find or create a constant to initialize the variable from. The type of
     // |instruction| must be such that the function FindOrCreateConstant can be
@@ -79,7 +80,7 @@
     // Apply the transformation replacing OpCopyObject with Store and Load.
     ApplyTransformation(TransformationReplaceCopyObjectWithStoreLoad(
         instruction->result_id(), GetFuzzerContext()->GetFreshId(),
-        variable_storage_class, variable_initializer_id));
+        uint32_t(variable_storage_class), variable_initializer_id));
   });
 }
 
diff --git a/source/fuzz/fuzzer_pass_replace_irrelevant_ids.cpp b/source/fuzz/fuzzer_pass_replace_irrelevant_ids.cpp
index 4d55ae8..4c0bd85 100644
--- a/source/fuzz/fuzzer_pass_replace_irrelevant_ids.cpp
+++ b/source/fuzz/fuzzer_pass_replace_irrelevant_ids.cpp
@@ -73,7 +73,7 @@
   // we cannot use these as replacements.
   for (const auto& pair : GetIRContext()->get_def_use_mgr()->id_to_defs()) {
     uint32_t type_id = pair.second->type_id();
-    if (pair.second->opcode() != SpvOpFunction && type_id &&
+    if (pair.second->opcode() != spv::Op::OpFunction && type_id &&
         types_to_ids.count(type_id)) {
       types_to_ids[type_id].push_back(pair.first);
     }
diff --git a/source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.cpp b/source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.cpp
index 38ac048..8d292ac 100644
--- a/source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.cpp
+++ b/source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.cpp
@@ -50,9 +50,9 @@
       std::unordered_map<uint32_t, opt::Instruction*> current_op_loads;
       for (auto& instruction : block) {
         // Add a potential OpLoad instruction.
-        if (instruction.opcode() == SpvOpLoad) {
+        if (instruction.opcode() == spv::Op::OpLoad) {
           current_op_loads[instruction.result_id()] = &instruction;
-        } else if (instruction.opcode() == SpvOpStore) {
+        } else if (instruction.opcode() == spv::Op::OpStore) {
           if (current_op_loads.find(instruction.GetSingleWordOperand(1)) !=
               current_op_loads.end()) {
             // We have found the matching OpLoad instruction to the current
@@ -73,7 +73,7 @@
             opt::Instruction* source_id =
                 GetIRContext()->get_def_use_mgr()->GetDef(
                     it->second->GetSingleWordOperand(2));
-            SpvStorageClass storage_class =
+            spv::StorageClass storage_class =
                 fuzzerutil::GetStorageClassFromPointerType(
                     GetIRContext(), source_id->type_id());
             if (!TransformationReplaceLoadStoreWithCopyMemory::
diff --git a/source/fuzz/fuzzer_pass_replace_opphi_ids_from_dead_predecessors.cpp b/source/fuzz/fuzzer_pass_replace_opphi_ids_from_dead_predecessors.cpp
index ea90a7a..26475ab 100644
--- a/source/fuzz/fuzzer_pass_replace_opphi_ids_from_dead_predecessors.cpp
+++ b/source/fuzz/fuzzer_pass_replace_opphi_ids_from_dead_predecessors.cpp
@@ -50,7 +50,7 @@
               block->id(), [this, &function, block, &transformations](
                                opt::Instruction* instruction, uint32_t) {
                 // Only consider OpPhi instructions.
-                if (instruction->opcode() != SpvOpPhi) {
+                if (instruction->opcode() != spv::Op::OpPhi) {
                   return;
                 }
 
diff --git a/source/fuzz/fuzzer_pass_replace_opselects_with_conditional_branches.cpp b/source/fuzz/fuzzer_pass_replace_opselects_with_conditional_branches.cpp
index 72ed093..4691e0a 100644
--- a/source/fuzz/fuzzer_pass_replace_opselects_with_conditional_branches.cpp
+++ b/source/fuzz/fuzzer_pass_replace_opselects_with_conditional_branches.cpp
@@ -52,7 +52,7 @@
 
       for (auto& instruction : block) {
         // We only care about OpSelect instructions.
-        if (instruction.opcode() != SpvOpSelect) {
+        if (instruction.opcode() != spv::Op::OpSelect) {
           continue;
         }
 
@@ -69,7 +69,7 @@
                 ->get_def_use_mgr()
                 ->GetDef(fuzzerutil::GetTypeId(
                     GetIRContext(), instruction.GetSingleWordInOperand(0)))
-                ->opcode() != SpvOpTypeBool) {
+                ->opcode() != spv::Op::OpTypeBool) {
           continue;
         }
 
@@ -136,7 +136,7 @@
 
 bool FuzzerPassReplaceOpSelectsWithConditionalBranches::
     InstructionNeedsSplitBefore(opt::Instruction* instruction) {
-  assert(instruction && instruction->opcode() == SpvOpSelect &&
+  assert(instruction && instruction->opcode() == spv::Op::OpSelect &&
          "The instruction must be OpSelect.");
 
   auto block = GetIRContext()->get_instr_block(instruction);
@@ -163,7 +163,7 @@
   auto predecessor = GetIRContext()->get_instr_block(
       GetIRContext()->cfg()->preds(block->id())[0]);
   return predecessor->MergeBlockIdIfAny() ||
-         predecessor->terminator()->opcode() != SpvOpBranch;
+         predecessor->terminator()->opcode() != spv::Op::OpBranch;
 }
 
 }  // namespace fuzz
diff --git a/source/fuzz/fuzzer_pass_replace_parameter_with_global.cpp b/source/fuzz/fuzzer_pass_replace_parameter_with_global.cpp
index 7fb7b0d..d7eddca 100644
--- a/source/fuzz/fuzzer_pass_replace_parameter_with_global.cpp
+++ b/source/fuzz/fuzzer_pass_replace_parameter_with_global.cpp
@@ -72,7 +72,8 @@
     assert(replaced_param && "Unable to find a parameter to replace");
 
     // Make sure type id for the global variable exists in the module.
-    FindOrCreatePointerType(replaced_param->type_id(), SpvStorageClassPrivate);
+    FindOrCreatePointerType(replaced_param->type_id(),
+                            spv::StorageClass::Private);
 
     // Make sure initializer for the global variable exists in the module.
     FindOrCreateZeroConstant(replaced_param->type_id(), false);
diff --git a/source/fuzz/fuzzer_pass_split_blocks.cpp b/source/fuzz/fuzzer_pass_split_blocks.cpp
index 40a4151..5b4afcc 100644
--- a/source/fuzz/fuzzer_pass_split_blocks.cpp
+++ b/source/fuzz/fuzzer_pass_split_blocks.cpp
@@ -65,7 +65,7 @@
 
     // Counts the number of times we have seen each opcode since we reset the
     // base instruction.
-    std::map<SpvOp, uint32_t> skip_count;
+    std::map<spv::Op, uint32_t> skip_count;
 
     // Consider every instruction in the block.  The label is excluded: it is
     // only necessary to consider it as a base in case the first instruction
@@ -78,7 +78,7 @@
         base = inst.result_id();
         skip_count.clear();
       }
-      const SpvOp opcode = inst.opcode();
+      const spv::Op opcode = inst.opcode();
       instruction_descriptors.emplace_back(MakeInstructionDescriptor(
           base, opcode, skip_count.count(opcode) ? skip_count.at(opcode) : 0));
       if (!inst.HasResultId()) {
diff --git a/source/fuzz/fuzzer_pass_swap_conditional_branch_operands.cpp b/source/fuzz/fuzzer_pass_swap_conditional_branch_operands.cpp
index f8bf111..72c8358 100644
--- a/source/fuzz/fuzzer_pass_swap_conditional_branch_operands.cpp
+++ b/source/fuzz/fuzzer_pass_swap_conditional_branch_operands.cpp
@@ -39,7 +39,7 @@
              const protobufs::InstructionDescriptor& instruction_descriptor) {
         const auto& inst = *inst_it;
 
-        if (inst.opcode() != SpvOpBranchConditional) {
+        if (inst.opcode() != spv::Op::OpBranchConditional) {
           return;
         }
 
diff --git a/source/fuzz/fuzzer_pass_toggle_access_chain_instruction.cpp b/source/fuzz/fuzzer_pass_toggle_access_chain_instruction.cpp
index ac2b156..2a1ad6e 100644
--- a/source/fuzz/fuzzer_pass_toggle_access_chain_instruction.cpp
+++ b/source/fuzz/fuzzer_pass_toggle_access_chain_instruction.cpp
@@ -36,8 +36,9 @@
   // probabilistically applied.
   context->module()->ForEachInst([this,
                                   context](opt::Instruction* instruction) {
-    SpvOp opcode = instruction->opcode();
-    if ((opcode == SpvOpAccessChain || opcode == SpvOpInBoundsAccessChain) &&
+    spv::Op opcode = instruction->opcode();
+    if ((opcode == spv::Op::OpAccessChain ||
+         opcode == spv::Op::OpInBoundsAccessChain) &&
         GetFuzzerContext()->ChoosePercentage(
             GetFuzzerContext()->GetChanceOfTogglingAccessChainInstruction())) {
       auto instructionDescriptor =
diff --git a/source/fuzz/fuzzer_pass_wrap_vector_synonym.cpp b/source/fuzz/fuzzer_pass_wrap_vector_synonym.cpp
index 35adcfe..55fbe2c 100644
--- a/source/fuzz/fuzzer_pass_wrap_vector_synonym.cpp
+++ b/source/fuzz/fuzzer_pass_wrap_vector_synonym.cpp
@@ -52,7 +52,7 @@
         // It must be valid to insert an OpCompositeConstruct instruction
         // before |instruction_iterator|.
         if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
-                SpvOpCompositeConstruct, instruction_iterator)) {
+                spv::Op::OpCompositeConstruct, instruction_iterator)) {
           return;
         }
 
diff --git a/source/fuzz/fuzzer_util.cpp b/source/fuzz/fuzzer_util.cpp
index 1d368a9..e85ff2f 100644
--- a/source/fuzz/fuzzer_util.cpp
+++ b/source/fuzz/fuzzer_util.cpp
@@ -49,7 +49,7 @@
                             const std::vector<uint32_t>& words,
                             uint32_t type_id, bool is_irrelevant) {
   for (const auto& inst : ir_context->types_values()) {
-    if (inst.opcode() == SpvOpConstant && inst.type_id() == type_id &&
+    if (inst.opcode() == spv::Op::OpConstant && inst.type_id() == type_id &&
         inst.GetInOperand(0).words == words &&
         transformation_context.GetFactManager()->IdIsIrrelevant(
             inst.result_id()) == is_irrelevant) {
@@ -112,7 +112,7 @@
     // No instruction defining this id was found.
     return nullptr;
   }
-  if (inst->opcode() != SpvOpLabel) {
+  if (inst->opcode() != spv::Op::OpLabel) {
     // The instruction defining the id is not a label, so it cannot be a block
     // id.
     return nullptr;
@@ -138,7 +138,7 @@
   // makes sense here because we need to increment |phi_index| for each OpPhi
   // instruction.
   for (auto& inst : *bb_to) {
-    if (inst.opcode() != SpvOpPhi) {
+    if (inst.opcode() != spv::Op::OpPhi) {
       // The OpPhi instructions all occur at the start of the block; if we find
       // a non-OpPhi then we have seen them all.
       break;
@@ -189,24 +189,24 @@
   const auto* bb_from = MaybeFindBlock(ir_context, bb_from_id);
   assert(bb_from && "|bb_from_id| is invalid");
   assert(MaybeFindBlock(ir_context, bb_to_id) && "|bb_to_id| is invalid");
-  assert(bb_from->terminator()->opcode() == SpvOpBranch &&
+  assert(bb_from->terminator()->opcode() == spv::Op::OpBranch &&
          "Precondition on terminator of bb_from is not satisfied");
 
   // Get the id of the boolean constant to be used as the condition.
   auto condition_inst = ir_context->get_def_use_mgr()->GetDef(bool_id);
   assert(condition_inst &&
-         (condition_inst->opcode() == SpvOpConstantTrue ||
-          condition_inst->opcode() == SpvOpConstantFalse) &&
+         (condition_inst->opcode() == spv::Op::OpConstantTrue ||
+          condition_inst->opcode() == spv::Op::OpConstantFalse) &&
          "|bool_id| is invalid");
 
-  auto condition_value = condition_inst->opcode() == SpvOpConstantTrue;
+  auto condition_value = condition_inst->opcode() == spv::Op::OpConstantTrue;
   auto successor_id = bb_from->terminator()->GetSingleWordInOperand(0);
 
   // Add the dead branch, by turning OpBranch into OpBranchConditional, and
   // ordering the targets depending on whether the given boolean corresponds to
   // true or false.
   return opt::Instruction(
-      ir_context, SpvOpBranchConditional, 0, 0,
+      ir_context, spv::Op::OpBranchConditional, 0, 0,
       {{SPV_OPERAND_TYPE_ID, {bool_id}},
        {SPV_OPERAND_TYPE_ID, {condition_value ? successor_id : bb_to_id}},
        {SPV_OPERAND_TYPE_ID, {condition_value ? bb_to_id : successor_id}}});
@@ -228,7 +228,7 @@
   if (!from_to_edge_already_exists) {
     uint32_t phi_index = 0;
     for (auto& inst : *bb_to) {
-      if (inst.opcode() != SpvOpPhi) {
+      if (inst.opcode() != spv::Op::OpPhi) {
         break;
       }
       assert(phi_index < static_cast<uint32_t>(phi_ids.size()) &&
@@ -285,28 +285,30 @@
 }
 
 bool CanInsertOpcodeBeforeInstruction(
-    SpvOp opcode, const opt::BasicBlock::iterator& instruction_in_block) {
+    spv::Op opcode, const opt::BasicBlock::iterator& instruction_in_block) {
   if (instruction_in_block->PreviousNode() &&
-      (instruction_in_block->PreviousNode()->opcode() == SpvOpLoopMerge ||
-       instruction_in_block->PreviousNode()->opcode() == SpvOpSelectionMerge)) {
+      (instruction_in_block->PreviousNode()->opcode() == spv::Op::OpLoopMerge ||
+       instruction_in_block->PreviousNode()->opcode() ==
+           spv::Op::OpSelectionMerge)) {
     // We cannot insert directly after a merge instruction.
     return false;
   }
-  if (opcode != SpvOpVariable &&
-      instruction_in_block->opcode() == SpvOpVariable) {
+  if (opcode != spv::Op::OpVariable &&
+      instruction_in_block->opcode() == spv::Op::OpVariable) {
     // We cannot insert a non-OpVariable instruction directly before a
     // variable; variables in a function must be contiguous in the entry block.
     return false;
   }
   // We cannot insert a non-OpPhi instruction directly before an OpPhi, because
   // OpPhi instructions need to be contiguous at the start of a block.
-  return opcode == SpvOpPhi || instruction_in_block->opcode() != SpvOpPhi;
+  return opcode == spv::Op::OpPhi ||
+         instruction_in_block->opcode() != spv::Op::OpPhi;
 }
 
 bool CanMakeSynonymOf(opt::IRContext* ir_context,
                       const TransformationContext& transformation_context,
                       const opt::Instruction& inst) {
-  if (inst.opcode() == SpvOpSampledImage) {
+  if (inst.opcode() == spv::Op::OpSampledImage) {
     // The SPIR-V data rules say that only very specific instructions may
     // may consume the result id of an OpSampledImage, and this excludes the
     // instructions that are used for making synonyms.
@@ -326,15 +328,15 @@
     return false;
   }
   auto type_inst = ir_context->get_def_use_mgr()->GetDef(inst.type_id());
-  if (type_inst->opcode() == SpvOpTypeVoid) {
+  if (type_inst->opcode() == spv::Op::OpTypeVoid) {
     // We only make synonyms of instructions that define objects, and an object
     // cannot have void type.
     return false;
   }
-  if (type_inst->opcode() == SpvOpTypePointer) {
+  if (type_inst->opcode() == spv::Op::OpTypePointer) {
     switch (inst.opcode()) {
-      case SpvOpConstantNull:
-      case SpvOpUndef:
+      case spv::Op::OpConstantNull:
+      case spv::Op::OpUndef:
         // We disallow making synonyms of null or undefined pointers.  This is
         // to provide the property that if the original shader exhibited no bad
         // pointer accesses, the transformed shader will not either.
@@ -373,22 +375,22 @@
       context->get_def_use_mgr()->GetDef(base_object_type_id);
   assert(should_be_composite_type && "The type should exist.");
   switch (should_be_composite_type->opcode()) {
-    case SpvOpTypeArray: {
+    case spv::Op::OpTypeArray: {
       auto array_length = GetArraySize(*should_be_composite_type, context);
       if (array_length == 0 || index >= array_length) {
         return 0;
       }
       return should_be_composite_type->GetSingleWordInOperand(0);
     }
-    case SpvOpTypeMatrix:
-    case SpvOpTypeVector: {
+    case spv::Op::OpTypeMatrix:
+    case spv::Op::OpTypeVector: {
       auto count = should_be_composite_type->GetSingleWordInOperand(1);
       if (index >= count) {
         return 0;
       }
       return should_be_composite_type->GetSingleWordInOperand(0);
     }
-    case SpvOpTypeStruct: {
+    case spv::Op::OpTypeStruct: {
       if (index >= GetNumberOfStructMembers(*should_be_composite_type)) {
         return 0;
       }
@@ -415,7 +417,7 @@
 
 uint32_t GetNumberOfStructMembers(
     const opt::Instruction& struct_type_instruction) {
-  assert(struct_type_instruction.opcode() == SpvOpTypeStruct &&
+  assert(struct_type_instruction.opcode() == spv::Op::OpTypeStruct &&
          "An OpTypeStruct instruction is required here.");
   return struct_type_instruction.NumInOperands();
 }
@@ -436,15 +438,15 @@
 uint32_t GetBoundForCompositeIndex(const opt::Instruction& composite_type_inst,
                                    opt::IRContext* ir_context) {
   switch (composite_type_inst.opcode()) {
-    case SpvOpTypeArray:
+    case spv::Op::OpTypeArray:
       return fuzzerutil::GetArraySize(composite_type_inst, ir_context);
-    case SpvOpTypeMatrix:
-    case SpvOpTypeVector:
+    case spv::Op::OpTypeMatrix:
+    case spv::Op::OpTypeVector:
       return composite_type_inst.GetSingleWordInOperand(1);
-    case SpvOpTypeStruct: {
+    case spv::Op::OpTypeStruct: {
       return fuzzerutil::GetNumberOfStructMembers(composite_type_inst);
     }
-    case SpvOpTypeRuntimeArray:
+    case spv::Op::OpTypeRuntimeArray:
       assert(false &&
              "GetBoundForCompositeIndex should not be invoked with an "
              "OpTypeRuntimeArray, which does not have a static bound.");
@@ -455,27 +457,27 @@
   }
 }
 
-SpvMemorySemanticsMask GetMemorySemanticsForStorageClass(
-    SpvStorageClass storage_class) {
+spv::MemorySemanticsMask GetMemorySemanticsForStorageClass(
+    spv::StorageClass storage_class) {
   switch (storage_class) {
-    case SpvStorageClassWorkgroup:
-      return SpvMemorySemanticsWorkgroupMemoryMask;
+    case spv::StorageClass::Workgroup:
+      return spv::MemorySemanticsMask::WorkgroupMemory;
 
-    case SpvStorageClassStorageBuffer:
-    case SpvStorageClassPhysicalStorageBuffer:
-      return SpvMemorySemanticsUniformMemoryMask;
+    case spv::StorageClass::StorageBuffer:
+    case spv::StorageClass::PhysicalStorageBuffer:
+      return spv::MemorySemanticsMask::UniformMemory;
 
-    case SpvStorageClassCrossWorkgroup:
-      return SpvMemorySemanticsCrossWorkgroupMemoryMask;
+    case spv::StorageClass::CrossWorkgroup:
+      return spv::MemorySemanticsMask::CrossWorkgroupMemory;
 
-    case SpvStorageClassAtomicCounter:
-      return SpvMemorySemanticsAtomicCounterMemoryMask;
+    case spv::StorageClass::AtomicCounter:
+      return spv::MemorySemanticsMask::AtomicCounterMemory;
 
-    case SpvStorageClassImage:
-      return SpvMemorySemanticsImageMemoryMask;
+    case spv::StorageClass::Image:
+      return spv::MemorySemanticsMask::ImageMemory;
 
     default:
-      return SpvMemorySemanticsMaskNone;
+      return spv::MemorySemanticsMask::MaskNone;
   }
 }
 
@@ -562,8 +564,8 @@
       [&result](const opt::Instruction* use_instruction,
                 uint32_t /*unused*/) -> bool {
         switch (use_instruction->opcode()) {
-          case SpvOpLoopMerge:
-          case SpvOpSelectionMerge:
+          case spv::Op::OpLoopMerge:
+          case spv::Op::OpSelectionMerge:
             result = true;
             return false;
           default:
@@ -581,7 +583,7 @@
       [ir_context, &result](opt::Instruction* use_instruction,
                             uint32_t use_index) -> bool {
         switch (use_instruction->opcode()) {
-          case SpvOpLoopMerge:
+          case spv::Op::OpLoopMerge:
             // The merge block operand is the first operand in OpLoopMerge.
             if (use_index == 0) {
               result = ir_context->get_instr_block(use_instruction)->id();
@@ -599,7 +601,7 @@
                           const std::vector<uint32_t>& type_ids) {
   // Look through the existing types for a match.
   for (auto& type_or_value : ir_context->types_values()) {
-    if (type_or_value.opcode() != SpvOpTypeFunction) {
+    if (type_or_value.opcode() != spv::Op::OpTypeFunction) {
       // We are only interested in function types.
       continue;
     }
@@ -641,8 +643,8 @@
 
 bool FunctionContainsOpKillOrUnreachable(const opt::Function& function) {
   for (auto& block : function) {
-    if (block.terminator()->opcode() == SpvOpKill ||
-        block.terminator()->opcode() == SpvOpUnreachable) {
+    if (block.terminator()->opcode() == spv::Op::OpKill ||
+        block.terminator()->opcode() == spv::Op::OpUnreachable) {
       return true;
     }
   }
@@ -669,7 +671,7 @@
       context->get_instr_block(use_instruction)->GetParent();
   // If the id a function parameter, it needs to be associated with the
   // function containing the use.
-  if (defining_instruction->opcode() == SpvOpFunctionParameter) {
+  if (defining_instruction->opcode() == spv::Op::OpFunctionParameter) {
     return InstructionIsFunctionParameter(defining_instruction,
                                           enclosing_function);
   }
@@ -687,7 +689,7 @@
     return false;
   }
   auto dominator_analysis = context->GetDominatorAnalysis(enclosing_function);
-  if (use_instruction->opcode() == SpvOpPhi) {
+  if (use_instruction->opcode() == spv::Op::OpPhi) {
     // In the case where the use is an operand to OpPhi, it is actually the
     // *parent* block associated with the operand that must be dominated by
     // the synonym.
@@ -710,7 +712,7 @@
       context->get_instr_block(instruction)->GetParent();
   // If the id a function parameter, it needs to be associated with the
   // function containing the instruction.
-  if (id_definition->opcode() == SpvOpFunctionParameter) {
+  if (id_definition->opcode() == spv::Op::OpFunctionParameter) {
     return InstructionIsFunctionParameter(id_definition,
                                           function_enclosing_instruction);
   }
@@ -732,7 +734,7 @@
     // the instruction.
     return true;
   }
-  if (id_definition->opcode() == SpvOpVariable &&
+  if (id_definition->opcode() == spv::Op::OpVariable &&
       function_enclosing_instruction ==
           context->get_instr_block(id)->GetParent()) {
     assert(!context->IsReachable(*context->get_instr_block(instruction)) &&
@@ -747,7 +749,7 @@
 
 bool InstructionIsFunctionParameter(opt::Instruction* instruction,
                                     opt::Function* function) {
-  if (instruction->opcode() != SpvOpFunctionParameter) {
+  if (instruction->opcode() != spv::Op::OpFunctionParameter) {
     return false;
   }
   bool found_parameter = false;
@@ -767,7 +769,8 @@
 }
 
 uint32_t GetPointeeTypeIdFromPointerType(opt::Instruction* pointer_type_inst) {
-  assert(pointer_type_inst && pointer_type_inst->opcode() == SpvOpTypePointer &&
+  assert(pointer_type_inst &&
+         pointer_type_inst->opcode() == spv::Op::OpTypePointer &&
          "Precondition: |pointer_type_inst| must be OpTypePointer.");
   return pointer_type_inst->GetSingleWordInOperand(1);
 }
@@ -778,26 +781,28 @@
       context->get_def_use_mgr()->GetDef(pointer_type_id));
 }
 
-SpvStorageClass GetStorageClassFromPointerType(
+spv::StorageClass GetStorageClassFromPointerType(
     opt::Instruction* pointer_type_inst) {
-  assert(pointer_type_inst && pointer_type_inst->opcode() == SpvOpTypePointer &&
+  assert(pointer_type_inst &&
+         pointer_type_inst->opcode() == spv::Op::OpTypePointer &&
          "Precondition: |pointer_type_inst| must be OpTypePointer.");
-  return static_cast<SpvStorageClass>(
+  return static_cast<spv::StorageClass>(
       pointer_type_inst->GetSingleWordInOperand(0));
 }
 
-SpvStorageClass GetStorageClassFromPointerType(opt::IRContext* context,
-                                               uint32_t pointer_type_id) {
+spv::StorageClass GetStorageClassFromPointerType(opt::IRContext* context,
+                                                 uint32_t pointer_type_id) {
   return GetStorageClassFromPointerType(
       context->get_def_use_mgr()->GetDef(pointer_type_id));
 }
 
 uint32_t MaybeGetPointerType(opt::IRContext* context, uint32_t pointee_type_id,
-                             SpvStorageClass storage_class) {
+                             spv::StorageClass storage_class) {
   for (auto& inst : context->types_values()) {
     switch (inst.opcode()) {
-      case SpvOpTypePointer:
-        if (inst.GetSingleWordInOperand(0) == storage_class &&
+      case spv::Op::OpTypePointer:
+        if (spv::StorageClass(inst.GetSingleWordInOperand(0)) ==
+                storage_class &&
             inst.GetSingleWordInOperand(1) == pointee_type_id) {
           return inst.result_id();
         }
@@ -818,30 +823,30 @@
 bool IsNullConstantSupported(opt::IRContext* ir_context,
                              const opt::Instruction& type_inst) {
   switch (type_inst.opcode()) {
-    case SpvOpTypeArray:
-    case SpvOpTypeBool:
-    case SpvOpTypeDeviceEvent:
-    case SpvOpTypeEvent:
-    case SpvOpTypeFloat:
-    case SpvOpTypeInt:
-    case SpvOpTypeMatrix:
-    case SpvOpTypeQueue:
-    case SpvOpTypeReserveId:
-    case SpvOpTypeVector:
-    case SpvOpTypeStruct:
+    case spv::Op::OpTypeArray:
+    case spv::Op::OpTypeBool:
+    case spv::Op::OpTypeDeviceEvent:
+    case spv::Op::OpTypeEvent:
+    case spv::Op::OpTypeFloat:
+    case spv::Op::OpTypeInt:
+    case spv::Op::OpTypeMatrix:
+    case spv::Op::OpTypeQueue:
+    case spv::Op::OpTypeReserveId:
+    case spv::Op::OpTypeVector:
+    case spv::Op::OpTypeStruct:
       return true;
-    case SpvOpTypePointer:
+    case spv::Op::OpTypePointer:
       // Null pointers are allowed if the VariablePointers capability is
       // enabled, or if the VariablePointersStorageBuffer capability is enabled
       // and the pointer type has StorageBuffer as its storage class.
       if (ir_context->get_feature_mgr()->HasCapability(
-              SpvCapabilityVariablePointers)) {
+              spv::Capability::VariablePointers)) {
         return true;
       }
       if (ir_context->get_feature_mgr()->HasCapability(
-              SpvCapabilityVariablePointersStorageBuffer)) {
-        return type_inst.GetSingleWordInOperand(0) ==
-               SpvStorageClassStorageBuffer;
+              spv::Capability::VariablePointersStorageBuffer)) {
+        return spv::StorageClass(type_inst.GetSingleWordInOperand(0)) ==
+               spv::StorageClass::StorageBuffer;
       }
       return false;
     default:
@@ -885,22 +890,22 @@
 
 opt::Instruction* AddGlobalVariable(opt::IRContext* context, uint32_t result_id,
                                     uint32_t type_id,
-                                    SpvStorageClass storage_class,
+                                    spv::StorageClass storage_class,
                                     uint32_t initializer_id) {
   // Check various preconditions.
   assert(result_id != 0 && "Result id can't be 0");
 
-  assert((storage_class == SpvStorageClassPrivate ||
-          storage_class == SpvStorageClassWorkgroup) &&
+  assert((storage_class == spv::StorageClass::Private ||
+          storage_class == spv::StorageClass::Workgroup) &&
          "Variable's storage class must be either Private or Workgroup");
 
   auto* type_inst = context->get_def_use_mgr()->GetDef(type_id);
   (void)type_inst;  // Variable becomes unused in release mode.
-  assert(type_inst && type_inst->opcode() == SpvOpTypePointer &&
+  assert(type_inst && type_inst->opcode() == spv::Op::OpTypePointer &&
          GetStorageClassFromPointerType(type_inst) == storage_class &&
          "Variable's type is invalid");
 
-  if (storage_class == SpvStorageClassWorkgroup) {
+  if (storage_class == spv::StorageClass::Workgroup) {
     assert(initializer_id == 0);
   }
 
@@ -922,7 +927,7 @@
   }
 
   auto new_instruction = MakeUnique<opt::Instruction>(
-      context, SpvOpVariable, type_id, result_id, std::move(operands));
+      context, spv::Op::OpVariable, type_id, result_id, std::move(operands));
   auto result = new_instruction.get();
   context->module()->AddGlobalValue(std::move(new_instruction));
 
@@ -940,8 +945,9 @@
 
   auto* type_inst = context->get_def_use_mgr()->GetDef(type_id);
   (void)type_inst;  // Variable becomes unused in release mode.
-  assert(type_inst && type_inst->opcode() == SpvOpTypePointer &&
-         GetStorageClassFromPointerType(type_inst) == SpvStorageClassFunction &&
+  assert(type_inst && type_inst->opcode() == spv::Op::OpTypePointer &&
+         GetStorageClassFromPointerType(type_inst) ==
+             spv::StorageClass::Function &&
          "Variable's type is invalid");
 
   const auto* constant_inst =
@@ -956,10 +962,10 @@
   assert(function && "Function id is invalid");
 
   auto new_instruction = MakeUnique<opt::Instruction>(
-      context, SpvOpVariable, type_id, result_id,
-      opt::Instruction::OperandList{
-          {SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassFunction}},
-          {SPV_OPERAND_TYPE_ID, {initializer_id}}});
+      context, spv::Op::OpVariable, type_id, result_id,
+      opt::Instruction::OperandList{{SPV_OPERAND_TYPE_STORAGE_CLASS,
+                                     {uint32_t(spv::StorageClass::Function)}},
+                                    {SPV_OPERAND_TYPE_ID, {initializer_id}}});
   auto result = new_instruction.get();
   function->begin()->begin()->InsertBefore(std::move(new_instruction));
 
@@ -1022,7 +1028,7 @@
   std::vector<opt::Instruction*> result;
   ir_context->get_def_use_mgr()->ForEachUser(
       function_id, [&result, function_id](opt::Instruction* inst) {
-        if (inst->opcode() == SpvOpFunctionCall &&
+        if (inst->opcode() == spv::Op::OpFunctionCall &&
             inst->GetSingleWordInOperand(0) == function_id) {
           result.push_back(inst);
         }
@@ -1137,7 +1143,7 @@
   }
 
   ir_context->AddType(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpTypeFunction, 0, result_id, std::move(operands)));
+      ir_context, spv::Op::OpTypeFunction, 0, result_id, std::move(operands)));
 
   UpdateModuleIdBound(ir_context, result_id);
 }
@@ -1186,7 +1192,7 @@
 uint32_t MaybeGetStructType(opt::IRContext* ir_context,
                             const std::vector<uint32_t>& component_type_ids) {
   for (auto& type_or_value : ir_context->types_values()) {
-    if (type_or_value.opcode() != SpvOpTypeStruct ||
+    if (type_or_value.opcode() != spv::Op::OpTypeStruct ||
         type_or_value.NumInOperands() !=
             static_cast<uint32_t>(component_type_ids.size())) {
       continue;
@@ -1219,11 +1225,11 @@
   assert(type_inst && "|scalar_or_composite_type_id| is invalid");
 
   switch (type_inst->opcode()) {
-    case SpvOpTypeBool:
+    case spv::Op::OpTypeBool:
       return MaybeGetBoolConstant(ir_context, transformation_context, false,
                                   is_irrelevant);
-    case SpvOpTypeFloat:
-    case SpvOpTypeInt: {
+    case spv::Op::OpTypeFloat:
+    case spv::Op::OpTypeInt: {
       const auto width = type_inst->GetSingleWordInOperand(0);
       std::vector<uint32_t> words = {0};
       if (width > 32) {
@@ -1233,7 +1239,7 @@
       return MaybeGetScalarConstant(ir_context, transformation_context, words,
                                     scalar_or_composite_type_id, is_irrelevant);
     }
-    case SpvOpTypeStruct: {
+    case spv::Op::OpTypeStruct: {
       std::vector<uint32_t> component_ids;
       for (uint32_t i = 0; i < type_inst->NumInOperands(); ++i) {
         const auto component_type_id = type_inst->GetSingleWordInOperand(i);
@@ -1260,8 +1266,8 @@
           ir_context, transformation_context, component_ids,
           scalar_or_composite_type_id, is_irrelevant);
     }
-    case SpvOpTypeMatrix:
-    case SpvOpTypeVector: {
+    case spv::Op::OpTypeMatrix:
+    case spv::Op::OpTypeVector: {
       const auto component_type_id = type_inst->GetSingleWordInOperand(0);
 
       auto component_id = MaybeGetZeroConstant(
@@ -1284,7 +1290,7 @@
           std::vector<uint32_t>(component_count, component_id),
           scalar_or_composite_type_id, is_irrelevant);
     }
-    case SpvOpTypeArray: {
+    case spv::Op::OpTypeArray: {
       const auto component_type_id = type_inst->GetSingleWordInOperand(0);
 
       auto component_id = MaybeGetZeroConstant(
@@ -1319,16 +1325,16 @@
   assert(spvOpcodeGeneratesType(type_instr->opcode()) &&
          "A type-generating opcode was expected.");
   switch (type_instr->opcode()) {
-    case SpvOpTypeBool:
-    case SpvOpTypeInt:
-    case SpvOpTypeFloat:
-    case SpvOpTypeMatrix:
-    case SpvOpTypeVector:
+    case spv::Op::OpTypeBool:
+    case spv::Op::OpTypeInt:
+    case spv::Op::OpTypeFloat:
+    case spv::Op::OpTypeMatrix:
+    case spv::Op::OpTypeVector:
       return true;
-    case SpvOpTypeArray:
+    case spv::Op::OpTypeArray:
       return CanCreateConstant(ir_context,
                                type_instr->GetSingleWordInOperand(0));
-    case SpvOpTypeStruct:
+    case spv::Op::OpTypeStruct:
       if (HasBlockOrBufferBlockDecoration(ir_context, type_id)) {
         return false;
       }
@@ -1377,7 +1383,7 @@
   assert(IsCompositeType(type) && "|composite_type_id| is invalid");
 
   for (const auto& inst : ir_context->types_values()) {
-    if (inst.opcode() == SpvOpConstantComposite &&
+    if (inst.opcode() == spv::Op::OpConstantComposite &&
         inst.type_id() == composite_type_id &&
         transformation_context.GetFactManager()->IdIsIrrelevant(
             inst.result_id()) == is_irrelevant &&
@@ -1457,7 +1463,8 @@
     bool is_irrelevant) {
   if (auto type_id = MaybeGetBoolType(ir_context)) {
     for (const auto& inst : ir_context->types_values()) {
-      if (inst.opcode() == (value ? SpvOpConstantTrue : SpvOpConstantFalse) &&
+      if (inst.opcode() ==
+              (value ? spv::Op::OpConstantTrue : spv::Op::OpConstantFalse) &&
           inst.type_id() == type_id &&
           transformation_context.GetFactManager()->IdIsIrrelevant(
               inst.result_id()) == is_irrelevant) {
@@ -1552,13 +1559,13 @@
 
 opt::Instruction* GetLastInsertBeforeInstruction(opt::IRContext* ir_context,
                                                  uint32_t block_id,
-                                                 SpvOp opcode) {
+                                                 spv::Op opcode) {
   // CFG::block uses std::map::at which throws an exception when |block_id| is
   // invalid. The error message is unhelpful, though. Thus, we test that
   // |block_id| is valid here.
   const auto* label_inst = ir_context->get_def_use_mgr()->GetDef(block_id);
   (void)label_inst;  // Make compilers happy in release mode.
-  assert(label_inst && label_inst->opcode() == SpvOpLabel &&
+  assert(label_inst && label_inst->opcode() == spv::Op::OpLabel &&
          "|block_id| is invalid");
 
   auto* block = ir_context->cfg()->block(block_id);
@@ -1624,7 +1631,7 @@
         assert(composite_type_being_accessed->AsStruct());
         auto constant_index_instruction = ir_context->get_def_use_mgr()->GetDef(
             use_instruction->GetSingleWordInOperand(index_in_operand));
-        assert(constant_index_instruction->opcode() == SpvOpConstant);
+        assert(constant_index_instruction->opcode() == spv::Op::OpConstant);
         uint32_t member_index =
             constant_index_instruction->GetSingleWordInOperand(0);
         composite_type_being_accessed =
@@ -1641,7 +1648,7 @@
     }
   }
 
-  if (use_instruction->opcode() == SpvOpFunctionCall &&
+  if (use_instruction->opcode() == spv::Op::OpFunctionCall &&
       use_in_operand_index > 0) {
     // This is a function call argument.  It is not allowed to have pointer
     // type.
@@ -1663,7 +1670,7 @@
     }
   }
 
-  if (use_instruction->opcode() == SpvOpImageTexelPointer &&
+  if (use_instruction->opcode() == spv::Op::OpImageTexelPointer &&
       use_in_operand_index == 2) {
     // The OpImageTexelPointer instruction has a Sample parameter that in some
     // situations must be an id for the value 0.  To guard against disrupting
@@ -1671,38 +1678,38 @@
     return false;
   }
 
-  if (ir_context->get_feature_mgr()->HasCapability(SpvCapabilityShader)) {
+  if (ir_context->get_feature_mgr()->HasCapability(spv::Capability::Shader)) {
     // With the Shader capability, memory scope and memory semantics operands
     // are required to be constants, so they cannot be replaced arbitrarily.
     switch (use_instruction->opcode()) {
-      case SpvOpAtomicLoad:
-      case SpvOpAtomicStore:
-      case SpvOpAtomicExchange:
-      case SpvOpAtomicIIncrement:
-      case SpvOpAtomicIDecrement:
-      case SpvOpAtomicIAdd:
-      case SpvOpAtomicISub:
-      case SpvOpAtomicSMin:
-      case SpvOpAtomicUMin:
-      case SpvOpAtomicSMax:
-      case SpvOpAtomicUMax:
-      case SpvOpAtomicAnd:
-      case SpvOpAtomicOr:
-      case SpvOpAtomicXor:
+      case spv::Op::OpAtomicLoad:
+      case spv::Op::OpAtomicStore:
+      case spv::Op::OpAtomicExchange:
+      case spv::Op::OpAtomicIIncrement:
+      case spv::Op::OpAtomicIDecrement:
+      case spv::Op::OpAtomicIAdd:
+      case spv::Op::OpAtomicISub:
+      case spv::Op::OpAtomicSMin:
+      case spv::Op::OpAtomicUMin:
+      case spv::Op::OpAtomicSMax:
+      case spv::Op::OpAtomicUMax:
+      case spv::Op::OpAtomicAnd:
+      case spv::Op::OpAtomicOr:
+      case spv::Op::OpAtomicXor:
         if (use_in_operand_index == 1 || use_in_operand_index == 2) {
           return false;
         }
         break;
-      case SpvOpAtomicCompareExchange:
+      case spv::Op::OpAtomicCompareExchange:
         if (use_in_operand_index == 1 || use_in_operand_index == 2 ||
             use_in_operand_index == 3) {
           return false;
         }
         break;
-      case SpvOpAtomicCompareExchangeWeak:
-      case SpvOpAtomicFlagTestAndSet:
-      case SpvOpAtomicFlagClear:
-      case SpvOpAtomicFAddEXT:
+      case spv::Op::OpAtomicCompareExchangeWeak:
+      case spv::Op::OpAtomicFlagTestAndSet:
+      case spv::Op::OpAtomicFlagClear:
+      case spv::Op::OpAtomicFAddEXT:
         assert(false && "Not allowed with the Shader capability.");
       default:
         break;
@@ -1715,17 +1722,17 @@
 bool MembersHaveBuiltInDecoration(opt::IRContext* ir_context,
                                   uint32_t struct_type_id) {
   const auto* type_inst = ir_context->get_def_use_mgr()->GetDef(struct_type_id);
-  assert(type_inst && type_inst->opcode() == SpvOpTypeStruct &&
+  assert(type_inst && type_inst->opcode() == spv::Op::OpTypeStruct &&
          "|struct_type_id| is not a result id of an OpTypeStruct");
 
   uint32_t builtin_count = 0;
   ir_context->get_def_use_mgr()->ForEachUser(
       type_inst,
       [struct_type_id, &builtin_count](const opt::Instruction* user) {
-        if (user->opcode() == SpvOpMemberDecorate &&
+        if (user->opcode() == spv::Op::OpMemberDecorate &&
             user->GetSingleWordInOperand(0) == struct_type_id &&
-            static_cast<SpvDecoration>(user->GetSingleWordInOperand(2)) ==
-                SpvDecorationBuiltIn) {
+            static_cast<spv::Decoration>(user->GetSingleWordInOperand(2)) ==
+                spv::Decoration::BuiltIn) {
           ++builtin_count;
         }
       });
@@ -1738,9 +1745,11 @@
 }
 
 bool HasBlockOrBufferBlockDecoration(opt::IRContext* ir_context, uint32_t id) {
-  for (auto decoration : {SpvDecorationBlock, SpvDecorationBufferBlock}) {
+  for (auto decoration :
+       {spv::Decoration::Block, spv::Decoration::BufferBlock}) {
     if (!ir_context->get_decoration_mgr()->WhileEachDecoration(
-            id, decoration, [](const opt::Instruction & /*unused*/) -> bool {
+            id, uint32_t(decoration),
+            [](const opt::Instruction & /*unused*/) -> bool {
               return false;
             })) {
       return true;
@@ -1762,7 +1771,7 @@
     if (before_split) {
       // If the instruction comes before the split and its opcode is
       // OpSampledImage, record its result id.
-      if (instruction.opcode() == SpvOpSampledImage) {
+      if (instruction.opcode() == spv::Op::OpSampledImage) {
         sampled_image_result_ids.insert(instruction.result_id());
       }
     } else {
@@ -1784,110 +1793,110 @@
 
 bool InstructionHasNoSideEffects(const opt::Instruction& instruction) {
   switch (instruction.opcode()) {
-    case SpvOpUndef:
-    case SpvOpAccessChain:
-    case SpvOpInBoundsAccessChain:
-    case SpvOpArrayLength:
-    case SpvOpVectorExtractDynamic:
-    case SpvOpVectorInsertDynamic:
-    case SpvOpVectorShuffle:
-    case SpvOpCompositeConstruct:
-    case SpvOpCompositeExtract:
-    case SpvOpCompositeInsert:
-    case SpvOpCopyObject:
-    case SpvOpTranspose:
-    case SpvOpConvertFToU:
-    case SpvOpConvertFToS:
-    case SpvOpConvertSToF:
-    case SpvOpConvertUToF:
-    case SpvOpUConvert:
-    case SpvOpSConvert:
-    case SpvOpFConvert:
-    case SpvOpQuantizeToF16:
-    case SpvOpSatConvertSToU:
-    case SpvOpSatConvertUToS:
-    case SpvOpBitcast:
-    case SpvOpSNegate:
-    case SpvOpFNegate:
-    case SpvOpIAdd:
-    case SpvOpFAdd:
-    case SpvOpISub:
-    case SpvOpFSub:
-    case SpvOpIMul:
-    case SpvOpFMul:
-    case SpvOpUDiv:
-    case SpvOpSDiv:
-    case SpvOpFDiv:
-    case SpvOpUMod:
-    case SpvOpSRem:
-    case SpvOpSMod:
-    case SpvOpFRem:
-    case SpvOpFMod:
-    case SpvOpVectorTimesScalar:
-    case SpvOpMatrixTimesScalar:
-    case SpvOpVectorTimesMatrix:
-    case SpvOpMatrixTimesVector:
-    case SpvOpMatrixTimesMatrix:
-    case SpvOpOuterProduct:
-    case SpvOpDot:
-    case SpvOpIAddCarry:
-    case SpvOpISubBorrow:
-    case SpvOpUMulExtended:
-    case SpvOpSMulExtended:
-    case SpvOpAny:
-    case SpvOpAll:
-    case SpvOpIsNan:
-    case SpvOpIsInf:
-    case SpvOpIsFinite:
-    case SpvOpIsNormal:
-    case SpvOpSignBitSet:
-    case SpvOpLessOrGreater:
-    case SpvOpOrdered:
-    case SpvOpUnordered:
-    case SpvOpLogicalEqual:
-    case SpvOpLogicalNotEqual:
-    case SpvOpLogicalOr:
-    case SpvOpLogicalAnd:
-    case SpvOpLogicalNot:
-    case SpvOpSelect:
-    case SpvOpIEqual:
-    case SpvOpINotEqual:
-    case SpvOpUGreaterThan:
-    case SpvOpSGreaterThan:
-    case SpvOpUGreaterThanEqual:
-    case SpvOpSGreaterThanEqual:
-    case SpvOpULessThan:
-    case SpvOpSLessThan:
-    case SpvOpULessThanEqual:
-    case SpvOpSLessThanEqual:
-    case SpvOpFOrdEqual:
-    case SpvOpFUnordEqual:
-    case SpvOpFOrdNotEqual:
-    case SpvOpFUnordNotEqual:
-    case SpvOpFOrdLessThan:
-    case SpvOpFUnordLessThan:
-    case SpvOpFOrdGreaterThan:
-    case SpvOpFUnordGreaterThan:
-    case SpvOpFOrdLessThanEqual:
-    case SpvOpFUnordLessThanEqual:
-    case SpvOpFOrdGreaterThanEqual:
-    case SpvOpFUnordGreaterThanEqual:
-    case SpvOpShiftRightLogical:
-    case SpvOpShiftRightArithmetic:
-    case SpvOpShiftLeftLogical:
-    case SpvOpBitwiseOr:
-    case SpvOpBitwiseXor:
-    case SpvOpBitwiseAnd:
-    case SpvOpNot:
-    case SpvOpBitFieldInsert:
-    case SpvOpBitFieldSExtract:
-    case SpvOpBitFieldUExtract:
-    case SpvOpBitReverse:
-    case SpvOpBitCount:
-    case SpvOpCopyLogical:
-    case SpvOpPhi:
-    case SpvOpPtrEqual:
-    case SpvOpPtrNotEqual:
+    case spv::Op::OpUndef:
+    case spv::Op::OpAccessChain:
+    case spv::Op::OpInBoundsAccessChain:
+    case spv::Op::OpArrayLength:
+    case spv::Op::OpVectorExtractDynamic:
+    case spv::Op::OpVectorInsertDynamic:
+    case spv::Op::OpVectorShuffle:
+    case spv::Op::OpCompositeConstruct:
+    case spv::Op::OpCompositeExtract:
+    case spv::Op::OpCompositeInsert:
+    case spv::Op::OpCopyObject:
+    case spv::Op::OpTranspose:
+    case spv::Op::OpConvertFToU:
+    case spv::Op::OpConvertFToS:
+    case spv::Op::OpConvertSToF:
+    case spv::Op::OpConvertUToF:
+    case spv::Op::OpUConvert:
+    case spv::Op::OpSConvert:
+    case spv::Op::OpFConvert:
+    case spv::Op::OpQuantizeToF16:
+    case spv::Op::OpSatConvertSToU:
+    case spv::Op::OpSatConvertUToS:
+    case spv::Op::OpBitcast:
+    case spv::Op::OpSNegate:
+    case spv::Op::OpFNegate:
+    case spv::Op::OpIAdd:
+    case spv::Op::OpFAdd:
+    case spv::Op::OpISub:
+    case spv::Op::OpFSub:
+    case spv::Op::OpIMul:
+    case spv::Op::OpFMul:
+    case spv::Op::OpUDiv:
+    case spv::Op::OpSDiv:
+    case spv::Op::OpFDiv:
+    case spv::Op::OpUMod:
+    case spv::Op::OpSRem:
+    case spv::Op::OpSMod:
+    case spv::Op::OpFRem:
+    case spv::Op::OpFMod:
+    case spv::Op::OpVectorTimesScalar:
+    case spv::Op::OpMatrixTimesScalar:
+    case spv::Op::OpVectorTimesMatrix:
+    case spv::Op::OpMatrixTimesVector:
+    case spv::Op::OpMatrixTimesMatrix:
+    case spv::Op::OpOuterProduct:
+    case spv::Op::OpDot:
+    case spv::Op::OpIAddCarry:
+    case spv::Op::OpISubBorrow:
+    case spv::Op::OpUMulExtended:
+    case spv::Op::OpSMulExtended:
+    case spv::Op::OpAny:
+    case spv::Op::OpAll:
+    case spv::Op::OpIsNan:
+    case spv::Op::OpIsInf:
+    case spv::Op::OpIsFinite:
+    case spv::Op::OpIsNormal:
+    case spv::Op::OpSignBitSet:
+    case spv::Op::OpLessOrGreater:
+    case spv::Op::OpOrdered:
+    case spv::Op::OpUnordered:
+    case spv::Op::OpLogicalEqual:
+    case spv::Op::OpLogicalNotEqual:
+    case spv::Op::OpLogicalOr:
+    case spv::Op::OpLogicalAnd:
+    case spv::Op::OpLogicalNot:
+    case spv::Op::OpSelect:
+    case spv::Op::OpIEqual:
+    case spv::Op::OpINotEqual:
+    case spv::Op::OpUGreaterThan:
+    case spv::Op::OpSGreaterThan:
+    case spv::Op::OpUGreaterThanEqual:
+    case spv::Op::OpSGreaterThanEqual:
+    case spv::Op::OpULessThan:
+    case spv::Op::OpSLessThan:
+    case spv::Op::OpULessThanEqual:
+    case spv::Op::OpSLessThanEqual:
+    case spv::Op::OpFOrdEqual:
+    case spv::Op::OpFUnordEqual:
+    case spv::Op::OpFOrdNotEqual:
+    case spv::Op::OpFUnordNotEqual:
+    case spv::Op::OpFOrdLessThan:
+    case spv::Op::OpFUnordLessThan:
+    case spv::Op::OpFOrdGreaterThan:
+    case spv::Op::OpFUnordGreaterThan:
+    case spv::Op::OpFOrdLessThanEqual:
+    case spv::Op::OpFUnordLessThanEqual:
+    case spv::Op::OpFOrdGreaterThanEqual:
+    case spv::Op::OpFUnordGreaterThanEqual:
+    case spv::Op::OpShiftRightLogical:
+    case spv::Op::OpShiftRightArithmetic:
+    case spv::Op::OpShiftLeftLogical:
+    case spv::Op::OpBitwiseOr:
+    case spv::Op::OpBitwiseXor:
+    case spv::Op::OpBitwiseAnd:
+    case spv::Op::OpNot:
+    case spv::Op::OpBitFieldInsert:
+    case spv::Op::OpBitFieldSExtract:
+    case spv::Op::OpBitFieldUExtract:
+    case spv::Op::OpBitReverse:
+    case spv::Op::OpBitCount:
+    case spv::Op::OpCopyLogical:
+    case spv::Op::OpPhi:
+    case spv::Op::OpPtrEqual:
+    case spv::Op::OpPtrNotEqual:
       return true;
     default:
       return false;
@@ -1975,7 +1984,7 @@
 
     for (const auto& inst : block) {
       for (uint32_t i = 0; i < inst.NumInOperands();
-           i += inst.opcode() == SpvOpPhi ? 2 : 1) {
+           i += inst.opcode() == spv::Op::OpPhi ? 2 : 1) {
         const auto& operand = inst.GetInOperand(i);
         if (!spvIsInIdType(operand.type)) {
           continue;
@@ -1994,7 +2003,7 @@
           continue;
         }
 
-        auto domination_target_id = inst.opcode() == SpvOpPhi
+        auto domination_target_id = inst.opcode() == spv::Op::OpPhi
                                         ? inst.GetSingleWordInOperand(i + 1)
                                         : block.id();
 
@@ -2021,68 +2030,68 @@
 // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3582): Add all
 //  opcodes that are agnostic to signedness of operands to function.
 //  This is not exhaustive yet.
-bool IsAgnosticToSignednessOfOperand(SpvOp opcode,
+bool IsAgnosticToSignednessOfOperand(spv::Op opcode,
                                      uint32_t use_in_operand_index) {
   switch (opcode) {
-    case SpvOpSNegate:
-    case SpvOpNot:
-    case SpvOpIAdd:
-    case SpvOpISub:
-    case SpvOpIMul:
-    case SpvOpSDiv:
-    case SpvOpSRem:
-    case SpvOpSMod:
-    case SpvOpShiftRightLogical:
-    case SpvOpShiftRightArithmetic:
-    case SpvOpShiftLeftLogical:
-    case SpvOpBitwiseOr:
-    case SpvOpBitwiseXor:
-    case SpvOpBitwiseAnd:
-    case SpvOpIEqual:
-    case SpvOpINotEqual:
-    case SpvOpULessThan:
-    case SpvOpSLessThan:
-    case SpvOpUGreaterThan:
-    case SpvOpSGreaterThan:
-    case SpvOpULessThanEqual:
-    case SpvOpSLessThanEqual:
-    case SpvOpUGreaterThanEqual:
-    case SpvOpSGreaterThanEqual:
+    case spv::Op::OpSNegate:
+    case spv::Op::OpNot:
+    case spv::Op::OpIAdd:
+    case spv::Op::OpISub:
+    case spv::Op::OpIMul:
+    case spv::Op::OpSDiv:
+    case spv::Op::OpSRem:
+    case spv::Op::OpSMod:
+    case spv::Op::OpShiftRightLogical:
+    case spv::Op::OpShiftRightArithmetic:
+    case spv::Op::OpShiftLeftLogical:
+    case spv::Op::OpBitwiseOr:
+    case spv::Op::OpBitwiseXor:
+    case spv::Op::OpBitwiseAnd:
+    case spv::Op::OpIEqual:
+    case spv::Op::OpINotEqual:
+    case spv::Op::OpULessThan:
+    case spv::Op::OpSLessThan:
+    case spv::Op::OpUGreaterThan:
+    case spv::Op::OpSGreaterThan:
+    case spv::Op::OpULessThanEqual:
+    case spv::Op::OpSLessThanEqual:
+    case spv::Op::OpUGreaterThanEqual:
+    case spv::Op::OpSGreaterThanEqual:
       return true;
 
-    case SpvOpAtomicStore:
-    case SpvOpAtomicExchange:
-    case SpvOpAtomicIAdd:
-    case SpvOpAtomicISub:
-    case SpvOpAtomicSMin:
-    case SpvOpAtomicUMin:
-    case SpvOpAtomicSMax:
-    case SpvOpAtomicUMax:
-    case SpvOpAtomicAnd:
-    case SpvOpAtomicOr:
-    case SpvOpAtomicXor:
-    case SpvOpAtomicFAddEXT:  // Capability AtomicFloat32AddEXT,
+    case spv::Op::OpAtomicStore:
+    case spv::Op::OpAtomicExchange:
+    case spv::Op::OpAtomicIAdd:
+    case spv::Op::OpAtomicISub:
+    case spv::Op::OpAtomicSMin:
+    case spv::Op::OpAtomicUMin:
+    case spv::Op::OpAtomicSMax:
+    case spv::Op::OpAtomicUMax:
+    case spv::Op::OpAtomicAnd:
+    case spv::Op::OpAtomicOr:
+    case spv::Op::OpAtomicXor:
+    case spv::Op::OpAtomicFAddEXT:  // Capability AtomicFloat32AddEXT,
       // AtomicFloat64AddEXT.
       assert(use_in_operand_index != 0 &&
              "Signedness check should not occur on a pointer operand.");
       return use_in_operand_index == 1 || use_in_operand_index == 2;
 
-    case SpvOpAtomicCompareExchange:
-    case SpvOpAtomicCompareExchangeWeak:  // Capability Kernel.
+    case spv::Op::OpAtomicCompareExchange:
+    case spv::Op::OpAtomicCompareExchangeWeak:  // Capability Kernel.
       assert(use_in_operand_index != 0 &&
              "Signedness check should not occur on a pointer operand.");
       return use_in_operand_index >= 1 && use_in_operand_index <= 3;
 
-    case SpvOpAtomicLoad:
-    case SpvOpAtomicIIncrement:
-    case SpvOpAtomicIDecrement:
-    case SpvOpAtomicFlagTestAndSet:  // Capability Kernel.
-    case SpvOpAtomicFlagClear:       // Capability Kernel.
+    case spv::Op::OpAtomicLoad:
+    case spv::Op::OpAtomicIIncrement:
+    case spv::Op::OpAtomicIDecrement:
+    case spv::Op::OpAtomicFlagTestAndSet:  // Capability Kernel.
+    case spv::Op::OpAtomicFlagClear:       // Capability Kernel.
       assert(use_in_operand_index != 0 &&
              "Signedness check should not occur on a pointer operand.");
       return use_in_operand_index >= 1;
 
-    case SpvOpAccessChain:
+    case spv::Op::OpAccessChain:
       // The signedness of indices does not matter.
       return use_in_operand_index > 0;
 
@@ -2093,7 +2102,7 @@
   }
 }
 
-bool TypesAreCompatible(opt::IRContext* ir_context, SpvOp opcode,
+bool TypesAreCompatible(opt::IRContext* ir_context, spv::Op opcode,
                         uint32_t use_in_operand_index, uint32_t type_id_1,
                         uint32_t type_id_2) {
   assert(ir_context->get_type_mgr()->GetType(type_id_1) &&
diff --git a/source/fuzz/fuzzer_util.h b/source/fuzz/fuzzer_util.h
index 54aa14a..374e32e 100644
--- a/source/fuzz/fuzzer_util.h
+++ b/source/fuzz/fuzzer_util.h
@@ -111,7 +111,7 @@
 // Determines whether it is OK to insert an instruction with opcode |opcode|
 // before |instruction_in_block|.
 bool CanInsertOpcodeBeforeInstruction(
-    SpvOp opcode, const opt::BasicBlock::iterator& instruction_in_block);
+    spv::Op opcode, const opt::BasicBlock::iterator& instruction_in_block);
 
 // Determines whether it is OK to make a synonym of |inst|.
 // |transformation_context| is used to verify that the result id of |inst|
@@ -170,8 +170,8 @@
                                    opt::IRContext* ir_context);
 
 // Returns memory semantics mask for specific storage class.
-SpvMemorySemanticsMask GetMemorySemanticsForStorageClass(
-    SpvStorageClass storage_class);
+spv::MemorySemanticsMask GetMemorySemanticsForStorageClass(
+    spv::StorageClass storage_class);
 
 // Returns true if and only if |context| is valid, according to the validator
 // instantiated with |validator_options|.  |consumer| is used for error
@@ -258,18 +258,18 @@
 
 // Given |pointer_type_inst|, which must be an OpTypePointer instruction,
 // returns the associated storage class.
-SpvStorageClass GetStorageClassFromPointerType(
+spv::StorageClass GetStorageClassFromPointerType(
     opt::Instruction* pointer_type_inst);
 
 // Given |pointer_type_id|, which must be the id of a pointer type, returns the
 // associated storage class.
-SpvStorageClass GetStorageClassFromPointerType(opt::IRContext* context,
-                                               uint32_t pointer_type_id);
+spv::StorageClass GetStorageClassFromPointerType(opt::IRContext* context,
+                                                 uint32_t pointer_type_id);
 
 // Returns the id of a pointer with pointee type |pointee_type_id| and storage
 // class |storage_class|, if it exists, and 0 otherwise.
 uint32_t MaybeGetPointerType(opt::IRContext* context, uint32_t pointee_type_id,
-                             SpvStorageClass storage_class);
+                             spv::StorageClass storage_class);
 
 // Given an instruction |inst| and an operand absolute index |absolute_index|,
 // returns the index of the operand restricted to the input operands.
@@ -309,7 +309,7 @@
 // Returns a pointer to the new global variable instruction.
 opt::Instruction* AddGlobalVariable(opt::IRContext* context, uint32_t result_id,
                                     uint32_t type_id,
-                                    SpvStorageClass storage_class,
+                                    spv::StorageClass storage_class,
                                     uint32_t initializer_id);
 
 // Adds an instruction to the start of |function_id|, of the form:
@@ -541,7 +541,7 @@
 // opcode |opcode| can be inserted, or nullptr if there is no such instruction.
 opt::Instruction* GetLastInsertBeforeInstruction(opt::IRContext* ir_context,
                                                  uint32_t block_id,
-                                                 SpvOp opcode);
+                                                 spv::Op opcode);
 
 // Checks whether various conditions hold related to the acceptability of
 // replacing the id use at |use_in_operand_index| of |use_instruction| with a
@@ -608,14 +608,14 @@
 // behaviour depending on the signedness of the operand at
 // |use_in_operand_index|.
 // Assumes that the operand must be the id of an integer scalar or vector.
-bool IsAgnosticToSignednessOfOperand(SpvOp opcode,
+bool IsAgnosticToSignednessOfOperand(spv::Op opcode,
                                      uint32_t use_in_operand_index);
 
 // Returns true if |type_id_1| and |type_id_2| represent compatible types
 // given the context of the instruction with |opcode| (i.e. we can replace
 // an operand of |opcode| of the first type with an id of the second type
 // and vice-versa).
-bool TypesAreCompatible(opt::IRContext* ir_context, SpvOp opcode,
+bool TypesAreCompatible(opt::IRContext* ir_context, spv::Op opcode,
                         uint32_t use_in_operand_index, uint32_t type_id_1,
                         uint32_t type_id_2);
 
diff --git a/source/fuzz/instruction_descriptor.cpp b/source/fuzz/instruction_descriptor.cpp
index fb1ff76..120d8f8 100644
--- a/source/fuzz/instruction_descriptor.cpp
+++ b/source/fuzz/instruction_descriptor.cpp
@@ -40,8 +40,9 @@
              "The skipped instruction count should only be incremented "
              "after the instruction base has been found.");
     }
-    if (found_base && instruction.opcode() ==
-                          instruction_descriptor.target_instruction_opcode()) {
+    if (found_base &&
+        instruction.opcode() ==
+            spv::Op(instruction_descriptor.target_instruction_opcode())) {
       if (num_ignored == instruction_descriptor.num_opcodes_to_ignore()) {
         return &instruction;
       }
@@ -52,11 +53,11 @@
 }
 
 protobufs::InstructionDescriptor MakeInstructionDescriptor(
-    uint32_t base_instruction_result_id, SpvOp target_instruction_opcode,
+    uint32_t base_instruction_result_id, spv::Op target_instruction_opcode,
     uint32_t num_opcodes_to_ignore) {
   protobufs::InstructionDescriptor result;
   result.set_base_instruction_result_id(base_instruction_result_id);
-  result.set_target_instruction_opcode(target_instruction_opcode);
+  result.set_target_instruction_opcode(uint32_t(target_instruction_opcode));
   result.set_num_opcodes_to_ignore(num_opcodes_to_ignore);
   return result;
 }
@@ -64,7 +65,7 @@
 protobufs::InstructionDescriptor MakeInstructionDescriptor(
     const opt::BasicBlock& block,
     const opt::BasicBlock::const_iterator& inst_it) {
-  const SpvOp opcode =
+  const spv::Op opcode =
       inst_it->opcode();    // The opcode of the instruction being described.
   uint32_t skip_count = 0;  // The number of these opcodes we have skipped when
   // searching backwards.
diff --git a/source/fuzz/instruction_descriptor.h b/source/fuzz/instruction_descriptor.h
index 2ccd15a..063cad4 100644
--- a/source/fuzz/instruction_descriptor.h
+++ b/source/fuzz/instruction_descriptor.h
@@ -32,7 +32,7 @@
 // components.  See the protobuf definition for details of what these
 // components mean.
 protobufs::InstructionDescriptor MakeInstructionDescriptor(
-    uint32_t base_instruction_result_id, SpvOp target_instruction_opcode,
+    uint32_t base_instruction_result_id, spv::Op target_instruction_opcode,
     uint32_t num_opcodes_to_ignore);
 
 // Returns an instruction descriptor that describing the instruction at
diff --git a/source/fuzz/instruction_message.cpp b/source/fuzz/instruction_message.cpp
index 9503932..7e8ac71 100644
--- a/source/fuzz/instruction_message.cpp
+++ b/source/fuzz/instruction_message.cpp
@@ -20,10 +20,10 @@
 namespace fuzz {
 
 protobufs::Instruction MakeInstructionMessage(
-    SpvOp opcode, uint32_t result_type_id, uint32_t result_id,
+    spv::Op opcode, uint32_t result_type_id, uint32_t result_id,
     const opt::Instruction::OperandList& input_operands) {
   protobufs::Instruction result;
-  result.set_opcode(opcode);
+  result.set_opcode(uint32_t(opcode));
   result.set_result_type_id(result_type_id);
   result.set_result_id(result_id);
   for (auto& operand : input_operands) {
@@ -71,7 +71,7 @@
   }
   // Create and return the instruction.
   return MakeUnique<opt::Instruction>(
-      ir_context, static_cast<SpvOp>(instruction_message.opcode()),
+      ir_context, static_cast<spv::Op>(instruction_message.opcode()),
       instruction_message.result_type_id(), instruction_message.result_id(),
       in_operands);
 }
diff --git a/source/fuzz/instruction_message.h b/source/fuzz/instruction_message.h
index fcbb4c7..e1312f4 100644
--- a/source/fuzz/instruction_message.h
+++ b/source/fuzz/instruction_message.h
@@ -26,7 +26,7 @@
 
 // Creates an Instruction protobuf message from its component parts.
 protobufs::Instruction MakeInstructionMessage(
-    SpvOp opcode, uint32_t result_type_id, uint32_t result_id,
+    spv::Op opcode, uint32_t result_type_id, uint32_t result_id,
     const opt::Instruction::OperandList& input_operands);
 
 // Creates an Instruction protobuf message from a parsed instruction.
diff --git a/source/fuzz/transformation_access_chain.cpp b/source/fuzz/transformation_access_chain.cpp
index 3fe9e65..1e7f87b 100644
--- a/source/fuzz/transformation_access_chain.cpp
+++ b/source/fuzz/transformation_access_chain.cpp
@@ -63,7 +63,7 @@
   }
   // The type must indeed be a pointer.
   auto pointer_type = ir_context->get_def_use_mgr()->GetDef(pointer->type_id());
-  if (pointer_type->opcode() != SpvOpTypePointer) {
+  if (pointer_type->opcode() != spv::Op::OpTypePointer) {
     return false;
   }
 
@@ -75,7 +75,7 @@
     return false;
   }
   if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
-          SpvOpAccessChain, instruction_to_insert_before)) {
+          spv::Op::OpAccessChain, instruction_to_insert_before)) {
     return false;
   }
 
@@ -83,8 +83,8 @@
   // we do not want to allow accessing such pointers.  This might be acceptable
   // in dead blocks, but we conservatively avoid it.
   switch (pointer->opcode()) {
-    case SpvOpConstantNull:
-    case SpvOpUndef:
+    case spv::Op::OpConstantNull:
+    case spv::Op::OpUndef:
       assert(
           false &&
           "Access chains should not be created from null/undefined pointers");
@@ -117,7 +117,7 @@
 
     // Check whether the object is a struct.
     if (ir_context->get_def_use_mgr()->GetDef(subobject_type_id)->opcode() ==
-        SpvOpTypeStruct) {
+        spv::Op::OpTypeStruct) {
       // It is a struct: we need to retrieve the integer value.
 
       bool successful;
@@ -202,7 +202,7 @@
   // associated with pointers to isomorphic structs being regarded as the same.
   return fuzzerutil::MaybeGetPointerType(
              ir_context, subobject_type_id,
-             static_cast<SpvStorageClass>(
+             static_cast<spv::StorageClass>(
                  pointer_type->GetSingleWordInOperand(0))) != 0;
 }
 
@@ -243,7 +243,7 @@
 
     // Check whether the object is a struct.
     if (ir_context->get_def_use_mgr()->GetDef(subobject_type_id)->opcode() ==
-        SpvOpTypeStruct) {
+        spv::Op::OpTypeStruct) {
       // It is a struct: we need to retrieve the integer value.
 
       index_value =
@@ -290,7 +290,8 @@
       //   %fresh_ids.first = OpULessThanEqual %bool %int_id %bound_minus_one.
       fuzzerutil::UpdateModuleIdBound(ir_context, fresh_ids.first());
       auto comparison_instruction = MakeUnique<opt::Instruction>(
-          ir_context, SpvOpULessThanEqual, bool_type_id, fresh_ids.first(),
+          ir_context, spv::Op::OpULessThanEqual, bool_type_id,
+          fresh_ids.first(),
           opt::Instruction::OperandList(
               {{SPV_OPERAND_TYPE_ID, {index_instruction->result_id()}},
                {SPV_OPERAND_TYPE_ID, {bound_minus_one_id}}}));
@@ -306,7 +307,7 @@
       //                           %bound_minus_one
       fuzzerutil::UpdateModuleIdBound(ir_context, fresh_ids.second());
       auto select_instruction = MakeUnique<opt::Instruction>(
-          ir_context, SpvOpSelect, int_type_inst->result_id(),
+          ir_context, spv::Op::OpSelect, int_type_inst->result_id(),
           fresh_ids.second(),
           opt::Instruction::OperandList(
               {{SPV_OPERAND_TYPE_ID, {fresh_ids.first()}},
@@ -334,13 +335,14 @@
   // of the original pointer.
   uint32_t result_type = fuzzerutil::MaybeGetPointerType(
       ir_context, subobject_type_id,
-      static_cast<SpvStorageClass>(pointer_type->GetSingleWordInOperand(0)));
+      static_cast<spv::StorageClass>(pointer_type->GetSingleWordInOperand(0)));
 
   // Add the access chain instruction to the module, and update the module's
   // id bound.
   fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
-  auto access_chain_instruction = MakeUnique<opt::Instruction>(
-      ir_context, SpvOpAccessChain, result_type, message_.fresh_id(), operands);
+  auto access_chain_instruction =
+      MakeUnique<opt::Instruction>(ir_context, spv::Op::OpAccessChain,
+                                   result_type, message_.fresh_id(), operands);
   auto access_chain_instruction_ptr = access_chain_instruction.get();
   instruction_to_insert_before->InsertBefore(
       std::move(access_chain_instruction));
@@ -367,7 +369,7 @@
     opt::IRContext* ir_context, uint32_t index_id,
     uint32_t object_type_id) const {
   assert(ir_context->get_def_use_mgr()->GetDef(object_type_id)->opcode() ==
-             SpvOpTypeStruct &&
+             spv::Op::OpTypeStruct &&
          "Precondition: the type must be a struct type.");
   if (!ValidIndexToComposite(ir_context, index_id, object_type_id)) {
     return {false, 0};
@@ -408,14 +410,14 @@
   // The index type must be 32-bit integer.
   auto index_type =
       ir_context->get_def_use_mgr()->GetDef(index_instruction->type_id());
-  if (index_type->opcode() != SpvOpTypeInt ||
+  if (index_type->opcode() != spv::Op::OpTypeInt ||
       index_type->GetSingleWordInOperand(0) != 32) {
     return false;
   }
 
   // If the object being traversed is a struct, the id must correspond to an
   // in-bound constant.
-  if (object_type_def->opcode() == SpvOpTypeStruct) {
+  if (object_type_def->opcode() == spv::Op::OpTypeStruct) {
     if (!spvOpcodeIsConstant(index_instruction->opcode())) {
       return false;
     }
diff --git a/source/fuzz/transformation_add_bit_instruction_synonym.cpp b/source/fuzz/transformation_add_bit_instruction_synonym.cpp
index 636c0a3..4b26c2b 100644
--- a/source/fuzz/transformation_add_bit_instruction_synonym.cpp
+++ b/source/fuzz/transformation_add_bit_instruction_synonym.cpp
@@ -87,10 +87,10 @@
   // synonym fact.  The helper function should take care of invalidating
   // analyses before adding facts.
   switch (bit_instruction->opcode()) {
-    case SpvOpBitwiseOr:
-    case SpvOpBitwiseXor:
-    case SpvOpBitwiseAnd:
-    case SpvOpNot:
+    case spv::Op::OpBitwiseOr:
+    case spv::Op::OpBitwiseXor:
+    case spv::Op::OpBitwiseAnd:
+    case spv::Op::OpNot:
       AddOpBitwiseOrOpNotSynonym(ir_context, transformation_context,
                                  bit_instruction);
       break;
@@ -106,10 +106,10 @@
   //  Right now we only support certain operations. When this issue is addressed
   //  the following conditional can use the function |spvOpcodeIsBit|.
   // |instruction| must be defined and must be a supported bit instruction.
-  if (!instruction || (instruction->opcode() != SpvOpBitwiseOr &&
-                       instruction->opcode() != SpvOpBitwiseXor &&
-                       instruction->opcode() != SpvOpBitwiseAnd &&
-                       instruction->opcode() != SpvOpNot)) {
+  if (!instruction || (instruction->opcode() != spv::Op::OpBitwiseOr &&
+                       instruction->opcode() != spv::Op::OpBitwiseXor &&
+                       instruction->opcode() != spv::Op::OpBitwiseAnd &&
+                       instruction->opcode() != spv::Op::OpNot)) {
     return false;
   }
 
@@ -119,7 +119,7 @@
     return false;
   }
 
-  if (instruction->opcode() == SpvOpNot) {
+  if (instruction->opcode() == spv::Op::OpNot) {
     auto operand = instruction->GetInOperand(0).words[0];
     auto operand_inst = ir_context->get_def_use_mgr()->GetDef(operand);
     auto operand_type =
@@ -171,10 +171,10 @@
   // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3557):
   //  Right now, only certain operations are supported.
   switch (bit_instruction->opcode()) {
-    case SpvOpBitwiseOr:
-    case SpvOpBitwiseXor:
-    case SpvOpBitwiseAnd:
-    case SpvOpNot:
+    case spv::Op::OpBitwiseOr:
+    case spv::Op::OpBitwiseXor:
+    case spv::Op::OpBitwiseAnd:
+    case spv::Op::OpNot:
       return (2 + bit_instruction->NumInOperands()) *
                  ir_context->get_type_mgr()
                      ->GetType(bit_instruction->type_id())
@@ -220,7 +220,7 @@
     for (auto operand = bit_instruction->begin() + 2;
          operand != bit_instruction->end(); operand++) {
       auto bit_extract =
-          opt::Instruction(ir_context, SpvOpBitFieldUExtract,
+          opt::Instruction(ir_context, spv::Op::OpBitFieldUExtract,
                            bit_instruction->type_id(), *fresh_id++,
                            {{SPV_OPERAND_TYPE_ID, operand->words},
                             {SPV_OPERAND_TYPE_ID, {offset}},
@@ -246,12 +246,13 @@
   // first two bits of the result.
   uint32_t offset = fuzzerutil::MaybeGetIntegerConstant(
       ir_context, *transformation_context, {1}, 32, false, false);
-  auto bit_insert = opt::Instruction(
-      ir_context, SpvOpBitFieldInsert, bit_instruction->type_id(), *fresh_id++,
-      {{SPV_OPERAND_TYPE_ID, {extracted_bit_instructions[0]}},
-       {SPV_OPERAND_TYPE_ID, {extracted_bit_instructions[1]}},
-       {SPV_OPERAND_TYPE_ID, {offset}},
-       {SPV_OPERAND_TYPE_ID, {count}}});
+  auto bit_insert =
+      opt::Instruction(ir_context, spv::Op::OpBitFieldInsert,
+                       bit_instruction->type_id(), *fresh_id++,
+                       {{SPV_OPERAND_TYPE_ID, {extracted_bit_instructions[0]}},
+                        {SPV_OPERAND_TYPE_ID, {extracted_bit_instructions[1]}},
+                        {SPV_OPERAND_TYPE_ID, {offset}},
+                        {SPV_OPERAND_TYPE_ID, {count}}});
   bit_instruction->InsertBefore(MakeUnique<opt::Instruction>(bit_insert));
   fuzzerutil::UpdateModuleIdBound(ir_context, bit_insert.result_id());
 
@@ -260,7 +261,7 @@
     offset = fuzzerutil::MaybeGetIntegerConstant(
         ir_context, *transformation_context, {i}, 32, false, false);
     bit_insert = opt::Instruction(
-        ir_context, SpvOpBitFieldInsert, bit_instruction->type_id(),
+        ir_context, spv::Op::OpBitFieldInsert, bit_instruction->type_id(),
         *fresh_id++,
         {{SPV_OPERAND_TYPE_ID, {bit_insert.result_id()}},
          {SPV_OPERAND_TYPE_ID, {extracted_bit_instructions[i]}},
diff --git a/source/fuzz/transformation_add_constant_boolean.cpp b/source/fuzz/transformation_add_constant_boolean.cpp
index 3935432..89c2e57 100644
--- a/source/fuzz/transformation_add_constant_boolean.cpp
+++ b/source/fuzz/transformation_add_constant_boolean.cpp
@@ -43,7 +43,8 @@
   // Add the boolean constant to the module, ensuring the module's id bound is
   // high enough.
   auto new_instruction = MakeUnique<opt::Instruction>(
-      ir_context, message_.is_true() ? SpvOpConstantTrue : SpvOpConstantFalse,
+      ir_context,
+      message_.is_true() ? spv::Op::OpConstantTrue : spv::Op::OpConstantFalse,
       fuzzerutil::MaybeGetBoolType(ir_context), message_.fresh_id(),
       opt::Instruction::OperandList());
   auto new_instruction_ptr = new_instruction.get();
diff --git a/source/fuzz/transformation_add_constant_composite.cpp b/source/fuzz/transformation_add_constant_composite.cpp
index 89007ab..b8ee8be 100644
--- a/source/fuzz/transformation_add_constant_composite.cpp
+++ b/source/fuzz/transformation_add_constant_composite.cpp
@@ -53,7 +53,7 @@
   // struct - whether its decorations are OK.
   std::vector<uint32_t> constituent_type_ids;
   switch (composite_type_instruction->opcode()) {
-    case SpvOpTypeArray:
+    case spv::Op::OpTypeArray:
       for (uint32_t index = 0;
            index <
            fuzzerutil::GetArraySize(*composite_type_instruction, ir_context);
@@ -62,8 +62,8 @@
             composite_type_instruction->GetSingleWordInOperand(0));
       }
       break;
-    case SpvOpTypeMatrix:
-    case SpvOpTypeVector:
+    case spv::Op::OpTypeMatrix:
+    case spv::Op::OpTypeVector:
       for (uint32_t index = 0;
            index < composite_type_instruction->GetSingleWordInOperand(1);
            index++) {
@@ -71,7 +71,7 @@
             composite_type_instruction->GetSingleWordInOperand(0));
       }
       break;
-    case SpvOpTypeStruct:
+    case spv::Op::OpTypeStruct:
       // We do not create constants of structs decorated with Block nor
       // BufferBlock.  The SPIR-V spec does not explicitly disallow this, but it
       // seems like a strange thing to do, so we disallow it to avoid triggering
@@ -120,7 +120,7 @@
     in_operands.push_back({SPV_OPERAND_TYPE_ID, {constituent_id}});
   }
   auto new_instruction = MakeUnique<opt::Instruction>(
-      ir_context, SpvOpConstantComposite, message_.type_id(),
+      ir_context, spv::Op::OpConstantComposite, message_.type_id(),
       message_.fresh_id(), in_operands);
   auto new_instruction_ptr = new_instruction.get();
   ir_context->module()->AddGlobalValue(std::move(new_instruction));
diff --git a/source/fuzz/transformation_add_constant_null.cpp b/source/fuzz/transformation_add_constant_null.cpp
index c0f7367..7b83bae 100644
--- a/source/fuzz/transformation_add_constant_null.cpp
+++ b/source/fuzz/transformation_add_constant_null.cpp
@@ -48,8 +48,8 @@
 void TransformationAddConstantNull::Apply(
     opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
   auto new_instruction = MakeUnique<opt::Instruction>(
-      ir_context, SpvOpConstantNull, message_.type_id(), message_.fresh_id(),
-      opt::Instruction::OperandList());
+      ir_context, spv::Op::OpConstantNull, message_.type_id(),
+      message_.fresh_id(), opt::Instruction::OperandList());
   auto new_instruction_ptr = new_instruction.get();
   ir_context->module()->AddGlobalValue(std::move(new_instruction));
   fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
diff --git a/source/fuzz/transformation_add_constant_scalar.cpp b/source/fuzz/transformation_add_constant_scalar.cpp
index a2d95fb..45989d4 100644
--- a/source/fuzz/transformation_add_constant_scalar.cpp
+++ b/source/fuzz/transformation_add_constant_scalar.cpp
@@ -65,7 +65,7 @@
     opt::IRContext* ir_context,
     TransformationContext* transformation_context) const {
   auto new_instruction = MakeUnique<opt::Instruction>(
-      ir_context, SpvOpConstant, message_.type_id(), message_.fresh_id(),
+      ir_context, spv::Op::OpConstant, message_.type_id(), message_.fresh_id(),
       opt::Instruction::OperandList(
           {{SPV_OPERAND_TYPE_LITERAL_INTEGER,
             std::vector<uint32_t>(message_.word().begin(),
diff --git a/source/fuzz/transformation_add_copy_memory.cpp b/source/fuzz/transformation_add_copy_memory.cpp
index 5eb4bdc..9d1f325 100644
--- a/source/fuzz/transformation_add_copy_memory.cpp
+++ b/source/fuzz/transformation_add_copy_memory.cpp
@@ -27,12 +27,12 @@
 
 TransformationAddCopyMemory::TransformationAddCopyMemory(
     const protobufs::InstructionDescriptor& instruction_descriptor,
-    uint32_t fresh_id, uint32_t source_id, SpvStorageClass storage_class,
+    uint32_t fresh_id, uint32_t source_id, spv::StorageClass storage_class,
     uint32_t initializer_id) {
   *message_.mutable_instruction_descriptor() = instruction_descriptor;
   message_.set_fresh_id(fresh_id);
   message_.set_source_id(source_id);
-  message_.set_storage_class(storage_class);
+  message_.set_storage_class(uint32_t(storage_class));
   message_.set_initializer_id(initializer_id);
 }
 
@@ -53,7 +53,8 @@
   // Check that we can insert OpCopyMemory before |instruction_descriptor|.
   auto iter = fuzzerutil::GetIteratorForInstruction(
       ir_context->get_instr_block(inst), inst);
-  if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCopyMemory, iter)) {
+  if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpCopyMemory,
+                                                    iter)) {
     return false;
   }
 
@@ -65,8 +66,10 @@
   }
 
   // |storage_class| is either Function or Private.
-  if (message_.storage_class() != SpvStorageClassFunction &&
-      message_.storage_class() != SpvStorageClassPrivate) {
+  if (spv::StorageClass(message_.storage_class()) !=
+          spv::StorageClass::Function &&
+      spv::StorageClass(message_.storage_class()) !=
+          spv::StorageClass::Private) {
     return false;
   }
 
@@ -76,7 +79,7 @@
   // OpTypePointer with |message_.storage_class| exists.
   if (!fuzzerutil::MaybeGetPointerType(
           ir_context, pointee_type_id,
-          static_cast<SpvStorageClass>(message_.storage_class()))) {
+          static_cast<spv::StorageClass>(message_.storage_class()))) {
     return false;
   }
 
@@ -103,20 +106,20 @@
       ir_context->get_instr_block(insert_before_inst);
 
   // Add global or local variable to copy memory into.
-  auto storage_class = static_cast<SpvStorageClass>(message_.storage_class());
+  auto storage_class = static_cast<spv::StorageClass>(message_.storage_class());
   auto type_id = fuzzerutil::MaybeGetPointerType(
       ir_context,
       fuzzerutil::GetPointeeTypeIdFromPointerType(
           ir_context, fuzzerutil::GetTypeId(ir_context, message_.source_id())),
       storage_class);
 
-  if (storage_class == SpvStorageClassPrivate) {
+  if (storage_class == spv::StorageClass::Private) {
     opt::Instruction* new_global =
         fuzzerutil::AddGlobalVariable(ir_context, message_.fresh_id(), type_id,
                                       storage_class, message_.initializer_id());
     ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_global);
   } else {
-    assert(storage_class == SpvStorageClassFunction &&
+    assert(storage_class == spv::StorageClass::Function &&
            "Storage class can be either Private or Function");
     opt::Function* enclosing_function = enclosing_block->GetParent();
     opt::Instruction* new_local = fuzzerutil::AddLocalVariable(
@@ -130,7 +133,7 @@
       enclosing_block, insert_before_inst);
 
   auto new_instruction = MakeUnique<opt::Instruction>(
-      ir_context, SpvOpCopyMemory, 0, 0,
+      ir_context, spv::Op::OpCopyMemory, 0, 0,
       opt::Instruction::OperandList{
           {SPV_OPERAND_TYPE_ID, {message_.fresh_id()}},
           {SPV_OPERAND_TYPE_ID, {message_.source_id()}}});
@@ -160,7 +163,8 @@
 bool TransformationAddCopyMemory::IsInstructionSupported(
     opt::IRContext* ir_context, opt::Instruction* inst) {
   if (!inst->result_id() || !inst->type_id() ||
-      inst->opcode() == SpvOpConstantNull || inst->opcode() == SpvOpUndef) {
+      inst->opcode() == spv::Op::OpConstantNull ||
+      inst->opcode() == spv::Op::OpUndef) {
     return false;
   }
 
diff --git a/source/fuzz/transformation_add_copy_memory.h b/source/fuzz/transformation_add_copy_memory.h
index b25652f..053b629 100644
--- a/source/fuzz/transformation_add_copy_memory.h
+++ b/source/fuzz/transformation_add_copy_memory.h
@@ -30,7 +30,7 @@
 
   TransformationAddCopyMemory(
       const protobufs::InstructionDescriptor& instruction_descriptor,
-      uint32_t fresh_id, uint32_t source_id, SpvStorageClass storage_class,
+      uint32_t fresh_id, uint32_t source_id, spv::StorageClass storage_class,
       uint32_t initializer_id);
 
   // - |instruction_descriptor| must point to a valid instruction in the module.
diff --git a/source/fuzz/transformation_add_dead_block.cpp b/source/fuzz/transformation_add_dead_block.cpp
index df700ce..930adc1 100644
--- a/source/fuzz/transformation_add_dead_block.cpp
+++ b/source/fuzz/transformation_add_dead_block.cpp
@@ -61,7 +61,7 @@
   }
 
   // It must end with OpBranch.
-  if (existing_block->terminator()->opcode() != SpvOpBranch) {
+  if (existing_block->terminator()->opcode() != spv::Op::OpBranch) {
     return false;
   }
 
@@ -122,27 +122,27 @@
   auto enclosing_function = existing_block->GetParent();
   std::unique_ptr<opt::BasicBlock> new_block =
       MakeUnique<opt::BasicBlock>(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpLabel, 0, message_.fresh_id(),
+          ir_context, spv::Op::OpLabel, 0, message_.fresh_id(),
           opt::Instruction::OperandList()));
   new_block->AddInstruction(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpBranch, 0, 0,
+      ir_context, spv::Op::OpBranch, 0, 0,
       opt::Instruction::OperandList(
           {{SPV_OPERAND_TYPE_ID, {successor_block_id}}})));
 
   // Turn the original block into a selection merge, with its original successor
   // as the merge block.
   existing_block->terminator()->InsertBefore(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpSelectionMerge, 0, 0,
+      ir_context, spv::Op::OpSelectionMerge, 0, 0,
       opt::Instruction::OperandList(
           {{SPV_OPERAND_TYPE_ID, {successor_block_id}},
            {SPV_OPERAND_TYPE_SELECTION_CONTROL,
-            {SpvSelectionControlMaskNone}}})));
+            {uint32_t(spv::SelectionControlMask::MaskNone)}}})));
 
   // Change the original block's terminator to be a conditional branch on the
   // given boolean, with the original successor and the new successor as branch
   // targets, and such that at runtime control will always transfer to the
   // original successor.
-  existing_block->terminator()->SetOpcode(SpvOpBranchConditional);
+  existing_block->terminator()->SetOpcode(spv::Op::OpBranchConditional);
   existing_block->terminator()->SetInOperands(
       {{SPV_OPERAND_TYPE_ID, {bool_id}},
        {SPV_OPERAND_TYPE_ID,
diff --git a/source/fuzz/transformation_add_dead_break.cpp b/source/fuzz/transformation_add_dead_break.cpp
index 32080ca..07ed4dc 100644
--- a/source/fuzz/transformation_add_dead_break.cpp
+++ b/source/fuzz/transformation_add_dead_break.cpp
@@ -142,7 +142,7 @@
   }
 
   // Check that |message_.from_block| ends with an unconditional branch.
-  if (bb_from->terminator()->opcode() != SpvOpBranch) {
+  if (bb_from->terminator()->opcode() != spv::Op::OpBranch) {
     // The block associated with the id does not end with an unconditional
     // branch.
     return false;
diff --git a/source/fuzz/transformation_add_dead_continue.cpp b/source/fuzz/transformation_add_dead_continue.cpp
index f2b9ab3..c534801 100644
--- a/source/fuzz/transformation_add_dead_continue.cpp
+++ b/source/fuzz/transformation_add_dead_continue.cpp
@@ -55,7 +55,7 @@
   }
 
   // Check that |message_.from_block| ends with an unconditional branch.
-  if (bb_from->terminator()->opcode() != SpvOpBranch) {
+  if (bb_from->terminator()->opcode() != spv::Op::OpBranch) {
     // The block associated with the id does not end with an unconditional
     // branch.
     return false;
diff --git a/source/fuzz/transformation_add_early_terminator_wrapper.cpp b/source/fuzz/transformation_add_early_terminator_wrapper.cpp
index 547398a..28e0186 100644
--- a/source/fuzz/transformation_add_early_terminator_wrapper.cpp
+++ b/source/fuzz/transformation_add_early_terminator_wrapper.cpp
@@ -28,17 +28,17 @@
 TransformationAddEarlyTerminatorWrapper::
     TransformationAddEarlyTerminatorWrapper(uint32_t function_fresh_id,
                                             uint32_t label_fresh_id,
-                                            SpvOp opcode) {
+                                            spv::Op opcode) {
   message_.set_function_fresh_id(function_fresh_id);
   message_.set_label_fresh_id(label_fresh_id);
-  message_.set_opcode(opcode);
+  message_.set_opcode(uint32_t(opcode));
 }
 
 bool TransformationAddEarlyTerminatorWrapper::IsApplicable(
     opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
-  assert((message_.opcode() == SpvOpKill ||
-          message_.opcode() == SpvOpUnreachable ||
-          message_.opcode() == SpvOpTerminateInvocation) &&
+  assert((spv::Op(message_.opcode()) == spv::Op::OpKill ||
+          spv::Op(message_.opcode()) == spv::Op::OpUnreachable ||
+          spv::Op(message_.opcode()) == spv::Op::OpTerminateInvocation) &&
          "Invalid opcode.");
 
   if (!fuzzerutil::IsFreshId(ir_context, message_.function_fresh_id())) {
@@ -66,26 +66,29 @@
   // %label_fresh_id = OpLabel
   //                   OpKill|Unreachable|TerminateInvocation
   auto basic_block = MakeUnique<opt::BasicBlock>(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpLabel, 0, message_.label_fresh_id(),
+      ir_context, spv::Op::OpLabel, 0, message_.label_fresh_id(),
       opt::Instruction::OperandList()));
   basic_block->AddInstruction(MakeUnique<opt::Instruction>(
-      ir_context, static_cast<SpvOp>(message_.opcode()), 0, 0,
+      ir_context, static_cast<spv::Op>(message_.opcode()), 0, 0,
       opt::Instruction::OperandList()));
 
   // Create a zero-argument void function.
   auto void_type_id = fuzzerutil::MaybeGetVoidType(ir_context);
   auto function = MakeUnique<opt::Function>(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpFunction, void_type_id, message_.function_fresh_id(),
+      ir_context, spv::Op::OpFunction, void_type_id,
+      message_.function_fresh_id(),
       opt::Instruction::OperandList(
-          {{SPV_OPERAND_TYPE_FUNCTION_CONTROL, {SpvFunctionControlMaskNone}},
+          {{SPV_OPERAND_TYPE_FUNCTION_CONTROL,
+            {uint32_t(spv::FunctionControlMask::MaskNone)}},
            {SPV_OPERAND_TYPE_TYPE_ID,
             {fuzzerutil::FindFunctionType(ir_context, {void_type_id})}}})));
 
   // Add the basic block to the function as the sole block, and add the function
   // to the module.
   function->AddBasicBlock(std::move(basic_block));
-  function->SetFunctionEnd(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpFunctionEnd, 0, 0, opt::Instruction::OperandList()));
+  function->SetFunctionEnd(
+      MakeUnique<opt::Instruction>(ir_context, spv::Op::OpFunctionEnd, 0, 0,
+                                   opt::Instruction::OperandList()));
   ir_context->module()->AddFunction(std::move(function));
 
   ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
diff --git a/source/fuzz/transformation_add_early_terminator_wrapper.h b/source/fuzz/transformation_add_early_terminator_wrapper.h
index 97cc527..5d0201d 100644
--- a/source/fuzz/transformation_add_early_terminator_wrapper.h
+++ b/source/fuzz/transformation_add_early_terminator_wrapper.h
@@ -30,7 +30,7 @@
 
   TransformationAddEarlyTerminatorWrapper(uint32_t function_fresh_id,
                                           uint32_t label_fresh_id,
-                                          SpvOp opcode);
+                                          spv::Op opcode);
 
   // - |message_.function_fresh_id| and |message_.label_fresh_id| must be fresh
   //   and distinct.
diff --git a/source/fuzz/transformation_add_function.cpp b/source/fuzz/transformation_add_function.cpp
index 06cd657..1f61ede 100644
--- a/source/fuzz/transformation_add_function.cpp
+++ b/source/fuzz/transformation_add_function.cpp
@@ -178,7 +178,7 @@
   }
   ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
 
-  assert(message_.instruction(0).opcode() == SpvOpFunction &&
+  assert(spv::Op(message_.instruction(0).opcode()) == spv::Op::OpFunction &&
          "The first instruction of an 'add function' transformation must be "
          "OpFunction.");
 
@@ -189,7 +189,7 @@
   } else {
     // Inform the fact manager that all blocks in the function are dead.
     for (auto& inst : message_.instruction()) {
-      if (inst.opcode() == SpvOpLabel) {
+      if (spv::Op(inst.opcode()) == spv::Op::OpLabel) {
         transformation_context->GetFactManager()->AddFactBlockIsDead(
             inst.result_id());
       }
@@ -202,16 +202,16 @@
   // parameters to other functions knowing that it is OK if they get
   // over-written.
   for (auto& instruction : message_.instruction()) {
-    switch (instruction.opcode()) {
-      case SpvOpFunctionParameter:
+    switch (spv::Op(instruction.opcode())) {
+      case spv::Op::OpFunctionParameter:
         if (ir_context->get_def_use_mgr()
                 ->GetDef(instruction.result_type_id())
-                ->opcode() == SpvOpTypePointer) {
+                ->opcode() == spv::Op::OpTypePointer) {
           transformation_context->GetFactManager()
               ->AddFactValueOfPointeeIsIrrelevant(instruction.result_id());
         }
         break;
-      case SpvOpVariable:
+      case spv::Op::OpVariable:
         transformation_context->GetFactManager()
             ->AddFactValueOfPointeeIsIrrelevant(instruction.result_id());
         break;
@@ -239,7 +239,7 @@
 
   // A function must start with OpFunction.
   auto function_begin = message_.instruction(0);
-  if (function_begin.opcode() != SpvOpFunction) {
+  if (spv::Op(function_begin.opcode()) != spv::Op::OpFunction) {
     return false;
   }
 
@@ -256,8 +256,8 @@
   // Iterate through all function parameter instructions, adding parameters to
   // the new function.
   while (instruction_index < num_instructions &&
-         message_.instruction(instruction_index).opcode() ==
-             SpvOpFunctionParameter) {
+         spv::Op(message_.instruction(instruction_index).opcode()) ==
+             spv::Op::OpFunctionParameter) {
     new_function->AddParameter(InstructionFromMessage(
         ir_context, message_.instruction(instruction_index)));
     instruction_index++;
@@ -265,16 +265,19 @@
 
   // After the parameters, there needs to be a label.
   if (instruction_index == num_instructions ||
-      message_.instruction(instruction_index).opcode() != SpvOpLabel) {
+      spv::Op(message_.instruction(instruction_index).opcode()) !=
+          spv::Op::OpLabel) {
     return false;
   }
 
   // Iterate through the instructions block by block until the end of the
   // function is reached.
   while (instruction_index < num_instructions &&
-         message_.instruction(instruction_index).opcode() != SpvOpFunctionEnd) {
+         spv::Op(message_.instruction(instruction_index).opcode()) !=
+             spv::Op::OpFunctionEnd) {
     // Invariant: we should always be at a label instruction at this point.
-    assert(message_.instruction(instruction_index).opcode() == SpvOpLabel);
+    assert(spv::Op(message_.instruction(instruction_index).opcode()) ==
+           spv::Op::OpLabel);
 
     // Make a basic block using the label instruction.
     std::unique_ptr<opt::BasicBlock> block =
@@ -285,9 +288,10 @@
     // of the function, adding each such instruction to the block.
     instruction_index++;
     while (instruction_index < num_instructions &&
-           message_.instruction(instruction_index).opcode() !=
-               SpvOpFunctionEnd &&
-           message_.instruction(instruction_index).opcode() != SpvOpLabel) {
+           spv::Op(message_.instruction(instruction_index).opcode()) !=
+               spv::Op::OpFunctionEnd &&
+           spv::Op(message_.instruction(instruction_index).opcode()) !=
+               spv::Op::OpLabel) {
       block->AddInstruction(InstructionFromMessage(
           ir_context, message_.instruction(instruction_index)));
       instruction_index++;
@@ -298,7 +302,8 @@
   // Having considered all the blocks, we should be at the last instruction and
   // it needs to be OpFunctionEnd.
   if (instruction_index != num_instructions - 1 ||
-      message_.instruction(instruction_index).opcode() != SpvOpFunctionEnd) {
+      spv::Op(message_.instruction(instruction_index).opcode()) !=
+          spv::Op::OpFunctionEnd) {
     return false;
   }
   // Set the function's final instruction, add the function to the module and
@@ -339,20 +344,20 @@
   for (auto& block : *added_function) {
     for (auto& inst : block) {
       switch (inst.opcode()) {
-        case SpvOpKill:
-        case SpvOpUnreachable:
+        case spv::Op::OpKill:
+        case spv::Op::OpUnreachable:
           if (!TryToTurnKillOrUnreachableIntoReturn(ir_context, added_function,
                                                     &inst)) {
             return false;
           }
           break;
-        case SpvOpAccessChain:
-        case SpvOpInBoundsAccessChain:
+        case spv::Op::OpAccessChain:
+        case spv::Op::OpInBoundsAccessChain:
           if (!TryToClampAccessChainIndices(ir_context, &inst)) {
             return false;
           }
           break;
-        case SpvOpFunctionCall:
+        case spv::Op::OpFunctionCall:
           // A livesafe function my only call other livesafe functions.
           if (!transformation_context.GetFactManager()->FunctionIsLivesafe(
                   inst.GetSingleWordInOperand(0))) {
@@ -404,7 +409,7 @@
   auto loop_limit_constant_id_instr =
       ir_context->get_def_use_mgr()->GetDef(message_.loop_limit_constant_id());
   if (!loop_limit_constant_id_instr ||
-      loop_limit_constant_id_instr->opcode() != SpvOpConstant) {
+      loop_limit_constant_id_instr->opcode() != spv::Op::OpConstant) {
     // The loop limit constant id instruction must exist and have an
     // appropriate opcode.
     return false;
@@ -412,7 +417,7 @@
 
   auto loop_limit_type = ir_context->get_def_use_mgr()->GetDef(
       loop_limit_constant_id_instr->type_id());
-  if (loop_limit_type->opcode() != SpvOpTypeInt ||
+  if (loop_limit_type->opcode() != spv::Op::OpTypeInt ||
       loop_limit_type->GetSingleWordInOperand(0) != 32) {
     // The type of the loop limit constant must be 32-bit integer.  It
     // doesn't actually matter whether the integer is signed or not.
@@ -457,7 +462,7 @@
 
   // Look for pointer-to-unsigned int type.
   opt::analysis::Pointer pointer_to_unsigned_int_type(
-      registered_unsigned_int_type, SpvStorageClassFunction);
+      registered_unsigned_int_type, spv::StorageClass::Function);
   uint32_t pointer_to_unsigned_int_type_id =
       ir_context->get_type_mgr()->GetId(&pointer_to_unsigned_int_type);
   if (!pointer_to_unsigned_int_type_id) {
@@ -477,13 +482,13 @@
 
   // Declare the loop limiter variable at the start of the function's entry
   // block, via an instruction of the form:
-  //   %loop_limiter_var = SpvOpVariable %ptr_to_uint Function %zero
+  //   %loop_limiter_var = spv::Op::OpVariable %ptr_to_uint Function %zero
   added_function->begin()->begin()->InsertBefore(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpVariable, pointer_to_unsigned_int_type_id,
+      ir_context, spv::Op::OpVariable, pointer_to_unsigned_int_type_id,
       message_.loop_limiter_variable_id(),
-      opt::Instruction::OperandList(
-          {{SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassFunction}},
-           {SPV_OPERAND_TYPE_ID, {zero_id}}})));
+      opt::Instruction::OperandList({{SPV_OPERAND_TYPE_STORAGE_CLASS,
+                                      {uint32_t(spv::StorageClass::Function)}},
+                                     {SPV_OPERAND_TYPE_ID, {zero_id}}})));
   // Update the module's id bound since we have added the loop limiter
   // variable id.
   fuzzerutil::UpdateModuleIdBound(ir_context,
@@ -589,10 +594,11 @@
     auto back_edge_block = ir_context->cfg()->block(back_edge_block_id);
     auto back_edge_block_terminator = back_edge_block->terminator();
     bool compare_using_greater_than_equal;
-    if (back_edge_block_terminator->opcode() == SpvOpBranch) {
+    if (back_edge_block_terminator->opcode() == spv::Op::OpBranch) {
       compare_using_greater_than_equal = true;
     } else {
-      assert(back_edge_block_terminator->opcode() == SpvOpBranchConditional);
+      assert(back_edge_block_terminator->opcode() ==
+             spv::Op::OpBranchConditional);
       assert(((back_edge_block_terminator->GetSingleWordInOperand(1) ==
                    loop_header->id() &&
                back_edge_block_terminator->GetSingleWordInOperand(2) ==
@@ -613,7 +619,7 @@
     // Add a load from the loop limiter variable, of the form:
     //   %t1 = OpLoad %uint32 %loop_limiter
     new_instructions.push_back(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpLoad, unsigned_int_type_id,
+        ir_context, spv::Op::OpLoad, unsigned_int_type_id,
         loop_limiter_info.load_id(),
         opt::Instruction::OperandList(
             {{SPV_OPERAND_TYPE_ID, {message_.loop_limiter_variable_id()}}})));
@@ -621,7 +627,7 @@
     // Increment the loaded value:
     //   %t2 = OpIAdd %uint32 %t1 %one
     new_instructions.push_back(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpIAdd, unsigned_int_type_id,
+        ir_context, spv::Op::OpIAdd, unsigned_int_type_id,
         loop_limiter_info.increment_id(),
         opt::Instruction::OperandList(
             {{SPV_OPERAND_TYPE_ID, {loop_limiter_info.load_id()}},
@@ -630,7 +636,7 @@
     // Store the incremented value back to the loop limiter variable:
     //   OpStore %loop_limiter %t2
     new_instructions.push_back(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpStore, 0, 0,
+        ir_context, spv::Op::OpStore, 0, 0,
         opt::Instruction::OperandList(
             {{SPV_OPERAND_TYPE_ID, {message_.loop_limiter_variable_id()}},
              {SPV_OPERAND_TYPE_ID, {loop_limiter_info.increment_id()}}})));
@@ -641,17 +647,18 @@
     //   %t3 = OpULessThan %bool %t1 %loop_limit
     new_instructions.push_back(MakeUnique<opt::Instruction>(
         ir_context,
-        compare_using_greater_than_equal ? SpvOpUGreaterThanEqual
-                                         : SpvOpULessThan,
+        compare_using_greater_than_equal ? spv::Op::OpUGreaterThanEqual
+                                         : spv::Op::OpULessThan,
         bool_type_id, loop_limiter_info.compare_id(),
         opt::Instruction::OperandList(
             {{SPV_OPERAND_TYPE_ID, {loop_limiter_info.load_id()}},
              {SPV_OPERAND_TYPE_ID, {message_.loop_limit_constant_id()}}})));
 
-    if (back_edge_block_terminator->opcode() == SpvOpBranchConditional) {
+    if (back_edge_block_terminator->opcode() == spv::Op::OpBranchConditional) {
       new_instructions.push_back(MakeUnique<opt::Instruction>(
           ir_context,
-          compare_using_greater_than_equal ? SpvOpLogicalOr : SpvOpLogicalAnd,
+          compare_using_greater_than_equal ? spv::Op::OpLogicalOr
+                                           : spv::Op::OpLogicalAnd,
           bool_type_id, loop_limiter_info.logical_op_id(),
           opt::Instruction::OperandList(
               {{SPV_OPERAND_TYPE_ID,
@@ -669,11 +676,11 @@
       back_edge_block_terminator->InsertBefore(std::move(new_instructions));
     }
 
-    if (back_edge_block_terminator->opcode() == SpvOpBranchConditional) {
+    if (back_edge_block_terminator->opcode() == spv::Op::OpBranchConditional) {
       back_edge_block_terminator->SetInOperand(
           0, {loop_limiter_info.logical_op_id()});
     } else {
-      assert(back_edge_block_terminator->opcode() == SpvOpBranch &&
+      assert(back_edge_block_terminator->opcode() == spv::Op::OpBranch &&
              "Back-edge terminator must be OpBranch or OpBranchConditional");
 
       // Check that, if the merge block starts with OpPhi instructions, suitable
@@ -689,7 +696,7 @@
       // Augment OpPhi instructions at the loop merge with the given ids.
       uint32_t phi_index = 0;
       for (auto& inst : *merge_block) {
-        if (inst.opcode() != SpvOpPhi) {
+        if (inst.opcode() != spv::Op::OpPhi) {
           break;
         }
         assert(phi_index <
@@ -702,7 +709,7 @@
       }
 
       // Add the new edge, by changing OpBranch to OpBranchConditional.
-      back_edge_block_terminator->SetOpcode(SpvOpBranchConditional);
+      back_edge_block_terminator->SetOpcode(spv::Op::OpBranchConditional);
       back_edge_block_terminator->SetInOperands(opt::Instruction::OperandList(
           {{SPV_OPERAND_TYPE_ID, {loop_limiter_info.compare_id()}},
            {SPV_OPERAND_TYPE_ID, {loop_header->MergeBlockId()}},
@@ -724,18 +731,18 @@
 bool TransformationAddFunction::TryToTurnKillOrUnreachableIntoReturn(
     opt::IRContext* ir_context, opt::Function* added_function,
     opt::Instruction* kill_or_unreachable_inst) const {
-  assert((kill_or_unreachable_inst->opcode() == SpvOpKill ||
-          kill_or_unreachable_inst->opcode() == SpvOpUnreachable) &&
+  assert((kill_or_unreachable_inst->opcode() == spv::Op::OpKill ||
+          kill_or_unreachable_inst->opcode() == spv::Op::OpUnreachable) &&
          "Precondition: instruction must be OpKill or OpUnreachable.");
 
   // Get the function's return type.
   auto function_return_type_inst =
       ir_context->get_def_use_mgr()->GetDef(added_function->type_id());
 
-  if (function_return_type_inst->opcode() == SpvOpTypeVoid) {
+  if (function_return_type_inst->opcode() == spv::Op::OpTypeVoid) {
     // The function has void return type, so change this instruction to
     // OpReturn.
-    kill_or_unreachable_inst->SetOpcode(SpvOpReturn);
+    kill_or_unreachable_inst->SetOpcode(spv::Op::OpReturn);
   } else {
     // The function has non-void return type, so change this instruction
     // to OpReturnValue, using the value id provided with the
@@ -749,7 +756,7 @@
             ->type_id() != function_return_type_inst->result_id()) {
       return false;
     }
-    kill_or_unreachable_inst->SetOpcode(SpvOpReturnValue);
+    kill_or_unreachable_inst->SetOpcode(spv::Op::OpReturnValue);
     kill_or_unreachable_inst->SetInOperands(
         {{SPV_OPERAND_TYPE_ID, {message_.kill_unreachable_return_value_id()}}});
   }
@@ -758,8 +765,8 @@
 
 bool TransformationAddFunction::TryToClampAccessChainIndices(
     opt::IRContext* ir_context, opt::Instruction* access_chain_inst) const {
-  assert((access_chain_inst->opcode() == SpvOpAccessChain ||
-          access_chain_inst->opcode() == SpvOpInBoundsAccessChain) &&
+  assert((access_chain_inst->opcode() == spv::Op::OpAccessChain ||
+          access_chain_inst->opcode() == spv::Op::OpInBoundsAccessChain) &&
          "Precondition: instruction must be OpAccessChain or "
          "OpInBoundsAccessChain.");
 
@@ -793,7 +800,7 @@
   assert(base_object && "The base object must exist.");
   auto pointer_type =
       ir_context->get_def_use_mgr()->GetDef(base_object->type_id());
-  assert(pointer_type && pointer_type->opcode() == SpvOpTypePointer &&
+  assert(pointer_type && pointer_type->opcode() == spv::Op::OpTypePointer &&
          "The base object must have pointer type.");
   auto should_be_composite_type = ir_context->get_def_use_mgr()->GetDef(
       pointer_type->GetSingleWordInOperand(1));
@@ -824,18 +831,18 @@
     auto index_inst = ir_context->get_def_use_mgr()->GetDef(index_id);
     auto index_type_inst =
         ir_context->get_def_use_mgr()->GetDef(index_inst->type_id());
-    assert(index_type_inst->opcode() == SpvOpTypeInt);
+    assert(index_type_inst->opcode() == spv::Op::OpTypeInt);
     assert(index_type_inst->GetSingleWordInOperand(0) == 32);
     opt::analysis::Integer* index_int_type =
         ir_context->get_type_mgr()
             ->GetType(index_type_inst->result_id())
             ->AsInteger();
 
-    if (index_inst->opcode() != SpvOpConstant ||
+    if (index_inst->opcode() != spv::Op::OpConstant ||
         index_inst->GetSingleWordInOperand(0) >= bound) {
       // The index is either non-constant or an out-of-bounds constant, so we
       // need to clamp it.
-      assert(should_be_composite_type->opcode() != SpvOpTypeStruct &&
+      assert(should_be_composite_type->opcode() != spv::Op::OpTypeStruct &&
              "Access chain indices into structures are required to be "
              "constants.");
       opt::analysis::IntConstant bound_minus_one(index_int_type, {bound - 1});
@@ -866,7 +873,7 @@
       // Compare the index with the bound via an instruction of the form:
       //   %t1 = OpULessThanEqual %bool %index %bound_minus_one
       new_instructions.push_back(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpULessThanEqual, bool_type_id, compare_id,
+          ir_context, spv::Op::OpULessThanEqual, bool_type_id, compare_id,
           opt::Instruction::OperandList(
               {{SPV_OPERAND_TYPE_ID, {index_inst->result_id()}},
                {SPV_OPERAND_TYPE_ID, {bound_minus_one_id}}})));
@@ -874,7 +881,8 @@
       // Select the index if in-bounds, otherwise one less than the bound:
       //   %t2 = OpSelect %int_type %t1 %index %bound_minus_one
       new_instructions.push_back(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpSelect, index_type_inst->result_id(), select_id,
+          ir_context, spv::Op::OpSelect, index_type_inst->result_id(),
+          select_id,
           opt::Instruction::OperandList(
               {{SPV_OPERAND_TYPE_ID, {compare_id}},
                {SPV_OPERAND_TYPE_ID, {index_inst->result_id()}},
@@ -899,20 +907,20 @@
     uint32_t index_id) {
   uint32_t sub_object_type_id;
   switch (composite_type_inst.opcode()) {
-    case SpvOpTypeArray:
-    case SpvOpTypeRuntimeArray:
+    case spv::Op::OpTypeArray:
+    case spv::Op::OpTypeRuntimeArray:
       sub_object_type_id = composite_type_inst.GetSingleWordInOperand(0);
       break;
-    case SpvOpTypeMatrix:
-    case SpvOpTypeVector:
+    case spv::Op::OpTypeMatrix:
+    case spv::Op::OpTypeVector:
       sub_object_type_id = composite_type_inst.GetSingleWordInOperand(0);
       break;
-    case SpvOpTypeStruct: {
+    case spv::Op::OpTypeStruct: {
       auto index_inst = ir_context->get_def_use_mgr()->GetDef(index_id);
-      assert(index_inst->opcode() == SpvOpConstant);
+      assert(index_inst->opcode() == spv::Op::OpConstant);
       assert(ir_context->get_def_use_mgr()
                  ->GetDef(index_inst->type_id())
-                 ->opcode() == SpvOpTypeInt);
+                 ->opcode() == spv::Op::OpTypeInt);
       assert(ir_context->get_def_use_mgr()
                  ->GetDef(index_inst->type_id())
                  ->GetSingleWordInOperand(0) == 32);
diff --git a/source/fuzz/transformation_add_global_undef.cpp b/source/fuzz/transformation_add_global_undef.cpp
index ec0574a..5aca19d 100644
--- a/source/fuzz/transformation_add_global_undef.cpp
+++ b/source/fuzz/transformation_add_global_undef.cpp
@@ -39,14 +39,14 @@
   auto type = ir_context->get_def_use_mgr()->GetDef(message_.type_id());
   // The type must exist, and must not be a function or pointer type.
   return type != nullptr && opt::IsTypeInst(type->opcode()) &&
-         type->opcode() != SpvOpTypeFunction &&
-         type->opcode() != SpvOpTypePointer;
+         type->opcode() != spv::Op::OpTypeFunction &&
+         type->opcode() != spv::Op::OpTypePointer;
 }
 
 void TransformationAddGlobalUndef::Apply(
     opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
   auto new_instruction = MakeUnique<opt::Instruction>(
-      ir_context, SpvOpUndef, message_.type_id(), message_.fresh_id(),
+      ir_context, spv::Op::OpUndef, message_.type_id(), message_.fresh_id(),
       opt::Instruction::OperandList());
   auto new_instruction_ptr = new_instruction.get();
   ir_context->module()->AddGlobalValue(std::move(new_instruction));
diff --git a/source/fuzz/transformation_add_global_variable.cpp b/source/fuzz/transformation_add_global_variable.cpp
index 814d01b..6e82d59 100644
--- a/source/fuzz/transformation_add_global_variable.cpp
+++ b/source/fuzz/transformation_add_global_variable.cpp
@@ -24,11 +24,11 @@
     : message_(std::move(message)) {}
 
 TransformationAddGlobalVariable::TransformationAddGlobalVariable(
-    uint32_t fresh_id, uint32_t type_id, SpvStorageClass storage_class,
+    uint32_t fresh_id, uint32_t type_id, spv::StorageClass storage_class,
     uint32_t initializer_id, bool value_is_irrelevant) {
   message_.set_fresh_id(fresh_id);
   message_.set_type_id(type_id);
-  message_.set_storage_class(storage_class);
+  message_.set_storage_class(uint32_t(storage_class));
   message_.set_initializer_id(initializer_id);
   message_.set_value_is_irrelevant(value_is_irrelevant);
 }
@@ -41,10 +41,10 @@
   }
 
   // The storage class must be Private or Workgroup.
-  auto storage_class = static_cast<SpvStorageClass>(message_.storage_class());
+  auto storage_class = static_cast<spv::StorageClass>(message_.storage_class());
   switch (storage_class) {
-    case SpvStorageClassPrivate:
-    case SpvStorageClassWorkgroup:
+    case spv::StorageClass::Private:
+    case spv::StorageClass::Workgroup:
       break;
     default:
       assert(false && "Unsupported storage class.");
@@ -66,7 +66,7 @@
   }
   if (message_.initializer_id()) {
     // An initializer is not allowed if the storage class is Workgroup.
-    if (storage_class == SpvStorageClassWorkgroup) {
+    if (storage_class == spv::StorageClass::Workgroup) {
       assert(false &&
              "By construction this transformation should not have an "
              "initializer when Workgroup storage class is used.");
@@ -95,7 +95,7 @@
     TransformationContext* transformation_context) const {
   opt::Instruction* new_instruction = fuzzerutil::AddGlobalVariable(
       ir_context, message_.fresh_id(), message_.type_id(),
-      static_cast<SpvStorageClass>(message_.storage_class()),
+      static_cast<spv::StorageClass>(message_.storage_class()),
       message_.initializer_id());
 
   // Inform the def-use manager about the new instruction.
diff --git a/source/fuzz/transformation_add_global_variable.h b/source/fuzz/transformation_add_global_variable.h
index d74d48a..0178219 100644
--- a/source/fuzz/transformation_add_global_variable.h
+++ b/source/fuzz/transformation_add_global_variable.h
@@ -29,7 +29,7 @@
       protobufs::TransformationAddGlobalVariable message);
 
   TransformationAddGlobalVariable(uint32_t fresh_id, uint32_t type_id,
-                                  SpvStorageClass storage_class,
+                                  spv::StorageClass storage_class,
                                   uint32_t initializer_id,
                                   bool value_is_irrelevant);
 
diff --git a/source/fuzz/transformation_add_image_sample_unused_components.cpp b/source/fuzz/transformation_add_image_sample_unused_components.cpp
index 1ead82b..018fed4 100644
--- a/source/fuzz/transformation_add_image_sample_unused_components.cpp
+++ b/source/fuzz/transformation_add_image_sample_unused_components.cpp
@@ -73,7 +73,7 @@
   // It must be an OpCompositeConstruct instruction such that it can be checked
   // that the original components are present.
   if (coordinate_with_unused_components_instruction->opcode() !=
-      SpvOpCompositeConstruct) {
+      spv::Op::OpCompositeConstruct) {
     return false;
   }
 
diff --git a/source/fuzz/transformation_add_local_variable.cpp b/source/fuzz/transformation_add_local_variable.cpp
index 21768d2..9ee210c 100644
--- a/source/fuzz/transformation_add_local_variable.cpp
+++ b/source/fuzz/transformation_add_local_variable.cpp
@@ -43,8 +43,10 @@
   // function storage class.
   auto type_instruction =
       ir_context->get_def_use_mgr()->GetDef(message_.type_id());
-  if (!type_instruction || type_instruction->opcode() != SpvOpTypePointer ||
-      type_instruction->GetSingleWordInOperand(0) != SpvStorageClassFunction) {
+  if (!type_instruction ||
+      type_instruction->opcode() != spv::Op::OpTypePointer ||
+      spv::StorageClass(type_instruction->GetSingleWordInOperand(0)) !=
+          spv::StorageClass::Function) {
     return false;
   }
   // The initializer must...
diff --git a/source/fuzz/transformation_add_loop_preheader.cpp b/source/fuzz/transformation_add_loop_preheader.cpp
index 71ab18d..4b66b69 100644
--- a/source/fuzz/transformation_add_loop_preheader.cpp
+++ b/source/fuzz/transformation_add_loop_preheader.cpp
@@ -120,8 +120,8 @@
         // If |use_inst| is not a branch or merge instruction, it should not be
         // changed.
         if (!use_inst->IsBranch() &&
-            use_inst->opcode() != SpvOpSelectionMerge &&
-            use_inst->opcode() != SpvOpLoopMerge) {
+            use_inst->opcode() != spv::Op::OpSelectionMerge &&
+            use_inst->opcode() != spv::Op::OpLoopMerge) {
           return;
         }
 
@@ -134,7 +134,7 @@
   // Make a new block for the preheader.
   std::unique_ptr<opt::BasicBlock> preheader = MakeUnique<opt::BasicBlock>(
       std::unique_ptr<opt::Instruction>(new opt::Instruction(
-          ir_context, SpvOpLabel, 0, message_.fresh_id(), {})));
+          ir_context, spv::Op::OpLabel, 0, message_.fresh_id(), {})));
 
   uint32_t phi_ids_used = 0;
 
@@ -183,7 +183,7 @@
       fuzzerutil::UpdateModuleIdBound(ir_context, fresh_phi_id);
 
       preheader->AddInstruction(std::unique_ptr<opt::Instruction>(
-          new opt::Instruction(ir_context, SpvOpPhi, phi_inst->type_id(),
+          new opt::Instruction(ir_context, spv::Op::OpPhi, phi_inst->type_id(),
                                fresh_phi_id, preheader_in_operands)));
 
       // Update the OpPhi instruction in the header so that it refers to the
@@ -202,7 +202,7 @@
   // Add an unconditional branch from the preheader to the header.
   preheader->AddInstruction(
       std::unique_ptr<opt::Instruction>(new opt::Instruction(
-          ir_context, SpvOpBranch, 0, 0,
+          ir_context, spv::Op::OpBranch, 0, 0,
           std::initializer_list<opt::Operand>{opt::Operand(
               spv_operand_type_t::SPV_OPERAND_TYPE_ID, {loop_header->id()})})));
 
diff --git a/source/fuzz/transformation_add_loop_to_create_int_constant_synonym.cpp b/source/fuzz/transformation_add_loop_to_create_int_constant_synonym.cpp
index 657fafa..00030e7 100644
--- a/source/fuzz/transformation_add_loop_to_create_int_constant_synonym.cpp
+++ b/source/fuzz/transformation_add_loop_to_create_int_constant_synonym.cpp
@@ -262,13 +262,13 @@
   // Create the loop header block.
   std::unique_ptr<opt::BasicBlock> loop_block =
       MakeUnique<opt::BasicBlock>(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpLabel, 0, message_.loop_id(),
+          ir_context, spv::Op::OpLabel, 0, message_.loop_id(),
           opt::Instruction::OperandList{}));
 
   // Add OpPhi instructions to retrieve the current value of the counter and of
   // the temporary variable that will be decreased at each operation.
   loop_block->AddInstruction(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpPhi, const_0_def->type_id(), message_.ctr_id(),
+      ir_context, spv::Op::OpPhi, const_0_def->type_id(), message_.ctr_id(),
       opt::Instruction::OperandList{
           {SPV_OPERAND_TYPE_ID, {const_0_id}},
           {SPV_OPERAND_TYPE_ID, {pred_id}},
@@ -276,7 +276,8 @@
           {SPV_OPERAND_TYPE_ID, {last_loop_block_id}}}));
 
   loop_block->AddInstruction(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpPhi, initial_val_def->type_id(), message_.temp_id(),
+      ir_context, spv::Op::OpPhi, initial_val_def->type_id(),
+      message_.temp_id(),
       opt::Instruction::OperandList{
           {SPV_OPERAND_TYPE_ID, {message_.initial_val_id()}},
           {SPV_OPERAND_TYPE_ID, {pred_id}},
@@ -291,7 +292,7 @@
   // Add an instruction to subtract the step value from the temporary value.
   // The value of this id will converge to the constant in the last iteration.
   other_instructions.push_back(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpISub, initial_val_def->type_id(),
+      ir_context, spv::Op::OpISub, initial_val_def->type_id(),
       message_.eventual_syn_id(),
       opt::Instruction::OperandList{
           {SPV_OPERAND_TYPE_ID, {message_.temp_id()}},
@@ -299,15 +300,15 @@
 
   // Add an instruction to increment the counter.
   other_instructions.push_back(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpIAdd, const_0_def->type_id(),
+      ir_context, spv::Op::OpIAdd, const_0_def->type_id(),
       message_.incremented_ctr_id(),
       opt::Instruction::OperandList{{SPV_OPERAND_TYPE_ID, {message_.ctr_id()}},
                                     {SPV_OPERAND_TYPE_ID, {const_1_id}}}));
 
   // Add an instruction to decide whether the condition holds.
   other_instructions.push_back(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpSLessThan, fuzzerutil::MaybeGetBoolType(ir_context),
-      message_.cond_id(),
+      ir_context, spv::Op::OpSLessThan,
+      fuzzerutil::MaybeGetBoolType(ir_context), message_.cond_id(),
       opt::Instruction::OperandList{
           {SPV_OPERAND_TYPE_ID, {message_.incremented_ctr_id()}},
           {SPV_OPERAND_TYPE_ID, {message_.num_iterations_id()}}}));
@@ -316,18 +317,19 @@
   // the existing block, the continue block is the last block in the loop
   // (either the loop itself or the additional block).
   std::unique_ptr<opt::Instruction> merge_inst = MakeUnique<opt::Instruction>(
-      ir_context, SpvOpLoopMerge, 0, 0,
+      ir_context, spv::Op::OpLoopMerge, 0, 0,
       opt::Instruction::OperandList{
           {SPV_OPERAND_TYPE_ID, {message_.block_after_loop_id()}},
           {SPV_OPERAND_TYPE_ID, {last_loop_block_id}},
-          {SPV_OPERAND_TYPE_LOOP_CONTROL, {SpvLoopControlMaskNone}}});
+          {SPV_OPERAND_TYPE_LOOP_CONTROL,
+           {uint32_t(spv::LoopControlMask::MaskNone)}}});
 
   // Define a conditional branch instruction, branching to the loop header if
   // the condition holds, and to the existing block otherwise. This instruction
   // will be added to the last block in the loop.
   std::unique_ptr<opt::Instruction> conditional_branch =
       MakeUnique<opt::Instruction>(
-          ir_context, SpvOpBranchConditional, 0, 0,
+          ir_context, spv::Op::OpBranchConditional, 0, 0,
           opt::Instruction::OperandList{
               {SPV_OPERAND_TYPE_ID, {message_.cond_id()}},
               {SPV_OPERAND_TYPE_ID, {message_.loop_id()}},
@@ -340,7 +342,7 @@
 
     std::unique_ptr<opt::BasicBlock> additional_block =
         MakeUnique<opt::BasicBlock>(MakeUnique<opt::Instruction>(
-            ir_context, SpvOpLabel, 0, message_.additional_block_id(),
+            ir_context, spv::Op::OpLabel, 0, message_.additional_block_id(),
             opt::Instruction::OperandList{}));
 
     for (auto& instruction : other_instructions) {
@@ -354,7 +356,7 @@
 
     // Add an unconditional branch from the header to the additional block.
     loop_block->AddInstruction(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpBranch, 0, 0,
+        ir_context, spv::Op::OpBranch, 0, 0,
         opt::Instruction::OperandList{
             {SPV_OPERAND_TYPE_ID, {message_.additional_block_id()}}}));
 
@@ -384,14 +386,14 @@
   ir_context->get_def_use_mgr()->ForEachUse(
       message_.block_after_loop_id(),
       [this](opt::Instruction* instruction, uint32_t operand_index) {
-        assert(instruction->opcode() != SpvOpLoopMerge &&
-               instruction->opcode() != SpvOpSelectionMerge &&
+        assert(instruction->opcode() != spv::Op::OpLoopMerge &&
+               instruction->opcode() != spv::Op::OpSelectionMerge &&
                "The block should not be referenced by OpLoopMerge or "
                "OpSelectionMerge, by construction.");
         // Replace all uses of the label inside branch instructions.
-        if (instruction->opcode() == SpvOpBranch ||
-            instruction->opcode() == SpvOpBranchConditional ||
-            instruction->opcode() == SpvOpSwitch) {
+        if (instruction->opcode() == spv::Op::OpBranch ||
+            instruction->opcode() == spv::Op::OpBranchConditional ||
+            instruction->opcode() == spv::Op::OpSwitch) {
           instruction->SetOperand(operand_index, {message_.loop_id()});
         }
       });
@@ -410,7 +412,7 @@
   // |message_.initial_value_id|, since this is the value that is decremented in
   // the loop.
   block_after_loop->begin()->InsertBefore(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpPhi, initial_val_def->type_id(), message_.syn_id(),
+      ir_context, spv::Op::OpPhi, initial_val_def->type_id(), message_.syn_id(),
       opt::Instruction::OperandList{
           {SPV_OPERAND_TYPE_ID, {message_.eventual_syn_id()}},
           {SPV_OPERAND_TYPE_ID, {last_loop_block_id}}}));
diff --git a/source/fuzz/transformation_add_no_contraction_decoration.cpp b/source/fuzz/transformation_add_no_contraction_decoration.cpp
index 992a216..07a31e5 100644
--- a/source/fuzz/transformation_add_no_contraction_decoration.cpp
+++ b/source/fuzz/transformation_add_no_contraction_decoration.cpp
@@ -43,8 +43,8 @@
 void TransformationAddNoContractionDecoration::Apply(
     opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
   // Add a NoContraction decoration targeting |message_.result_id|.
-  ir_context->get_decoration_mgr()->AddDecoration(message_.result_id(),
-                                                  SpvDecorationNoContraction);
+  ir_context->get_decoration_mgr()->AddDecoration(
+      message_.result_id(), uint32_t(spv::Decoration::NoContraction));
 }
 
 protobufs::Transformation TransformationAddNoContractionDecoration::ToMessage()
@@ -54,50 +54,50 @@
   return result;
 }
 
-bool TransformationAddNoContractionDecoration::IsArithmetic(uint32_t opcode) {
+bool TransformationAddNoContractionDecoration::IsArithmetic(spv::Op opcode) {
   switch (opcode) {
-    case SpvOpSNegate:
-    case SpvOpFNegate:
-    case SpvOpIAdd:
-    case SpvOpFAdd:
-    case SpvOpISub:
-    case SpvOpFSub:
-    case SpvOpIMul:
-    case SpvOpFMul:
-    case SpvOpUDiv:
-    case SpvOpSDiv:
-    case SpvOpFDiv:
-    case SpvOpUMod:
-    case SpvOpSRem:
-    case SpvOpSMod:
-    case SpvOpFRem:
-    case SpvOpFMod:
-    case SpvOpVectorTimesScalar:
-    case SpvOpMatrixTimesScalar:
-    case SpvOpVectorTimesMatrix:
-    case SpvOpMatrixTimesVector:
-    case SpvOpMatrixTimesMatrix:
-    case SpvOpOuterProduct:
-    case SpvOpDot:
-    case SpvOpIAddCarry:
-    case SpvOpISubBorrow:
-    case SpvOpUMulExtended:
-    case SpvOpSMulExtended:
-    case SpvOpAny:
-    case SpvOpAll:
-    case SpvOpIsNan:
-    case SpvOpIsInf:
-    case SpvOpIsFinite:
-    case SpvOpIsNormal:
-    case SpvOpSignBitSet:
-    case SpvOpLessOrGreater:
-    case SpvOpOrdered:
-    case SpvOpUnordered:
-    case SpvOpLogicalEqual:
-    case SpvOpLogicalNotEqual:
-    case SpvOpLogicalOr:
-    case SpvOpLogicalAnd:
-    case SpvOpLogicalNot:
+    case spv::Op::OpSNegate:
+    case spv::Op::OpFNegate:
+    case spv::Op::OpIAdd:
+    case spv::Op::OpFAdd:
+    case spv::Op::OpISub:
+    case spv::Op::OpFSub:
+    case spv::Op::OpIMul:
+    case spv::Op::OpFMul:
+    case spv::Op::OpUDiv:
+    case spv::Op::OpSDiv:
+    case spv::Op::OpFDiv:
+    case spv::Op::OpUMod:
+    case spv::Op::OpSRem:
+    case spv::Op::OpSMod:
+    case spv::Op::OpFRem:
+    case spv::Op::OpFMod:
+    case spv::Op::OpVectorTimesScalar:
+    case spv::Op::OpMatrixTimesScalar:
+    case spv::Op::OpVectorTimesMatrix:
+    case spv::Op::OpMatrixTimesVector:
+    case spv::Op::OpMatrixTimesMatrix:
+    case spv::Op::OpOuterProduct:
+    case spv::Op::OpDot:
+    case spv::Op::OpIAddCarry:
+    case spv::Op::OpISubBorrow:
+    case spv::Op::OpUMulExtended:
+    case spv::Op::OpSMulExtended:
+    case spv::Op::OpAny:
+    case spv::Op::OpAll:
+    case spv::Op::OpIsNan:
+    case spv::Op::OpIsInf:
+    case spv::Op::OpIsFinite:
+    case spv::Op::OpIsNormal:
+    case spv::Op::OpSignBitSet:
+    case spv::Op::OpLessOrGreater:
+    case spv::Op::OpOrdered:
+    case spv::Op::OpUnordered:
+    case spv::Op::OpLogicalEqual:
+    case spv::Op::OpLogicalNotEqual:
+    case spv::Op::OpLogicalOr:
+    case spv::Op::OpLogicalAnd:
+    case spv::Op::OpLogicalNot:
       return true;
     default:
       return false;
diff --git a/source/fuzz/transformation_add_no_contraction_decoration.h b/source/fuzz/transformation_add_no_contraction_decoration.h
index 2f78d42..4235dc1 100644
--- a/source/fuzz/transformation_add_no_contraction_decoration.h
+++ b/source/fuzz/transformation_add_no_contraction_decoration.h
@@ -50,7 +50,7 @@
 
   // Returns true if and only if |opcode| is the opcode of an arithmetic
   // instruction, as defined by the SPIR-V specification.
-  static bool IsArithmetic(uint32_t opcode);
+  static bool IsArithmetic(spv::Op opcode);
 
  private:
   protobufs::TransformationAddNoContractionDecoration message_;
diff --git a/source/fuzz/transformation_add_opphi_synonym.cpp b/source/fuzz/transformation_add_opphi_synonym.cpp
index 3c4698a..31c56b6 100644
--- a/source/fuzz/transformation_add_opphi_synonym.cpp
+++ b/source/fuzz/transformation_add_opphi_synonym.cpp
@@ -142,8 +142,8 @@
   // Add a new OpPhi instructions at the beginning of the block.
   ir_context->get_instr_block(message_.block_id())
       ->begin()
-      .InsertBefore(MakeUnique<opt::Instruction>(ir_context, SpvOpPhi, type_id,
-                                                 message_.fresh_id(),
+      .InsertBefore(MakeUnique<opt::Instruction>(ir_context, spv::Op::OpPhi,
+                                                 type_id, message_.fresh_id(),
                                                  std::move(operand_list)));
 
   // Update the module id bound.
@@ -186,9 +186,9 @@
   if (type->AsPointer()) {
     auto storage_class = type->AsPointer()->storage_class();
     return ir_context->get_feature_mgr()->HasCapability(
-               SpvCapabilityVariablePointers) &&
-           (storage_class == SpvStorageClassWorkgroup ||
-            storage_class == SpvStorageClassStorageBuffer);
+               spv::Capability::VariablePointers) &&
+           (storage_class == spv::StorageClass::Workgroup ||
+            storage_class == spv::StorageClass::StorageBuffer);
   }
 
   // We do not allow other types.
diff --git a/source/fuzz/transformation_add_parameter.cpp b/source/fuzz/transformation_add_parameter.cpp
index 48de3e8..8bd2ed7 100644
--- a/source/fuzz/transformation_add_parameter.cpp
+++ b/source/fuzz/transformation_add_parameter.cpp
@@ -112,7 +112,7 @@
 
   // Add new parameters to the function.
   function->AddParameter(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpFunctionParameter, new_parameter_type_id,
+      ir_context, spv::Op::OpFunctionParameter, new_parameter_type_id,
       message_.parameter_fresh_id(), opt::Instruction::OperandList()));
 
   fuzzerutil::UpdateModuleIdBound(ir_context, message_.parameter_fresh_id());
@@ -178,16 +178,16 @@
   //  Think about other type instructions we can add here.
   opt::Instruction* type_inst = ir_context->get_def_use_mgr()->GetDef(type_id);
   switch (type_inst->opcode()) {
-    case SpvOpTypeBool:
-    case SpvOpTypeInt:
-    case SpvOpTypeFloat:
-    case SpvOpTypeMatrix:
-    case SpvOpTypeVector:
+    case spv::Op::OpTypeBool:
+    case spv::Op::OpTypeInt:
+    case spv::Op::OpTypeFloat:
+    case spv::Op::OpTypeMatrix:
+    case spv::Op::OpTypeVector:
       return true;
-    case SpvOpTypeArray:
+    case spv::Op::OpTypeArray:
       return IsParameterTypeSupported(ir_context,
                                       type_inst->GetSingleWordInOperand(0));
-    case SpvOpTypeStruct:
+    case spv::Op::OpTypeStruct:
       if (fuzzerutil::HasBlockOrBufferBlockDecoration(ir_context, type_id)) {
         return false;
       }
@@ -198,13 +198,13 @@
         }
       }
       return true;
-    case SpvOpTypePointer: {
-      SpvStorageClass storage_class =
-          static_cast<SpvStorageClass>(type_inst->GetSingleWordInOperand(0));
+    case spv::Op::OpTypePointer: {
+      spv::StorageClass storage_class =
+          static_cast<spv::StorageClass>(type_inst->GetSingleWordInOperand(0));
       switch (storage_class) {
-        case SpvStorageClassPrivate:
-        case SpvStorageClassFunction:
-        case SpvStorageClassWorkgroup: {
+        case spv::StorageClass::Private:
+        case spv::StorageClass::Function:
+        case spv::StorageClass::Workgroup: {
           return IsParameterTypeSupported(ir_context,
                                           type_inst->GetSingleWordInOperand(1));
         }
diff --git a/source/fuzz/transformation_add_relaxed_decoration.cpp b/source/fuzz/transformation_add_relaxed_decoration.cpp
index b66a1a8..6cd4ecb 100644
--- a/source/fuzz/transformation_add_relaxed_decoration.cpp
+++ b/source/fuzz/transformation_add_relaxed_decoration.cpp
@@ -54,7 +54,7 @@
     opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
   // Add a RelaxedPrecision decoration targeting |message_.result_id|.
   ir_context->get_decoration_mgr()->AddDecoration(
-      message_.result_id(), SpvDecorationRelaxedPrecision);
+      message_.result_id(), uint32_t(spv::Decoration::RelaxedPrecision));
 }
 
 protobufs::Transformation TransformationAddRelaxedDecoration::ToMessage()
@@ -64,77 +64,77 @@
   return result;
 }
 
-bool TransformationAddRelaxedDecoration::IsNumeric(uint32_t opcode) {
+bool TransformationAddRelaxedDecoration::IsNumeric(spv::Op opcode) {
   switch (opcode) {
-    case SpvOpConvertFToU:
-    case SpvOpConvertFToS:
-    case SpvOpConvertSToF:
-    case SpvOpConvertUToF:
-    case SpvOpUConvert:
-    case SpvOpSConvert:
-    case SpvOpFConvert:
-    case SpvOpConvertPtrToU:
-    case SpvOpSatConvertSToU:
-    case SpvOpSatConvertUToS:
-    case SpvOpVectorExtractDynamic:
-    case SpvOpVectorInsertDynamic:
-    case SpvOpVectorShuffle:
-    case SpvOpTranspose:
-    case SpvOpSNegate:
-    case SpvOpFNegate:
-    case SpvOpIAdd:
-    case SpvOpFAdd:
-    case SpvOpISub:
-    case SpvOpFSub:
-    case SpvOpIMul:
-    case SpvOpFMul:
-    case SpvOpUDiv:
-    case SpvOpSDiv:
-    case SpvOpFDiv:
-    case SpvOpUMod:
-    case SpvOpSRem:
-    case SpvOpSMod:
-    case SpvOpFRem:
-    case SpvOpFMod:
-    case SpvOpVectorTimesScalar:
-    case SpvOpMatrixTimesScalar:
-    case SpvOpVectorTimesMatrix:
-    case SpvOpMatrixTimesVector:
-    case SpvOpMatrixTimesMatrix:
-    case SpvOpOuterProduct:
-    case SpvOpDot:
-    case SpvOpIAddCarry:
-    case SpvOpISubBorrow:
-    case SpvOpUMulExtended:
-    case SpvOpSMulExtended:
-    case SpvOpShiftRightLogical:
-    case SpvOpShiftRightArithmetic:
-    case SpvOpShiftLeftLogical:
-    case SpvOpBitwiseOr:
-    case SpvOpBitwiseXor:
-    case SpvOpBitwiseAnd:
-    case SpvOpNot:
-    case SpvOpBitFieldInsert:
-    case SpvOpBitFieldSExtract:
-    case SpvOpBitFieldUExtract:
-    case SpvOpBitReverse:
-    case SpvOpBitCount:
-    case SpvOpAtomicLoad:
-    case SpvOpAtomicStore:
-    case SpvOpAtomicExchange:
-    case SpvOpAtomicCompareExchange:
-    case SpvOpAtomicCompareExchangeWeak:
-    case SpvOpAtomicIIncrement:
-    case SpvOpAtomicIDecrement:
-    case SpvOpAtomicIAdd:
-    case SpvOpAtomicISub:
-    case SpvOpAtomicSMin:
-    case SpvOpAtomicUMin:
-    case SpvOpAtomicSMax:
-    case SpvOpAtomicUMax:
-    case SpvOpAtomicAnd:
-    case SpvOpAtomicOr:
-    case SpvOpAtomicXor:
+    case spv::Op::OpConvertFToU:
+    case spv::Op::OpConvertFToS:
+    case spv::Op::OpConvertSToF:
+    case spv::Op::OpConvertUToF:
+    case spv::Op::OpUConvert:
+    case spv::Op::OpSConvert:
+    case spv::Op::OpFConvert:
+    case spv::Op::OpConvertPtrToU:
+    case spv::Op::OpSatConvertSToU:
+    case spv::Op::OpSatConvertUToS:
+    case spv::Op::OpVectorExtractDynamic:
+    case spv::Op::OpVectorInsertDynamic:
+    case spv::Op::OpVectorShuffle:
+    case spv::Op::OpTranspose:
+    case spv::Op::OpSNegate:
+    case spv::Op::OpFNegate:
+    case spv::Op::OpIAdd:
+    case spv::Op::OpFAdd:
+    case spv::Op::OpISub:
+    case spv::Op::OpFSub:
+    case spv::Op::OpIMul:
+    case spv::Op::OpFMul:
+    case spv::Op::OpUDiv:
+    case spv::Op::OpSDiv:
+    case spv::Op::OpFDiv:
+    case spv::Op::OpUMod:
+    case spv::Op::OpSRem:
+    case spv::Op::OpSMod:
+    case spv::Op::OpFRem:
+    case spv::Op::OpFMod:
+    case spv::Op::OpVectorTimesScalar:
+    case spv::Op::OpMatrixTimesScalar:
+    case spv::Op::OpVectorTimesMatrix:
+    case spv::Op::OpMatrixTimesVector:
+    case spv::Op::OpMatrixTimesMatrix:
+    case spv::Op::OpOuterProduct:
+    case spv::Op::OpDot:
+    case spv::Op::OpIAddCarry:
+    case spv::Op::OpISubBorrow:
+    case spv::Op::OpUMulExtended:
+    case spv::Op::OpSMulExtended:
+    case spv::Op::OpShiftRightLogical:
+    case spv::Op::OpShiftRightArithmetic:
+    case spv::Op::OpShiftLeftLogical:
+    case spv::Op::OpBitwiseOr:
+    case spv::Op::OpBitwiseXor:
+    case spv::Op::OpBitwiseAnd:
+    case spv::Op::OpNot:
+    case spv::Op::OpBitFieldInsert:
+    case spv::Op::OpBitFieldSExtract:
+    case spv::Op::OpBitFieldUExtract:
+    case spv::Op::OpBitReverse:
+    case spv::Op::OpBitCount:
+    case spv::Op::OpAtomicLoad:
+    case spv::Op::OpAtomicStore:
+    case spv::Op::OpAtomicExchange:
+    case spv::Op::OpAtomicCompareExchange:
+    case spv::Op::OpAtomicCompareExchangeWeak:
+    case spv::Op::OpAtomicIIncrement:
+    case spv::Op::OpAtomicIDecrement:
+    case spv::Op::OpAtomicIAdd:
+    case spv::Op::OpAtomicISub:
+    case spv::Op::OpAtomicSMin:
+    case spv::Op::OpAtomicUMin:
+    case spv::Op::OpAtomicSMax:
+    case spv::Op::OpAtomicUMax:
+    case spv::Op::OpAtomicAnd:
+    case spv::Op::OpAtomicOr:
+    case spv::Op::OpAtomicXor:
       return true;
     default:
       return false;
@@ -147,4 +147,4 @@
 }
 
 }  // namespace fuzz
-}  // namespace spvtools
\ No newline at end of file
+}  // namespace spvtools
diff --git a/source/fuzz/transformation_add_relaxed_decoration.h b/source/fuzz/transformation_add_relaxed_decoration.h
index c016349..e13594e 100644
--- a/source/fuzz/transformation_add_relaxed_decoration.h
+++ b/source/fuzz/transformation_add_relaxed_decoration.h
@@ -52,7 +52,7 @@
   // Returns true if and only if |opcode| is the opcode of an instruction
   // that operates on 32-bit integers and 32-bit floats
   // as defined by the SPIR-V specification.
-  static bool IsNumeric(uint32_t opcode);
+  static bool IsNumeric(spv::Op opcode);
 
  private:
   protobufs::TransformationAddRelaxedDecoration message_;
diff --git a/source/fuzz/transformation_add_spec_constant_op.cpp b/source/fuzz/transformation_add_spec_constant_op.cpp
index 19c5e85..685f0a4 100644
--- a/source/fuzz/transformation_add_spec_constant_op.cpp
+++ b/source/fuzz/transformation_add_spec_constant_op.cpp
@@ -26,11 +26,11 @@
     : message_(std::move(message)) {}
 
 TransformationAddSpecConstantOp::TransformationAddSpecConstantOp(
-    uint32_t fresh_id, uint32_t type_id, SpvOp opcode,
+    uint32_t fresh_id, uint32_t type_id, spv::Op opcode,
     const opt::Instruction::OperandList& operands) {
   message_.set_fresh_id(fresh_id);
   message_.set_type_id(type_id);
-  message_.set_opcode(opcode);
+  message_.set_opcode(uint32_t(opcode));
   for (const auto& operand : operands) {
     auto* op = message_.add_operand();
     op->set_operand_type(operand.type);
@@ -70,8 +70,8 @@
   }
 
   ir_context->AddGlobalValue(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpSpecConstantOp, message_.type_id(), message_.fresh_id(),
-      std::move(operands)));
+      ir_context, spv::Op::OpSpecConstantOp, message_.type_id(),
+      message_.fresh_id(), std::move(operands)));
 
   fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
 }
diff --git a/source/fuzz/transformation_add_spec_constant_op.h b/source/fuzz/transformation_add_spec_constant_op.h
index 29851fd..665f66a 100644
--- a/source/fuzz/transformation_add_spec_constant_op.h
+++ b/source/fuzz/transformation_add_spec_constant_op.h
@@ -29,7 +29,7 @@
       protobufs::TransformationAddSpecConstantOp message);
 
   TransformationAddSpecConstantOp(
-      uint32_t fresh_id, uint32_t type_id, SpvOp opcode,
+      uint32_t fresh_id, uint32_t type_id, spv::Op opcode,
       const opt::Instruction::OperandList& operands);
 
   // - |fresh_id| is a fresh result id in the module.
diff --git a/source/fuzz/transformation_add_synonym.cpp b/source/fuzz/transformation_add_synonym.cpp
index 69269e5..00df9cf 100644
--- a/source/fuzz/transformation_add_synonym.cpp
+++ b/source/fuzz/transformation_add_synonym.cpp
@@ -82,7 +82,7 @@
   // Check that we can insert |message._synonymous_instruction| before
   // |message_.insert_before| instruction. We use OpIAdd to represent some
   // instruction that can produce a synonym.
-  if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpIAdd,
+  if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpIAdd,
                                                     insert_before_inst)) {
     return false;
   }
@@ -147,7 +147,8 @@
   // Instruction must have a result id, type id. We skip OpUndef and
   // OpConstantNull.
   if (!inst || !inst->result_id() || !inst->type_id() ||
-      inst->opcode() == SpvOpUndef || inst->opcode() == SpvOpConstantNull) {
+      inst->opcode() == spv::Op::OpUndef ||
+      inst->opcode() == spv::Op::OpConstantNull) {
     return false;
   }
 
@@ -208,7 +209,7 @@
   auto synonym_type_id =
       fuzzerutil::GetTypeId(ir_context, message_.result_id());
   assert(synonym_type_id && "Synonym has invalid type id");
-  auto opcode = SpvOpNop;
+  auto opcode = spv::Op::OpNop;
   const auto* synonym_type =
       ir_context->get_type_mgr()->GetType(synonym_type_id);
   assert(synonym_type && "Synonym has invalid type");
@@ -219,30 +220,30 @@
 
   switch (message_.synonym_type()) {
     case protobufs::TransformationAddSynonym::SUB_ZERO:
-      opcode = is_integral ? SpvOpISub : SpvOpFSub;
+      opcode = is_integral ? spv::Op::OpISub : spv::Op::OpFSub;
       break;
     case protobufs::TransformationAddSynonym::MUL_ONE:
-      opcode = is_integral ? SpvOpIMul : SpvOpFMul;
+      opcode = is_integral ? spv::Op::OpIMul : spv::Op::OpFMul;
       break;
     case protobufs::TransformationAddSynonym::ADD_ZERO:
-      opcode = is_integral ? SpvOpIAdd : SpvOpFAdd;
+      opcode = is_integral ? spv::Op::OpIAdd : spv::Op::OpFAdd;
       break;
     case protobufs::TransformationAddSynonym::LOGICAL_OR:
-      opcode = SpvOpLogicalOr;
+      opcode = spv::Op::OpLogicalOr;
       break;
     case protobufs::TransformationAddSynonym::LOGICAL_AND:
-      opcode = SpvOpLogicalAnd;
+      opcode = spv::Op::OpLogicalAnd;
       break;
     case protobufs::TransformationAddSynonym::BITWISE_OR:
-      opcode = SpvOpBitwiseOr;
+      opcode = spv::Op::OpBitwiseOr;
       break;
     case protobufs::TransformationAddSynonym::BITWISE_XOR:
-      opcode = SpvOpBitwiseXor;
+      opcode = spv::Op::OpBitwiseXor;
       break;
 
     case protobufs::TransformationAddSynonym::COPY_OBJECT:
       return MakeUnique<opt::Instruction>(
-          ir_context, SpvOpCopyObject, synonym_type_id,
+          ir_context, spv::Op::OpCopyObject, synonym_type_id,
           message_.synonym_fresh_id(),
           opt::Instruction::OperandList{
               {SPV_OPERAND_TYPE_ID, {message_.result_id()}}});
diff --git a/source/fuzz/transformation_add_type_array.cpp b/source/fuzz/transformation_add_type_array.cpp
index 45bc8df..d00d0e4 100644
--- a/source/fuzz/transformation_add_type_array.cpp
+++ b/source/fuzz/transformation_add_type_array.cpp
@@ -72,7 +72,7 @@
   in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.element_type_id()}});
   in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.size_id()}});
   auto type_instruction = MakeUnique<opt::Instruction>(
-      ir_context, SpvOpTypeArray, 0, message_.fresh_id(), in_operands);
+      ir_context, spv::Op::OpTypeArray, 0, message_.fresh_id(), in_operands);
   auto type_instruction_ptr = type_instruction.get();
   ir_context->module()->AddType(std::move(type_instruction));
 
diff --git a/source/fuzz/transformation_add_type_boolean.cpp b/source/fuzz/transformation_add_type_boolean.cpp
index 30ff43e..47fc744 100644
--- a/source/fuzz/transformation_add_type_boolean.cpp
+++ b/source/fuzz/transformation_add_type_boolean.cpp
@@ -43,7 +43,7 @@
     opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
   opt::Instruction::OperandList empty_operands;
   auto type_instruction = MakeUnique<opt::Instruction>(
-      ir_context, SpvOpTypeBool, 0, message_.fresh_id(), empty_operands);
+      ir_context, spv::Op::OpTypeBool, 0, message_.fresh_id(), empty_operands);
   auto type_instruction_ptr = type_instruction.get();
   ir_context->module()->AddType(std::move(type_instruction));
 
diff --git a/source/fuzz/transformation_add_type_float.cpp b/source/fuzz/transformation_add_type_float.cpp
index 1b88b25..1943ffa 100644
--- a/source/fuzz/transformation_add_type_float.cpp
+++ b/source/fuzz/transformation_add_type_float.cpp
@@ -40,7 +40,8 @@
   switch (message_.width()) {
     case 16:
       // The Float16 capability must be present.
-      if (!ir_context->get_feature_mgr()->HasCapability(SpvCapabilityFloat16)) {
+      if (!ir_context->get_feature_mgr()->HasCapability(
+              spv::Capability::Float16)) {
         return false;
       }
       break;
@@ -49,7 +50,8 @@
       break;
     case 64:
       // The Float64 capability must be present.
-      if (!ir_context->get_feature_mgr()->HasCapability(SpvCapabilityFloat64)) {
+      if (!ir_context->get_feature_mgr()->HasCapability(
+              spv::Capability::Float64)) {
         return false;
       }
       break;
@@ -66,7 +68,7 @@
 void TransformationAddTypeFloat::Apply(
     opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
   auto type_instruction = MakeUnique<opt::Instruction>(
-      ir_context, SpvOpTypeFloat, 0, message_.fresh_id(),
+      ir_context, spv::Op::OpTypeFloat, 0, message_.fresh_id(),
       opt::Instruction::OperandList{
           {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.width()}}});
   auto type_instruction_ptr = type_instruction.get();
diff --git a/source/fuzz/transformation_add_type_int.cpp b/source/fuzz/transformation_add_type_int.cpp
index d4ef981..35663f9 100644
--- a/source/fuzz/transformation_add_type_int.cpp
+++ b/source/fuzz/transformation_add_type_int.cpp
@@ -42,13 +42,15 @@
   switch (message_.width()) {
     case 8:
       // The Int8 capability must be present.
-      if (!ir_context->get_feature_mgr()->HasCapability(SpvCapabilityInt8)) {
+      if (!ir_context->get_feature_mgr()->HasCapability(
+              spv::Capability::Int8)) {
         return false;
       }
       break;
     case 16:
       // The Int16 capability must be present.
-      if (!ir_context->get_feature_mgr()->HasCapability(SpvCapabilityInt16)) {
+      if (!ir_context->get_feature_mgr()->HasCapability(
+              spv::Capability::Int16)) {
         return false;
       }
       break;
@@ -57,7 +59,8 @@
       break;
     case 64:
       // The Int64 capability must be present.
-      if (!ir_context->get_feature_mgr()->HasCapability(SpvCapabilityInt64)) {
+      if (!ir_context->get_feature_mgr()->HasCapability(
+              spv::Capability::Int64)) {
         return false;
       }
       break;
@@ -75,7 +78,7 @@
 void TransformationAddTypeInt::Apply(opt::IRContext* ir_context,
                                      TransformationContext* /*unused*/) const {
   auto type_instruction = MakeUnique<opt::Instruction>(
-      ir_context, SpvOpTypeInt, 0, message_.fresh_id(),
+      ir_context, spv::Op::OpTypeInt, 0, message_.fresh_id(),
       opt::Instruction::OperandList{
           {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.width()}},
           {SPV_OPERAND_TYPE_LITERAL_INTEGER,
diff --git a/source/fuzz/transformation_add_type_matrix.cpp b/source/fuzz/transformation_add_type_matrix.cpp
index b574b01..e3f1786 100644
--- a/source/fuzz/transformation_add_type_matrix.cpp
+++ b/source/fuzz/transformation_add_type_matrix.cpp
@@ -53,7 +53,7 @@
   in_operands.push_back(
       {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.column_count()}});
   auto type_instruction = MakeUnique<opt::Instruction>(
-      ir_context, SpvOpTypeMatrix, 0, message_.fresh_id(), in_operands);
+      ir_context, spv::Op::OpTypeMatrix, 0, message_.fresh_id(), in_operands);
   auto type_instruction_ptr = type_instruction.get();
   ir_context->module()->AddType(std::move(type_instruction));
 
diff --git a/source/fuzz/transformation_add_type_pointer.cpp b/source/fuzz/transformation_add_type_pointer.cpp
index c6c3945..c112615 100644
--- a/source/fuzz/transformation_add_type_pointer.cpp
+++ b/source/fuzz/transformation_add_type_pointer.cpp
@@ -24,9 +24,9 @@
     : message_(std::move(message)) {}
 
 TransformationAddTypePointer::TransformationAddTypePointer(
-    uint32_t fresh_id, SpvStorageClass storage_class, uint32_t base_type_id) {
+    uint32_t fresh_id, spv::StorageClass storage_class, uint32_t base_type_id) {
   message_.set_fresh_id(fresh_id);
-  message_.set_storage_class(storage_class);
+  message_.set_storage_class(uint32_t(storage_class));
   message_.set_base_type_id(base_type_id);
 }
 
@@ -48,7 +48,7 @@
       {SPV_OPERAND_TYPE_STORAGE_CLASS, {message_.storage_class()}},
       {SPV_OPERAND_TYPE_ID, {message_.base_type_id()}}};
   auto type_instruction = MakeUnique<opt::Instruction>(
-      ir_context, SpvOpTypePointer, 0, message_.fresh_id(), in_operands);
+      ir_context, spv::Op::OpTypePointer, 0, message_.fresh_id(), in_operands);
   auto type_instruction_ptr = type_instruction.get();
   ir_context->module()->AddType(std::move(type_instruction));
 
diff --git a/source/fuzz/transformation_add_type_pointer.h b/source/fuzz/transformation_add_type_pointer.h
index 8468c14..e4ef9d8 100644
--- a/source/fuzz/transformation_add_type_pointer.h
+++ b/source/fuzz/transformation_add_type_pointer.h
@@ -28,7 +28,8 @@
   explicit TransformationAddTypePointer(
       protobufs::TransformationAddTypePointer message);
 
-  TransformationAddTypePointer(uint32_t fresh_id, SpvStorageClass storage_class,
+  TransformationAddTypePointer(uint32_t fresh_id,
+                               spv::StorageClass storage_class,
                                uint32_t base_type_id);
 
   // - |message_.fresh_id| must not be used by the module
diff --git a/source/fuzz/transformation_add_type_struct.cpp b/source/fuzz/transformation_add_type_struct.cpp
index d7f0711..95fbbba 100644
--- a/source/fuzz/transformation_add_type_struct.cpp
+++ b/source/fuzz/transformation_add_type_struct.cpp
@@ -79,8 +79,9 @@
     operands.push_back({SPV_OPERAND_TYPE_ID, {type_id}});
   }
 
-  auto type_instruction = MakeUnique<opt::Instruction>(
-      ir_context, SpvOpTypeStruct, 0, message_.fresh_id(), std::move(operands));
+  auto type_instruction =
+      MakeUnique<opt::Instruction>(ir_context, spv::Op::OpTypeStruct, 0,
+                                   message_.fresh_id(), std::move(operands));
   auto type_instruction_ptr = type_instruction.get();
   ir_context->AddType(std::move(type_instruction));
 
diff --git a/source/fuzz/transformation_add_type_vector.cpp b/source/fuzz/transformation_add_type_vector.cpp
index 4da0ff0..a7b0fa7 100644
--- a/source/fuzz/transformation_add_type_vector.cpp
+++ b/source/fuzz/transformation_add_type_vector.cpp
@@ -57,7 +57,7 @@
          "Precondition: component count must be in range [2, 4].");
 
   auto type_instruction = MakeUnique<opt::Instruction>(
-      ir_context, SpvOpTypeVector, 0, message_.fresh_id(),
+      ir_context, spv::Op::OpTypeVector, 0, message_.fresh_id(),
       opt::Instruction::OperandList{
           {SPV_OPERAND_TYPE_ID, {message_.component_type_id()}},
           {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.component_count()}}});
diff --git a/source/fuzz/transformation_adjust_branch_weights.cpp b/source/fuzz/transformation_adjust_branch_weights.cpp
index 21fef25..2651938 100644
--- a/source/fuzz/transformation_adjust_branch_weights.cpp
+++ b/source/fuzz/transformation_adjust_branch_weights.cpp
@@ -47,7 +47,7 @@
     return false;
   }
 
-  SpvOp opcode = static_cast<SpvOp>(
+  spv::Op opcode = static_cast<spv::Op>(
       message_.instruction_descriptor().target_instruction_opcode());
 
   assert(instruction->opcode() == opcode &&
@@ -55,7 +55,7 @@
          "descriptor.");
 
   // Must be an OpBranchConditional instruction.
-  if (opcode != SpvOpBranchConditional) {
+  if (opcode != spv::Op::OpBranchConditional) {
     return false;
   }
 
diff --git a/source/fuzz/transformation_composite_construct.cpp b/source/fuzz/transformation_composite_construct.cpp
index 2d8e599..075b33d 100644
--- a/source/fuzz/transformation_composite_construct.cpp
+++ b/source/fuzz/transformation_composite_construct.cpp
@@ -121,7 +121,7 @@
 
   // Insert an OpCompositeConstruct instruction.
   auto new_instruction = MakeUnique<opt::Instruction>(
-      ir_context, SpvOpCompositeConstruct, message_.composite_type_id(),
+      ir_context, spv::Op::OpCompositeConstruct, message_.composite_type_id(),
       message_.fresh_id(), in_operands);
   auto new_instruction_ptr = new_instruction.get();
   insert_before.InsertBefore(std::move(new_instruction));
diff --git a/source/fuzz/transformation_composite_extract.cpp b/source/fuzz/transformation_composite_extract.cpp
index 0fbd4e1..7118432 100644
--- a/source/fuzz/transformation_composite_extract.cpp
+++ b/source/fuzz/transformation_composite_extract.cpp
@@ -67,7 +67,7 @@
   }
 
   if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
-          SpvOpCompositeExtract, instruction_to_insert_before)) {
+          spv::Op::OpCompositeExtract, instruction_to_insert_before)) {
     return false;
   }
 
@@ -93,7 +93,7 @@
       FindInstruction(message_.instruction_to_insert_before(), ir_context);
   opt::Instruction* new_instruction =
       insert_before->InsertBefore(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpCompositeExtract, extracted_type,
+          ir_context, spv::Op::OpCompositeExtract, extracted_type,
           message_.fresh_id(), extract_operands));
   ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction);
   ir_context->set_instr_block(new_instruction,
diff --git a/source/fuzz/transformation_composite_insert.cpp b/source/fuzz/transformation_composite_insert.cpp
index 60fa562..2f69c95 100644
--- a/source/fuzz/transformation_composite_insert.cpp
+++ b/source/fuzz/transformation_composite_insert.cpp
@@ -102,7 +102,7 @@
   // It must be possible to insert an OpCompositeInsert before this
   // instruction.
   return fuzzerutil::CanInsertOpcodeBeforeInstruction(
-      SpvOpCompositeInsert, instruction_to_insert_before);
+      spv::Op::OpCompositeInsert, instruction_to_insert_before);
 }
 
 void TransformationCompositeInsert::Apply(
@@ -126,8 +126,8 @@
   auto insert_before =
       FindInstruction(message_.instruction_to_insert_before(), ir_context);
   auto new_instruction = MakeUnique<opt::Instruction>(
-      ir_context, SpvOpCompositeInsert, composite_type_id, message_.fresh_id(),
-      std::move(in_operands));
+      ir_context, spv::Op::OpCompositeInsert, composite_type_id,
+      message_.fresh_id(), std::move(in_operands));
   auto new_instruction_ptr = new_instruction.get();
   insert_before->InsertBefore(std::move(new_instruction));
 
diff --git a/source/fuzz/transformation_duplicate_region_with_selection.cpp b/source/fuzz/transformation_duplicate_region_with_selection.cpp
index db88610..9176bf7 100644
--- a/source/fuzz/transformation_duplicate_region_with_selection.cpp
+++ b/source/fuzz/transformation_duplicate_region_with_selection.cpp
@@ -77,7 +77,7 @@
   // The entry and exit block ids must refer to blocks.
   for (auto block_id : {message_.entry_block_id(), message_.exit_block_id()}) {
     auto block_label = ir_context->get_def_use_mgr()->GetDef(block_id);
-    if (!block_label || block_label->opcode() != SpvOpLabel) {
+    if (!block_label || block_label->opcode() != spv::Op::OpLabel) {
       return false;
     }
   }
@@ -297,7 +297,7 @@
   // in the same function.
   std::unique_ptr<opt::BasicBlock> new_entry_block =
       MakeUnique<opt::BasicBlock>(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpLabel, 0, message_.new_entry_fresh_id(),
+          ir_context, spv::Op::OpLabel, 0, message_.new_entry_fresh_id(),
           opt::Instruction::OperandList()));
   auto entry_block = ir_context->cfg()->block(message_.entry_block_id());
   auto enclosing_function = entry_block->GetParent();
@@ -310,7 +310,7 @@
   // Construct the merge block.
   std::unique_ptr<opt::BasicBlock> merge_block =
       MakeUnique<opt::BasicBlock>(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpLabel, 0, message_.merge_label_fresh_id(),
+          ir_context, spv::Op::OpLabel, 0, message_.merge_label_fresh_id(),
           opt::Instruction::OperandList()));
 
   // Get the maps from the protobuf.
@@ -361,7 +361,7 @@
   exit_block->ForEachSuccessorLabel([this, ir_context](uint32_t label_id) {
     auto block = ir_context->cfg()->block(label_id);
     for (auto& instr : *block) {
-      if (instr.opcode() == SpvOpPhi) {
+      if (instr.opcode() == spv::Op::OpPhi) {
         instr.ForEachId([this](uint32_t* id) {
           if (*id == message_.exit_block_id()) {
             *id = message_.merge_label_fresh_id();
@@ -390,7 +390,7 @@
   // occurrence of |entry_block_pred_id| to the id of |new_entry|, because we
   // will insert |new_entry| before |entry_block|.
   for (auto& instr : *entry_block) {
-    if (instr.opcode() == SpvOpPhi) {
+    if (instr.opcode() == spv::Op::OpPhi) {
       instr.ForEachId([this, entry_block_pred_id](uint32_t* id) {
         if (*id == entry_block_pred_id) {
           *id = message_.new_entry_fresh_id();
@@ -421,7 +421,7 @@
 
     std::unique_ptr<opt::BasicBlock> duplicated_block =
         MakeUnique<opt::BasicBlock>(MakeUnique<opt::Instruction>(
-            ir_context, SpvOpLabel, 0,
+            ir_context, spv::Op::OpLabel, 0,
             original_label_to_duplicate_label.at(block->id()),
             opt::Instruction::OperandList()));
 
@@ -430,12 +430,12 @@
       // handled separately.
       if (block == exit_block && instr.IsBlockTerminator()) {
         switch (instr.opcode()) {
-          case SpvOpBranch:
-          case SpvOpBranchConditional:
-          case SpvOpReturn:
-          case SpvOpReturnValue:
-          case SpvOpUnreachable:
-          case SpvOpKill:
+          case spv::Op::OpBranch:
+          case spv::Op::OpBranchConditional:
+          case spv::Op::OpReturn:
+          case spv::Op::OpReturnValue:
+          case spv::Op::OpUnreachable:
+          case spv::Op::OpKill:
             continue;
           default:
             assert(false &&
@@ -497,7 +497,7 @@
         // the end of the region, as long as the result id is valid for use
         // with OpPhi.
         merge_block->AddInstruction(MakeUnique<opt::Instruction>(
-            ir_context, SpvOpPhi, instr.type_id(),
+            ir_context, spv::Op::OpPhi, instr.type_id(),
             original_id_to_phi_id.at(instr.result_id()),
             opt::Instruction::OperandList({
                 {SPV_OPERAND_TYPE_ID, {instr.result_id()}},
@@ -537,14 +537,14 @@
   // false, the execution proceeds in the first block of the
   // duplicated region.
   new_entry_block->AddInstruction(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpSelectionMerge, 0, 0,
+      ir_context, spv::Op::OpSelectionMerge, 0, 0,
       opt::Instruction::OperandList(
           {{SPV_OPERAND_TYPE_ID, {message_.merge_label_fresh_id()}},
            {SPV_OPERAND_TYPE_SELECTION_CONTROL,
-            {SpvSelectionControlMaskNone}}})));
+            {uint32_t(spv::SelectionControlMask::MaskNone)}}})));
 
   new_entry_block->AddInstruction(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpBranchConditional, 0, 0,
+      ir_context, spv::Op::OpBranchConditional, 0, 0,
       opt::Instruction::OperandList(
           {{SPV_OPERAND_TYPE_ID, {message_.condition_id()}},
            {SPV_OPERAND_TYPE_ID, {message_.entry_block_id()}},
@@ -563,7 +563,7 @@
   // |exit_block| and at the end of |duplicated_exit_block|, so that
   // the execution proceeds in the |merge_block|.
   opt::Instruction merge_branch_instr = opt::Instruction(
-      ir_context, SpvOpBranch, 0, 0,
+      ir_context, spv::Op::OpBranch, 0, 0,
       opt::Instruction::OperandList(
           {{SPV_OPERAND_TYPE_ID, {message_.merge_label_fresh_id()}}}));
   exit_block->AddInstruction(MakeUnique<opt::Instruction>(merge_branch_instr));
@@ -584,14 +584,14 @@
           return;
         }
         switch (user->opcode()) {
-          case SpvOpSwitch:
-          case SpvOpBranch:
-          case SpvOpBranchConditional:
-          case SpvOpLoopMerge:
-          case SpvOpSelectionMerge: {
+          case spv::Op::OpSwitch:
+          case spv::Op::OpBranch:
+          case spv::Op::OpBranchConditional:
+          case spv::Op::OpLoopMerge:
+          case spv::Op::OpSelectionMerge: {
             user->SetOperand(operand_index, {message_.new_entry_fresh_id()});
           } break;
-          case SpvOpName:
+          case spv::Op::OpName:
             break;
           default:
             assert(false &&
@@ -605,8 +605,8 @@
 
   opt::Instruction* merge_block_terminator = merge_block->terminator();
   switch (merge_block_terminator->opcode()) {
-    case SpvOpReturnValue:
-    case SpvOpBranchConditional: {
+    case spv::Op::OpReturnValue:
+    case spv::Op::OpBranchConditional: {
       uint32_t operand = merge_block_terminator->GetSingleWordInOperand(0);
       if (original_id_to_phi_id.count(operand)) {
         merge_block_terminator->SetInOperand(
@@ -699,19 +699,19 @@
       ir_context->get_def_use_mgr()->GetDef(instr.type_id());
 
   // It is invalid to apply OpPhi to void-typed values.
-  if (instr_type->opcode() == SpvOpTypeVoid) {
+  if (instr_type->opcode() == spv::Op::OpTypeVoid) {
     return false;
   }
 
   // Using pointers with OpPhi requires capability VariablePointers.
-  if (instr_type->opcode() == SpvOpTypePointer &&
+  if (instr_type->opcode() == spv::Op::OpTypePointer &&
       !ir_context->get_feature_mgr()->HasCapability(
-          SpvCapabilityVariablePointers)) {
+          spv::Capability::VariablePointers)) {
     return false;
   }
 
   // OpTypeSampledImage cannot be the result type of an OpPhi instruction.
-  if (instr_type->opcode() == SpvOpTypeSampledImage) {
+  if (instr_type->opcode() == spv::Op::OpTypeSampledImage) {
     return false;
   }
   return true;
diff --git a/source/fuzz/transformation_equation_instruction.cpp b/source/fuzz/transformation_equation_instruction.cpp
index 1e5dae9..72487a8 100644
--- a/source/fuzz/transformation_equation_instruction.cpp
+++ b/source/fuzz/transformation_equation_instruction.cpp
@@ -25,10 +25,11 @@
     : message_(std::move(message)) {}
 
 TransformationEquationInstruction::TransformationEquationInstruction(
-    uint32_t fresh_id, SpvOp opcode, const std::vector<uint32_t>& in_operand_id,
+    uint32_t fresh_id, spv::Op opcode,
+    const std::vector<uint32_t>& in_operand_id,
     const protobufs::InstructionDescriptor& instruction_to_insert_before) {
   message_.set_fresh_id(fresh_id);
-  message_.set_opcode(opcode);
+  message_.set_opcode(uint32_t(opcode));
   for (auto id : in_operand_id) {
     message_.add_in_operand_id(id);
   }
@@ -57,7 +58,7 @@
     if (!inst) {
       return false;
     }
-    if (inst->opcode() == SpvOpUndef) {
+    if (inst->opcode() == spv::Op::OpUndef) {
       return false;
     }
     if (transformation_context.GetFactManager()->IdIsIrrelevant(id)) {
@@ -88,7 +89,7 @@
       FindInstruction(message_.instruction_to_insert_before(), ir_context);
   opt::Instruction* new_instruction =
       insert_before->InsertBefore(MakeUnique<opt::Instruction>(
-          ir_context, static_cast<SpvOp>(message_.opcode()),
+          ir_context, static_cast<spv::Op>(message_.opcode()),
           MaybeGetResultTypeId(ir_context), message_.fresh_id(),
           std::move(in_operands)));
 
@@ -101,7 +102,7 @@
   if (!transformation_context->GetFactManager()->IdIsIrrelevant(
           message_.fresh_id())) {
     transformation_context->GetFactManager()->AddFactIdEquation(
-        message_.fresh_id(), static_cast<SpvOp>(message_.opcode()), rhs_id);
+        message_.fresh_id(), static_cast<spv::Op>(message_.opcode()), rhs_id);
   }
 }
 
@@ -113,10 +114,10 @@
 
 uint32_t TransformationEquationInstruction::MaybeGetResultTypeId(
     opt::IRContext* ir_context) const {
-  auto opcode = static_cast<SpvOp>(message_.opcode());
+  auto opcode = static_cast<spv::Op>(message_.opcode());
   switch (opcode) {
-    case SpvOpConvertUToF:
-    case SpvOpConvertSToF: {
+    case spv::Op::OpConvertUToF:
+    case spv::Op::OpConvertSToF: {
       if (message_.in_operand_id_size() != 1) {
         return 0;
       }
@@ -148,7 +149,7 @@
                                              type->AsInteger()->width());
       }
     }
-    case SpvOpBitcast: {
+    case spv::Op::OpBitcast: {
       if (message_.in_operand_id_size() != 1) {
         return 0;
       }
@@ -210,8 +211,8 @@
         return 0;
       }
     }
-    case SpvOpIAdd:
-    case SpvOpISub: {
+    case spv::Op::OpIAdd:
+    case spv::Op::OpISub: {
       if (message_.in_operand_id_size() != 2) {
         return 0;
       }
@@ -249,7 +250,7 @@
              "A type must have been found for the first operand.");
       return first_operand_type_id;
     }
-    case SpvOpLogicalNot: {
+    case spv::Op::OpLogicalNot: {
       if (message_.in_operand_id().size() != 1) {
         return 0;
       }
@@ -267,7 +268,7 @@
       }
       return operand_inst->type_id();
     }
-    case SpvOpSNegate: {
+    case spv::Op::OpSNegate: {
       if (message_.in_operand_id().size() != 1) {
         return 0;
       }
diff --git a/source/fuzz/transformation_equation_instruction.h b/source/fuzz/transformation_equation_instruction.h
index ae32a1a..40118d9 100644
--- a/source/fuzz/transformation_equation_instruction.h
+++ b/source/fuzz/transformation_equation_instruction.h
@@ -31,7 +31,7 @@
       protobufs::TransformationEquationInstruction message);
 
   TransformationEquationInstruction(
-      uint32_t fresh_id, SpvOp opcode,
+      uint32_t fresh_id, spv::Op opcode,
       const std::vector<uint32_t>& in_operand_id,
       const protobufs::InstructionDescriptor& instruction_to_insert_before);
 
diff --git a/source/fuzz/transformation_expand_vector_reduction.cpp b/source/fuzz/transformation_expand_vector_reduction.cpp
index bafcf92..4c13ec1 100644
--- a/source/fuzz/transformation_expand_vector_reduction.cpp
+++ b/source/fuzz/transformation_expand_vector_reduction.cpp
@@ -44,7 +44,8 @@
   }
 
   // |instruction| must be OpAny or OpAll.
-  if (instruction->opcode() != SpvOpAny && instruction->opcode() != SpvOpAll) {
+  if (instruction->opcode() != spv::Op::OpAny &&
+      instruction->opcode() != spv::Op::OpAll) {
     return false;
   }
 
@@ -92,10 +93,11 @@
 
   for (uint32_t i = 0; i < vector_component_count; i++) {
     // Extracts the i-th |vector| component.
-    auto vector_component = opt::Instruction(
-        ir_context, SpvOpCompositeExtract, instruction->type_id(), *fresh_id++,
-        {{SPV_OPERAND_TYPE_ID, {vector->result_id()}},
-         {SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}});
+    auto vector_component =
+        opt::Instruction(ir_context, spv::Op::OpCompositeExtract,
+                         instruction->type_id(), *fresh_id++,
+                         {{SPV_OPERAND_TYPE_ID, {vector->result_id()}},
+                          {SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}});
     instruction->InsertBefore(MakeUnique<opt::Instruction>(vector_component));
     fuzzerutil::UpdateModuleIdBound(ir_context, vector_component.result_id());
     vector_components.push_back(vector_component.result_id());
@@ -104,7 +106,8 @@
   // The first two |vector| components are used in the first logical operation.
   auto logical_instruction = opt::Instruction(
       ir_context,
-      instruction->opcode() == SpvOpAny ? SpvOpLogicalOr : SpvOpLogicalAnd,
+      instruction->opcode() == spv::Op::OpAny ? spv::Op::OpLogicalOr
+                                              : spv::Op::OpLogicalAnd,
       instruction->type_id(), *fresh_id++,
       {{SPV_OPERAND_TYPE_ID, {vector_components[0]}},
        {SPV_OPERAND_TYPE_ID, {vector_components[1]}}});
diff --git a/source/fuzz/transformation_flatten_conditional_branch.cpp b/source/fuzz/transformation_flatten_conditional_branch.cpp
index 127e762..f8d1c33 100644
--- a/source/fuzz/transformation_flatten_conditional_branch.cpp
+++ b/source/fuzz/transformation_flatten_conditional_branch.cpp
@@ -48,12 +48,12 @@
 
   // The block must have been found and it must be a selection header.
   if (!header_block || !header_block->GetMergeInst() ||
-      header_block->GetMergeInst()->opcode() != SpvOpSelectionMerge) {
+      header_block->GetMergeInst()->opcode() != spv::Op::OpSelectionMerge) {
     return false;
   }
 
   // The header block must end with an OpBranchConditional instruction.
-  if (header_block->terminator()->opcode() != SpvOpBranchConditional) {
+  if (header_block->terminator()->opcode() != spv::Op::OpBranchConditional) {
     return false;
   }
 
@@ -164,14 +164,14 @@
                opt::Instruction* phi_result_type =
                    ir_context->get_def_use_mgr()->GetDef(inst->type_id());
                switch (phi_result_type->opcode()) {
-                 case SpvOpTypeBool:
-                 case SpvOpTypeInt:
-                 case SpvOpTypeFloat:
-                 case SpvOpTypePointer:
+                 case spv::Op::OpTypeBool:
+                 case spv::Op::OpTypeInt:
+                 case spv::Op::OpTypeFloat:
+                 case spv::Op::OpTypePointer:
                    // Fine: OpSelect can work directly on scalar and pointer
                    // types.
                    return true;
-                 case SpvOpTypeVector: {
+                 case spv::Op::OpTypeVector: {
                    // In its restricted form, OpSelect can only select between
                    // vectors if the condition of the select is a boolean
                    // boolean vector.  We thus require the appropriate boolean
@@ -288,8 +288,8 @@
 
       current_block->ForEachInst(
           [&problematic_instructions](opt::Instruction* instruction) {
-            if (instruction->opcode() != SpvOpLabel &&
-                instruction->opcode() != SpvOpBranch &&
+            if (instruction->opcode() != spv::Op::OpLabel &&
+                instruction->opcode() != spv::Op::OpBranch &&
                 !fuzzerutil::InstructionHasNoSideEffects(*instruction)) {
               problematic_instructions.push_back(instruction);
             }
@@ -381,7 +381,7 @@
   // Add a new, unconditional, branch instruction from the current header to
   // |after_header|.
   header_block->AddInstruction(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpBranch, 0, 0,
+      ir_context, spv::Op::OpBranch, 0, 0,
       opt::Instruction::OperandList{{SPV_OPERAND_TYPE_ID, {after_header}}}));
 
   // If the first branch to be laid out exists, change the branch instruction so
@@ -437,8 +437,8 @@
         std::set<opt::Instruction*>* instructions_that_need_ids) {
   uint32_t merge_block_id = header->MergeBlockIdIfAny();
   assert(merge_block_id &&
-         header->GetMergeInst()->opcode() == SpvOpSelectionMerge &&
-         header->terminator()->opcode() == SpvOpBranchConditional &&
+         header->GetMergeInst()->opcode() == spv::Op::OpSelectionMerge &&
+         header->terminator()->opcode() == spv::Op::OpBranchConditional &&
          "|header| must be the header of a conditional.");
 
   // |header| must be reachable.
@@ -508,7 +508,7 @@
     }
 
     // The terminator instruction for the block must be OpBranch.
-    if (block->terminator()->opcode() != SpvOpBranch) {
+    if (block->terminator()->opcode() != spv::Op::OpBranch) {
       return false;
     }
 
@@ -524,7 +524,7 @@
         [ir_context, instructions_that_need_ids,
          &synonym_base_objects](opt::Instruction* instruction) {
           // We can ignore OpLabel instructions.
-          if (instruction->opcode() == SpvOpLabel) {
+          if (instruction->opcode() == spv::Op::OpLabel) {
             return true;
           }
 
@@ -539,7 +539,7 @@
 
           // If the instruction is a branch, it must be an unconditional branch.
           if (instruction->IsBranch()) {
-            return instruction->opcode() == SpvOpBranch;
+            return instruction->opcode() == spv::Op::OpBranch;
           }
 
           // We cannot go ahead if we encounter an instruction that cannot be
@@ -644,7 +644,7 @@
 
   // Add an unconditional branch from |execute_block| to |merge_block|.
   execute_block->AddInstruction(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpBranch, 0, 0,
+      ir_context, spv::Op::OpBranch, 0, 0,
       opt::Instruction::OperandList{
           {SPV_OPERAND_TYPE_ID, {merge_block->id()}}}));
 
@@ -668,10 +668,10 @@
     }
 
     // Create a new block using |fresh_ids.alternative_block_id| for its label.
-    auto alternative_block_temp =
-        MakeUnique<opt::BasicBlock>(MakeUnique<opt::Instruction>(
-            ir_context, SpvOpLabel, 0, wrapper_info.alternative_block_id(),
-            opt::Instruction::OperandList{}));
+    auto alternative_block_temp = MakeUnique<opt::BasicBlock>(
+        MakeUnique<opt::Instruction>(ir_context, spv::Op::OpLabel, 0,
+                                     wrapper_info.alternative_block_id(),
+                                     opt::Instruction::OperandList{}));
 
     // Keep the original result id of the instruction in a variable.
     uint32_t original_result_id = instruction->result_id();
@@ -685,14 +685,14 @@
       // If there is an available id to copy from, the placeholder instruction
       // will be %placeholder_result_id = OpCopyObject %type %value_to_copy_id
       alternative_block_temp->AddInstruction(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpCopyObject, instruction->type_id(),
+          ir_context, spv::Op::OpCopyObject, instruction->type_id(),
           wrapper_info.placeholder_result_id(),
           opt::Instruction::OperandList{
               {SPV_OPERAND_TYPE_ID, {wrapper_info.value_to_copy_id()}}}));
     } else {
       // If there is no such id, use an OpUndef instruction.
       alternative_block_temp->AddInstruction(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpUndef, instruction->type_id(),
+          ir_context, spv::Op::OpUndef, instruction->type_id(),
           wrapper_info.placeholder_result_id(),
           opt::Instruction::OperandList{}));
     }
@@ -702,7 +702,7 @@
 
     // Add an unconditional branch from the new block to the merge block.
     alternative_block_temp->AddInstruction(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpBranch, 0, 0,
+        ir_context, spv::Op::OpBranch, 0, 0,
         opt::Instruction::OperandList{
             {SPV_OPERAND_TYPE_ID, {merge_block->id()}}}));
 
@@ -714,7 +714,7 @@
     // merge block, which will either take the value of the result of the
     // instruction or the placeholder value defined in the alternative block.
     merge_block->begin().InsertBefore(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpPhi, instruction->type_id(), original_result_id,
+        ir_context, spv::Op::OpPhi, instruction->type_id(), original_result_id,
         opt::Instruction::OperandList{
             {SPV_OPERAND_TYPE_ID, {instruction->result_id()}},
             {SPV_OPERAND_TYPE_ID, {execute_block->id()}},
@@ -738,16 +738,17 @@
 
   // Add an OpSelectionMerge instruction to the block.
   block->AddInstruction(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpSelectionMerge, 0, 0,
-      opt::Instruction::OperandList{{SPV_OPERAND_TYPE_ID, {merge_block->id()}},
-                                    {SPV_OPERAND_TYPE_SELECTION_CONTROL,
-                                     {SpvSelectionControlMaskNone}}}));
+      ir_context, spv::Op::OpSelectionMerge, 0, 0,
+      opt::Instruction::OperandList{
+          {SPV_OPERAND_TYPE_ID, {merge_block->id()}},
+          {SPV_OPERAND_TYPE_SELECTION_CONTROL,
+           {uint32_t(spv::SelectionControlMask::MaskNone)}}}));
 
   // Add an OpBranchConditional, to the block, using |condition_id| as the
   // condition and branching to |if_block_id| if the condition is true and to
   // |else_block_id| if the condition is false.
   block->AddInstruction(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpBranchConditional, 0, 0,
+      ir_context, spv::Op::OpBranchConditional, 0, 0,
       opt::Instruction::OperandList{{SPV_OPERAND_TYPE_ID, {condition_id}},
                                     {SPV_OPERAND_TYPE_ID, {if_block_id}},
                                     {SPV_OPERAND_TYPE_ID, {else_block_id}}}));
@@ -764,26 +765,26 @@
 
   // We cannot handle barrier instructions, while we should be able to handle
   // all other instructions by enclosing them inside a conditional.
-  if (instruction.opcode() == SpvOpControlBarrier ||
-      instruction.opcode() == SpvOpMemoryBarrier ||
-      instruction.opcode() == SpvOpNamedBarrierInitialize ||
-      instruction.opcode() == SpvOpMemoryNamedBarrier ||
-      instruction.opcode() == SpvOpTypeNamedBarrier) {
+  if (instruction.opcode() == spv::Op::OpControlBarrier ||
+      instruction.opcode() == spv::Op::OpMemoryBarrier ||
+      instruction.opcode() == spv::Op::OpNamedBarrierInitialize ||
+      instruction.opcode() == spv::Op::OpMemoryNamedBarrier ||
+      instruction.opcode() == spv::Op::OpTypeNamedBarrier) {
     return false;
   }
 
   // We cannot handle OpSampledImage instructions, as they need to be in the
   // same block as their use.
-  if (instruction.opcode() == SpvOpSampledImage) {
+  if (instruction.opcode() == spv::Op::OpSampledImage) {
     return false;
   }
 
   // We cannot handle a sampled image load, because we re-work loads using
   // conditional branches and OpPhi instructions, and the result type of OpPhi
   // cannot be OpTypeSampledImage.
-  if (instruction.opcode() == SpvOpLoad &&
+  if (instruction.opcode() == spv::Op::OpLoad &&
       ir_context->get_def_use_mgr()->GetDef(instruction.type_id())->opcode() ==
-          SpvOpTypeSampledImage) {
+          spv::Op::OpTypeSampledImage) {
     return false;
   }
 
@@ -863,7 +864,7 @@
     in_operands.emplace_back(branch_condition_operand);
   }
   block->begin()->InsertBefore(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpCompositeConstruct,
+      ir_context, spv::Op::OpCompositeConstruct,
       fuzzerutil::MaybeGetVectorType(
           ir_context, fuzzerutil::MaybeGetBoolType(ir_context), dimension),
       fresh_id, in_operands));
@@ -906,7 +907,7 @@
         opt::Operand selector_operand = branch_condition_operand;
         opt::Instruction* type_inst =
             ir_context->get_def_use_mgr()->GetDef(phi_inst->type_id());
-        if (type_inst->opcode() == SpvOpTypeVector) {
+        if (type_inst->opcode() == spv::Op::OpTypeVector) {
           uint32_t dimension = type_inst->GetSingleWordInOperand(1);
           switch (dimension) {
             case 2:
@@ -1012,7 +1013,7 @@
           operands.emplace_back(phi_inst->GetInOperand(2));
           operands.emplace_back(phi_inst->GetInOperand(0));
         }
-        phi_inst->SetOpcode(SpvOpSelect);
+        phi_inst->SetOpcode(spv::Op::OpSelect);
         phi_inst->SetInOperands(std::move(operands));
       });
 
diff --git a/source/fuzz/transformation_function_call.cpp b/source/fuzz/transformation_function_call.cpp
index 0f88ce5..e96a230 100644
--- a/source/fuzz/transformation_function_call.cpp
+++ b/source/fuzz/transformation_function_call.cpp
@@ -49,7 +49,7 @@
   // The function must exist
   auto callee_inst =
       ir_context->get_def_use_mgr()->GetDef(message_.callee_id());
-  if (!callee_inst || callee_inst->opcode() != SpvOpFunction) {
+  if (!callee_inst || callee_inst->opcode() != spv::Op::OpFunction) {
     return false;
   }
 
@@ -60,7 +60,7 @@
 
   auto callee_type_inst = ir_context->get_def_use_mgr()->GetDef(
       callee_inst->GetSingleWordInOperand(1));
-  assert(callee_type_inst->opcode() == SpvOpTypeFunction &&
+  assert(callee_type_inst->opcode() == spv::Op::OpTypeFunction &&
          "Bad function type.");
 
   // The number of expected function arguments must match the number of given
@@ -78,7 +78,7 @@
   if (!insert_before) {
     return false;
   }
-  if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpFunctionCall,
+  if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpFunctionCall,
                                                     insert_before)) {
     return false;
   }
@@ -116,10 +116,10 @@
     }
     opt::Instruction* arg_type_inst =
         ir_context->get_def_use_mgr()->GetDef(arg_inst->type_id());
-    if (arg_type_inst->opcode() == SpvOpTypePointer) {
+    if (arg_type_inst->opcode() == spv::Op::OpTypePointer) {
       switch (arg_inst->opcode()) {
-        case SpvOpFunctionParameter:
-        case SpvOpVariable:
+        case spv::Op::OpFunctionParameter:
+        case spv::Op::OpVariable:
           // These are OK
           break;
         default:
@@ -173,7 +173,7 @@
   // Insert the function call before the instruction specified in the message.
   FindInstruction(message_.instruction_to_insert_before(), ir_context)
       ->InsertBefore(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpFunctionCall, return_type, message_.fresh_id(),
+          ir_context, spv::Op::OpFunctionCall, return_type, message_.fresh_id(),
           operands));
   // Invalidate all analyses since we have changed the module.
   ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
diff --git a/source/fuzz/transformation_inline_function.cpp b/source/fuzz/transformation_inline_function.cpp
index a48b817..69e88fd 100644
--- a/source/fuzz/transformation_inline_function.cpp
+++ b/source/fuzz/transformation_inline_function.cpp
@@ -62,7 +62,8 @@
       ir_context->get_instr_block(function_call_instruction);
   if (function_call_instruction !=
           &*--function_call_instruction_block->tail() ||
-      function_call_instruction_block->terminator()->opcode() != SpvOpBranch) {
+      function_call_instruction_block->terminator()->opcode() !=
+          spv::Op::OpBranch) {
     return false;
   }
 
@@ -143,7 +144,7 @@
   for (auto& entry_block_instruction : *called_function->entry()) {
     opt::Instruction* inlined_instruction;
 
-    if (entry_block_instruction.opcode() == SpvOpVariable) {
+    if (entry_block_instruction.opcode() == spv::Op::OpVariable) {
       // All OpVariable instructions in a function must be in the first block
       // in the function.
       inlined_instruction = caller_function->begin()->begin()->InsertBefore(
@@ -206,7 +207,7 @@
         block_containing_function_call->id(),
         [ir_context, new_return_block_id, successor_block](
             opt::Instruction* use_instruction, uint32_t operand_index) {
-          if (use_instruction->opcode() == SpvOpPhi &&
+          if (use_instruction->opcode() == spv::Op::OpPhi &&
               ir_context->get_instr_block(use_instruction) == successor_block) {
             use_instruction->SetOperand(operand_index, {new_return_block_id});
           }
@@ -234,7 +235,7 @@
   // |function_call_instruction| must be defined and must be an OpFunctionCall
   // instruction.
   if (!function_call_instruction ||
-      function_call_instruction->opcode() != SpvOpFunctionCall) {
+      function_call_instruction->opcode() != spv::Op::OpFunctionCall) {
     return false;
   }
 
@@ -331,13 +332,14 @@
             ->terminator()
             ->GetSingleWordInOperand(0);
     switch (instruction_to_be_inlined->opcode()) {
-      case SpvOpReturn:
+      case spv::Op::OpReturn:
         instruction_to_be_inlined->AddOperand(
             {SPV_OPERAND_TYPE_ID, {successor_block_id}});
         break;
-      case SpvOpReturnValue: {
+      case spv::Op::OpReturnValue: {
         instruction_to_be_inlined->InsertBefore(MakeUnique<opt::Instruction>(
-            ir_context, SpvOpCopyObject, function_call_instruction->type_id(),
+            ir_context, spv::Op::OpCopyObject,
+            function_call_instruction->type_id(),
             function_call_instruction->result_id(),
             opt::Instruction::OperandList(
                 {{SPV_OPERAND_TYPE_ID,
@@ -348,7 +350,7 @@
       default:
         break;
     }
-    instruction_to_be_inlined->SetOpcode(SpvOpBranch);
+    instruction_to_be_inlined->SetOpcode(spv::Op::OpBranch);
   }
 }
 
diff --git a/source/fuzz/transformation_invert_comparison_operator.cpp b/source/fuzz/transformation_invert_comparison_operator.cpp
index ed7358f..49801e3 100644
--- a/source/fuzz/transformation_invert_comparison_operator.cpp
+++ b/source/fuzz/transformation_invert_comparison_operator.cpp
@@ -47,7 +47,8 @@
   auto iter = fuzzerutil::GetIteratorForInstruction(block, inst);
   ++iter;
   assert(iter != block->end() && "Instruction can't be the last in the block");
-  assert(fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLogicalNot, iter) &&
+  assert(fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpLogicalNot,
+                                                      iter) &&
          "Can't insert negation after comparison operator");
 
   // |message_.fresh_id| must be fresh.
@@ -65,7 +66,7 @@
   ++iter;
 
   iter.InsertBefore(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpLogicalNot, inst->type_id(), inst->result_id(),
+      ir_context, spv::Op::OpLogicalNot, inst->type_id(), inst->result_id(),
       opt::Instruction::OperandList{
           {SPV_OPERAND_TYPE_ID, {message_.fresh_id()}}}));
 
@@ -82,88 +83,88 @@
 }
 
 bool TransformationInvertComparisonOperator::IsInversionSupported(
-    SpvOp opcode) {
+    spv::Op opcode) {
   switch (opcode) {
-    case SpvOpSGreaterThan:
-    case SpvOpSGreaterThanEqual:
-    case SpvOpSLessThan:
-    case SpvOpSLessThanEqual:
-    case SpvOpUGreaterThan:
-    case SpvOpUGreaterThanEqual:
-    case SpvOpULessThan:
-    case SpvOpULessThanEqual:
-    case SpvOpIEqual:
-    case SpvOpINotEqual:
-    case SpvOpFOrdEqual:
-    case SpvOpFUnordEqual:
-    case SpvOpFOrdNotEqual:
-    case SpvOpFUnordNotEqual:
-    case SpvOpFOrdLessThan:
-    case SpvOpFUnordLessThan:
-    case SpvOpFOrdLessThanEqual:
-    case SpvOpFUnordLessThanEqual:
-    case SpvOpFOrdGreaterThan:
-    case SpvOpFUnordGreaterThan:
-    case SpvOpFOrdGreaterThanEqual:
-    case SpvOpFUnordGreaterThanEqual:
+    case spv::Op::OpSGreaterThan:
+    case spv::Op::OpSGreaterThanEqual:
+    case spv::Op::OpSLessThan:
+    case spv::Op::OpSLessThanEqual:
+    case spv::Op::OpUGreaterThan:
+    case spv::Op::OpUGreaterThanEqual:
+    case spv::Op::OpULessThan:
+    case spv::Op::OpULessThanEqual:
+    case spv::Op::OpIEqual:
+    case spv::Op::OpINotEqual:
+    case spv::Op::OpFOrdEqual:
+    case spv::Op::OpFUnordEqual:
+    case spv::Op::OpFOrdNotEqual:
+    case spv::Op::OpFUnordNotEqual:
+    case spv::Op::OpFOrdLessThan:
+    case spv::Op::OpFUnordLessThan:
+    case spv::Op::OpFOrdLessThanEqual:
+    case spv::Op::OpFUnordLessThanEqual:
+    case spv::Op::OpFOrdGreaterThan:
+    case spv::Op::OpFUnordGreaterThan:
+    case spv::Op::OpFOrdGreaterThanEqual:
+    case spv::Op::OpFUnordGreaterThanEqual:
       return true;
     default:
       return false;
   }
 }
 
-SpvOp TransformationInvertComparisonOperator::InvertOpcode(SpvOp opcode) {
+spv::Op TransformationInvertComparisonOperator::InvertOpcode(spv::Op opcode) {
   assert(IsInversionSupported(opcode) && "Inversion must be supported");
 
   switch (opcode) {
-    case SpvOpSGreaterThan:
-      return SpvOpSLessThanEqual;
-    case SpvOpSGreaterThanEqual:
-      return SpvOpSLessThan;
-    case SpvOpSLessThan:
-      return SpvOpSGreaterThanEqual;
-    case SpvOpSLessThanEqual:
-      return SpvOpSGreaterThan;
-    case SpvOpUGreaterThan:
-      return SpvOpULessThanEqual;
-    case SpvOpUGreaterThanEqual:
-      return SpvOpULessThan;
-    case SpvOpULessThan:
-      return SpvOpUGreaterThanEqual;
-    case SpvOpULessThanEqual:
-      return SpvOpUGreaterThan;
-    case SpvOpIEqual:
-      return SpvOpINotEqual;
-    case SpvOpINotEqual:
-      return SpvOpIEqual;
-    case SpvOpFOrdEqual:
-      return SpvOpFUnordNotEqual;
-    case SpvOpFUnordEqual:
-      return SpvOpFOrdNotEqual;
-    case SpvOpFOrdNotEqual:
-      return SpvOpFUnordEqual;
-    case SpvOpFUnordNotEqual:
-      return SpvOpFOrdEqual;
-    case SpvOpFOrdLessThan:
-      return SpvOpFUnordGreaterThanEqual;
-    case SpvOpFUnordLessThan:
-      return SpvOpFOrdGreaterThanEqual;
-    case SpvOpFOrdLessThanEqual:
-      return SpvOpFUnordGreaterThan;
-    case SpvOpFUnordLessThanEqual:
-      return SpvOpFOrdGreaterThan;
-    case SpvOpFOrdGreaterThan:
-      return SpvOpFUnordLessThanEqual;
-    case SpvOpFUnordGreaterThan:
-      return SpvOpFOrdLessThanEqual;
-    case SpvOpFOrdGreaterThanEqual:
-      return SpvOpFUnordLessThan;
-    case SpvOpFUnordGreaterThanEqual:
-      return SpvOpFOrdLessThan;
+    case spv::Op::OpSGreaterThan:
+      return spv::Op::OpSLessThanEqual;
+    case spv::Op::OpSGreaterThanEqual:
+      return spv::Op::OpSLessThan;
+    case spv::Op::OpSLessThan:
+      return spv::Op::OpSGreaterThanEqual;
+    case spv::Op::OpSLessThanEqual:
+      return spv::Op::OpSGreaterThan;
+    case spv::Op::OpUGreaterThan:
+      return spv::Op::OpULessThanEqual;
+    case spv::Op::OpUGreaterThanEqual:
+      return spv::Op::OpULessThan;
+    case spv::Op::OpULessThan:
+      return spv::Op::OpUGreaterThanEqual;
+    case spv::Op::OpULessThanEqual:
+      return spv::Op::OpUGreaterThan;
+    case spv::Op::OpIEqual:
+      return spv::Op::OpINotEqual;
+    case spv::Op::OpINotEqual:
+      return spv::Op::OpIEqual;
+    case spv::Op::OpFOrdEqual:
+      return spv::Op::OpFUnordNotEqual;
+    case spv::Op::OpFUnordEqual:
+      return spv::Op::OpFOrdNotEqual;
+    case spv::Op::OpFOrdNotEqual:
+      return spv::Op::OpFUnordEqual;
+    case spv::Op::OpFUnordNotEqual:
+      return spv::Op::OpFOrdEqual;
+    case spv::Op::OpFOrdLessThan:
+      return spv::Op::OpFUnordGreaterThanEqual;
+    case spv::Op::OpFUnordLessThan:
+      return spv::Op::OpFOrdGreaterThanEqual;
+    case spv::Op::OpFOrdLessThanEqual:
+      return spv::Op::OpFUnordGreaterThan;
+    case spv::Op::OpFUnordLessThanEqual:
+      return spv::Op::OpFOrdGreaterThan;
+    case spv::Op::OpFOrdGreaterThan:
+      return spv::Op::OpFUnordLessThanEqual;
+    case spv::Op::OpFUnordGreaterThan:
+      return spv::Op::OpFOrdLessThanEqual;
+    case spv::Op::OpFOrdGreaterThanEqual:
+      return spv::Op::OpFUnordLessThan;
+    case spv::Op::OpFUnordGreaterThanEqual:
+      return spv::Op::OpFOrdLessThan;
     default:
       // The program will fail in the debug mode because of the assertion
       // at the beginning of the function.
-      return SpvOpNop;
+      return spv::Op::OpNop;
   }
 }
 
diff --git a/source/fuzz/transformation_invert_comparison_operator.h b/source/fuzz/transformation_invert_comparison_operator.h
index f00f62b..39c2fe0 100644
--- a/source/fuzz/transformation_invert_comparison_operator.h
+++ b/source/fuzz/transformation_invert_comparison_operator.h
@@ -50,11 +50,11 @@
   protobufs::Transformation ToMessage() const override;
 
   // Returns true if |opcode| is supported by this transformation.
-  static bool IsInversionSupported(SpvOp opcode);
+  static bool IsInversionSupported(spv::Op opcode);
 
  private:
   // Returns an inverted |opcode| (e.g. < becomes >=, == becomes != etc.)
-  static SpvOp InvertOpcode(SpvOp opcode);
+  static spv::Op InvertOpcode(spv::Op opcode);
 
   protobufs::TransformationInvertComparisonOperator message_;
 };
diff --git a/source/fuzz/transformation_load.cpp b/source/fuzz/transformation_load.cpp
index bf48d99..1cfde77 100644
--- a/source/fuzz/transformation_load.cpp
+++ b/source/fuzz/transformation_load.cpp
@@ -52,15 +52,15 @@
   // The type must indeed be a pointer type.
   auto pointer_type = ir_context->get_def_use_mgr()->GetDef(pointer->type_id());
   assert(pointer_type && "Type id must be defined.");
-  if (pointer_type->opcode() != SpvOpTypePointer) {
+  if (pointer_type->opcode() != spv::Op::OpTypePointer) {
     return false;
   }
   // We do not want to allow loading from null or undefined pointers, as it is
   // not clear how punishing the consequences of doing so are from a semantics
   // point of view.
   switch (pointer->opcode()) {
-    case SpvOpConstantNull:
-    case SpvOpUndef:
+    case spv::Op::OpConstantNull:
+    case spv::Op::OpUndef:
       return false;
     default:
       break;
@@ -74,13 +74,13 @@
     return false;
   }
   // ... and it must be legitimate to insert a load before it.
-  if (!message_.is_atomic() &&
-      !fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLoad, insert_before)) {
+  if (!message_.is_atomic() && !fuzzerutil::CanInsertOpcodeBeforeInstruction(
+                                   spv::Op::OpLoad, insert_before)) {
     return false;
   }
 
   if (message_.is_atomic() && !fuzzerutil::CanInsertOpcodeBeforeInstruction(
-                                  SpvOpAtomicLoad, insert_before)) {
+                                  spv::Op::OpAtomicLoad, insert_before)) {
     return false;
   }
 
@@ -99,10 +99,10 @@
     }
     // The memory scope and memory semantics instructions must have the
     // 'OpConstant' opcode.
-    if (memory_scope_instruction->opcode() != SpvOpConstant) {
+    if (memory_scope_instruction->opcode() != spv::Op::OpConstant) {
       return false;
     }
-    if (memory_semantics_instruction->opcode() != SpvOpConstant) {
+    if (memory_semantics_instruction->opcode() != spv::Op::OpConstant) {
       return false;
     }
     // The memory scope and memory semantics need to be available before
@@ -119,12 +119,12 @@
     // operand type with signedness does not matters.
     if (ir_context->get_def_use_mgr()
             ->GetDef(memory_scope_instruction->type_id())
-            ->opcode() != SpvOpTypeInt) {
+            ->opcode() != spv::Op::OpTypeInt) {
       return false;
     }
     if (ir_context->get_def_use_mgr()
             ->GetDef(memory_semantics_instruction->type_id())
-            ->opcode() != SpvOpTypeInt) {
+            ->opcode() != spv::Op::OpTypeInt) {
       return false;
     }
 
@@ -146,20 +146,20 @@
       return false;
     }
 
-    // The memory scope constant value must be that of SpvScopeInvocation.
+    // The memory scope constant value must be that of spv::Scope::Invocation.
     auto memory_scope_const_value =
-        memory_scope_instruction->GetSingleWordInOperand(0);
-    if (memory_scope_const_value != SpvScopeInvocation) {
+        spv::Scope(memory_scope_instruction->GetSingleWordInOperand(0));
+    if (memory_scope_const_value != spv::Scope::Invocation) {
       return false;
     }
 
     // The memory semantics constant value must match the storage class of the
     // pointer being loaded from.
-    auto memory_semantics_const_value = static_cast<SpvMemorySemanticsMask>(
+    auto memory_semantics_const_value = static_cast<spv::MemorySemanticsMask>(
         memory_semantics_instruction->GetSingleWordInOperand(0));
     if (memory_semantics_const_value !=
         fuzzerutil::GetMemorySemanticsForStorageClass(
-            static_cast<SpvStorageClass>(
+            static_cast<spv::StorageClass>(
                 pointer_type->GetSingleWordInOperand(0)))) {
       return false;
     }
@@ -180,7 +180,7 @@
     auto insert_before =
         FindInstruction(message_.instruction_to_insert_before(), ir_context);
     auto new_instruction = MakeUnique<opt::Instruction>(
-        ir_context, SpvOpAtomicLoad, result_type, message_.fresh_id(),
+        ir_context, spv::Op::OpAtomicLoad, result_type, message_.fresh_id(),
         opt::Instruction::OperandList(
             {{SPV_OPERAND_TYPE_ID, {message_.pointer_id()}},
              {SPV_OPERAND_TYPE_SCOPE_ID, {message_.memory_scope_id()}},
@@ -201,7 +201,7 @@
     auto insert_before =
         FindInstruction(message_.instruction_to_insert_before(), ir_context);
     auto new_instruction = MakeUnique<opt::Instruction>(
-        ir_context, SpvOpLoad, result_type, message_.fresh_id(),
+        ir_context, spv::Op::OpLoad, result_type, message_.fresh_id(),
         opt::Instruction::OperandList(
             {{SPV_OPERAND_TYPE_ID, {message_.pointer_id()}}}));
     auto new_instruction_ptr = new_instruction.get();
diff --git a/source/fuzz/transformation_load.h b/source/fuzz/transformation_load.h
index 57b4a53..6622918 100644
--- a/source/fuzz/transformation_load.h
+++ b/source/fuzz/transformation_load.h
@@ -37,7 +37,7 @@
   // - |message_.is_atomic| must be true if want to work with OpAtomicLoad
   // - If |is_atomic| is true then |message_memory_scope_id| must be the id of
   //   an OpConstant 32 bit integer instruction with the value
-  //   SpvScopeInvocation.
+  //   spv::Scope::Invocation.
   // - If |is_atomic| is true then |message_.memory_semantics_id| must be the id
   //   of an OpConstant 32 bit integer instruction with the values
   //   SpvMemorySemanticsWorkgroupMemoryMask or
diff --git a/source/fuzz/transformation_make_vector_operation_dynamic.cpp b/source/fuzz/transformation_make_vector_operation_dynamic.cpp
index bd0664c..ecc8dca 100644
--- a/source/fuzz/transformation_make_vector_operation_dynamic.cpp
+++ b/source/fuzz/transformation_make_vector_operation_dynamic.cpp
@@ -62,19 +62,19 @@
   // The OpVectorInsertDynamic instruction has the vector and component operands
   // in reverse order in relation to the OpCompositeInsert corresponding
   // operands.
-  if (instruction->opcode() == SpvOpCompositeInsert) {
+  if (instruction->opcode() == spv::Op::OpCompositeInsert) {
     std::swap(instruction->GetInOperand(0), instruction->GetInOperand(1));
   }
 
   // Sets the literal operand to the equivalent constant.
   instruction->SetInOperand(
-      instruction->opcode() == SpvOpCompositeExtract ? 1 : 2,
+      instruction->opcode() == spv::Op::OpCompositeExtract ? 1 : 2,
       {message_.constant_index_id()});
 
   // Sets the |instruction| opcode to the corresponding vector dynamic opcode.
-  instruction->SetOpcode(instruction->opcode() == SpvOpCompositeExtract
-                             ? SpvOpVectorExtractDynamic
-                             : SpvOpVectorInsertDynamic);
+  instruction->SetOpcode(instruction->opcode() == spv::Op::OpCompositeExtract
+                             ? spv::Op::OpVectorExtractDynamic
+                             : spv::Op::OpVectorInsertDynamic);
 }
 
 protobufs::Transformation TransformationMakeVectorOperationDynamic::ToMessage()
@@ -88,15 +88,15 @@
     opt::IRContext* ir_context, opt::Instruction* instruction) {
   // |instruction| must be defined and must be an OpCompositeExtract/Insert
   // instruction.
-  if (!instruction || (instruction->opcode() != SpvOpCompositeExtract &&
-                       instruction->opcode() != SpvOpCompositeInsert)) {
+  if (!instruction || (instruction->opcode() != spv::Op::OpCompositeExtract &&
+                       instruction->opcode() != spv::Op::OpCompositeInsert)) {
     return false;
   }
 
   // The composite must be a vector.
   auto composite_instruction =
       ir_context->get_def_use_mgr()->GetDef(instruction->GetSingleWordInOperand(
-          instruction->opcode() == SpvOpCompositeExtract ? 0 : 1));
+          instruction->opcode() == spv::Op::OpCompositeExtract ? 0 : 1));
   if (!ir_context->get_type_mgr()
            ->GetType(composite_instruction->type_id())
            ->AsVector()) {
diff --git a/source/fuzz/transformation_merge_function_returns.cpp b/source/fuzz/transformation_merge_function_returns.cpp
index 022e1b6..b35e358 100644
--- a/source/fuzz/transformation_merge_function_returns.cpp
+++ b/source/fuzz/transformation_merge_function_returns.cpp
@@ -50,7 +50,7 @@
   }
 
   // The entry block must end in an unconditional branch.
-  if (function->entry()->terminator()->opcode() != SpvOpBranch) {
+  if (function->entry()->terminator()->opcode() != spv::Op::OpBranch) {
     return false;
   }
 
@@ -134,9 +134,9 @@
     bool all_instructions_allowed =
         ir_context->get_instr_block(merge_block)
             ->WhileEachInst([](opt::Instruction* inst) {
-              return inst->opcode() == SpvOpLabel ||
-                     inst->opcode() == SpvOpPhi ||
-                     inst->opcode() == SpvOpBranch;
+              return inst->opcode() == spv::Op::OpLabel ||
+                     inst->opcode() == spv::Op::OpPhi ||
+                     inst->opcode() == spv::Op::OpBranch;
             });
     if (!all_instructions_allowed) {
       return false;
@@ -286,7 +286,7 @@
     }
 
     // Replace the return instruction with an unconditional branch.
-    ret_block->terminator()->SetOpcode(SpvOpBranch);
+    ret_block->terminator()->SetOpcode(spv::Op::OpBranch);
     ret_block->terminator()->SetInOperands(
         {{SPV_OPERAND_TYPE_ID, {merge_block_id}}});
   }
@@ -410,7 +410,7 @@
 
       // Insert the instruction.
       merge_block->begin()->InsertBefore(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpPhi, function->type_id(), maybe_return_val_id,
+          ir_context, spv::Op::OpPhi, function->type_id(), maybe_return_val_id,
           std::move(operand_list)));
 
       fuzzerutil::UpdateModuleIdBound(ir_context, maybe_return_val_id);
@@ -448,14 +448,14 @@
 
       // Insert the instruction.
       merge_block->begin()->InsertBefore(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpPhi, bool_type, is_returning_id,
+          ir_context, spv::Op::OpPhi, bool_type, is_returning_id,
           std::move(operand_list)));
 
       fuzzerutil::UpdateModuleIdBound(ir_context, is_returning_id);
     }
 
     // Change the branching instruction of the block.
-    assert(merge_block->terminator()->opcode() == SpvOpBranch &&
+    assert(merge_block->terminator()->opcode() == spv::Op::OpBranch &&
            "Each block should branch unconditionally to the next.");
 
     // Add a new entry to the map corresponding to the merge block of the
@@ -483,14 +483,14 @@
 
     // The block should branch to |enclosing_merge| if |is_returning_id| is
     // true, to |original_succ| otherwise.
-    merge_block->terminator()->SetOpcode(SpvOpBranchConditional);
+    merge_block->terminator()->SetOpcode(spv::Op::OpBranchConditional);
     merge_block->terminator()->SetInOperands(
         {{SPV_OPERAND_TYPE_ID, {is_returning_id}},
          {SPV_OPERAND_TYPE_ID, {enclosing_merge}},
          {SPV_OPERAND_TYPE_ID, {original_succ}}});
   }
 
-  assert(function->entry()->terminator()->opcode() == SpvOpBranch &&
+  assert(function->entry()->terminator()->opcode() == spv::Op::OpBranch &&
          "The entry block should branch unconditionally to another block.");
   uint32_t block_after_entry =
       function->entry()->terminator()->GetSingleWordInOperand(0);
@@ -498,7 +498,7 @@
   // Create the header for the new outer loop.
   auto outer_loop_header =
       MakeUnique<opt::BasicBlock>(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpLabel, 0, message_.outer_header_id(),
+          ir_context, spv::Op::OpLabel, 0, message_.outer_header_id(),
           opt::Instruction::OperandList()));
 
   fuzzerutil::UpdateModuleIdBound(ir_context, message_.outer_header_id());
@@ -506,15 +506,16 @@
   // Add the instruction:
   //   OpLoopMerge %outer_return_id %unreachable_continue_id None
   outer_loop_header->AddInstruction(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpLoopMerge, 0, 0,
+      ir_context, spv::Op::OpLoopMerge, 0, 0,
       opt::Instruction::OperandList{
           {SPV_OPERAND_TYPE_ID, {message_.outer_return_id()}},
           {SPV_OPERAND_TYPE_ID, {message_.unreachable_continue_id()}},
-          {SPV_OPERAND_TYPE_LOOP_CONTROL, {SpvLoopControlMaskNone}}}));
+          {SPV_OPERAND_TYPE_LOOP_CONTROL,
+           {uint32_t(spv::LoopControlMask::MaskNone)}}}));
 
   // Add unconditional branch to %block_after_entry.
   outer_loop_header->AddInstruction(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpBranch, 0, 0,
+      ir_context, spv::Op::OpBranch, 0, 0,
       opt::Instruction::OperandList{
           {SPV_OPERAND_TYPE_ID, {block_after_entry}}}));
 
@@ -531,7 +532,7 @@
   ir_context->get_def_use_mgr()->ForEachUse(
       function->entry()->id(),
       [this](opt::Instruction* use_instruction, uint32_t use_operand_index) {
-        if (use_instruction->opcode() == SpvOpPhi) {
+        if (use_instruction->opcode() == spv::Op::OpPhi) {
           use_instruction->SetOperand(use_operand_index,
                                       {message_.outer_header_id()});
         }
@@ -540,7 +541,7 @@
   // Create the merge block for the loop (and return block for the function).
   auto outer_return_block =
       MakeUnique<opt::BasicBlock>(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpLabel, 0, message_.outer_return_id(),
+          ir_context, spv::Op::OpLabel, 0, message_.outer_return_id(),
           opt::Instruction::OperandList()));
 
   fuzzerutil::UpdateModuleIdBound(ir_context, message_.outer_return_id());
@@ -561,20 +562,20 @@
 
     // Insert the OpPhi instruction.
     outer_return_block->AddInstruction(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpPhi, function->type_id(), message_.return_val_id(),
-        std::move(operand_list)));
+        ir_context, spv::Op::OpPhi, function->type_id(),
+        message_.return_val_id(), std::move(operand_list)));
 
     fuzzerutil::UpdateModuleIdBound(ir_context, message_.return_val_id());
 
     // Insert the OpReturnValue instruction.
     outer_return_block->AddInstruction(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpReturnValue, 0, 0,
+        ir_context, spv::Op::OpReturnValue, 0, 0,
         opt::Instruction::OperandList{
             {SPV_OPERAND_TYPE_ID, {message_.return_val_id()}}}));
   } else {
     // Insert an OpReturn instruction (the function is void).
     outer_return_block->AddInstruction(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpReturn, 0, 0, opt::Instruction::OperandList{}));
+        ir_context, spv::Op::OpReturn, 0, 0, opt::Instruction::OperandList{}));
   }
 
   // Insert the new return block at the end of the function.
@@ -583,7 +584,7 @@
   // Create the unreachable continue block associated with the enclosing loop.
   auto unreachable_continue_block =
       MakeUnique<opt::BasicBlock>(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpLabel, 0, message_.unreachable_continue_id(),
+          ir_context, spv::Op::OpLabel, 0, message_.unreachable_continue_id(),
           opt::Instruction::OperandList()));
 
   fuzzerutil::UpdateModuleIdBound(ir_context,
@@ -591,7 +592,7 @@
 
   // Insert an branch back to the loop header, to create a back edge.
   unreachable_continue_block->AddInstruction(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpBranch, 0, 0,
+      ir_context, spv::Op::OpBranch, 0, 0,
       opt::Instruction::OperandList{
           {SPV_OPERAND_TYPE_ID, {message_.outer_header_id()}}}));
 
@@ -751,7 +752,7 @@
                   // The usage is OK if it is inside an OpPhi instruction in the
                   // merge block.
                   return block_use == merge_block &&
-                         inst_use->opcode() == SpvOpPhi;
+                         inst_use->opcode() == spv::Op::OpPhi;
                 });
           });
 
diff --git a/source/fuzz/transformation_move_instruction_down.cpp b/source/fuzz/transformation_move_instruction_down.cpp
index c8139e7..4d5d9f0 100644
--- a/source/fuzz/transformation_move_instruction_down.cpp
+++ b/source/fuzz/transformation_move_instruction_down.cpp
@@ -26,7 +26,7 @@
 
 std::string GetExtensionSet(opt::IRContext* ir_context,
                             const opt::Instruction& op_ext_inst) {
-  assert(op_ext_inst.opcode() == SpvOpExtInst && "Wrong opcode");
+  assert(op_ext_inst.opcode() == spv::Op::OpExtInst && "Wrong opcode");
 
   const auto* ext_inst_import = ir_context->get_def_use_mgr()->GetDef(
       op_ext_inst.GetSingleWordInOperand(0));
@@ -142,112 +142,112 @@
 bool TransformationMoveInstructionDown::IsSimpleInstruction(
     opt::IRContext* ir_context, const opt::Instruction& inst) {
   switch (inst.opcode()) {
-    case SpvOpNop:
-    case SpvOpUndef:
-    case SpvOpAccessChain:
-    case SpvOpInBoundsAccessChain:
+    case spv::Op::OpNop:
+    case spv::Op::OpUndef:
+    case spv::Op::OpAccessChain:
+    case spv::Op::OpInBoundsAccessChain:
       // OpAccessChain and OpInBoundsAccessChain are considered simple
       // instructions since they result in a pointer to the object in memory,
       // not the object itself.
-    case SpvOpVectorExtractDynamic:
-    case SpvOpVectorInsertDynamic:
-    case SpvOpVectorShuffle:
-    case SpvOpCompositeConstruct:
-    case SpvOpCompositeExtract:
-    case SpvOpCompositeInsert:
-    case SpvOpCopyObject:
-    case SpvOpTranspose:
-    case SpvOpConvertFToU:
-    case SpvOpConvertFToS:
-    case SpvOpConvertSToF:
-    case SpvOpConvertUToF:
-    case SpvOpUConvert:
-    case SpvOpSConvert:
-    case SpvOpFConvert:
-    case SpvOpQuantizeToF16:
-    case SpvOpSatConvertSToU:
-    case SpvOpSatConvertUToS:
-    case SpvOpBitcast:
-    case SpvOpSNegate:
-    case SpvOpFNegate:
-    case SpvOpIAdd:
-    case SpvOpFAdd:
-    case SpvOpISub:
-    case SpvOpFSub:
-    case SpvOpIMul:
-    case SpvOpFMul:
-    case SpvOpUDiv:
-    case SpvOpSDiv:
-    case SpvOpFDiv:
-    case SpvOpUMod:
-    case SpvOpSRem:
-    case SpvOpSMod:
-    case SpvOpFRem:
-    case SpvOpFMod:
-    case SpvOpVectorTimesScalar:
-    case SpvOpMatrixTimesScalar:
-    case SpvOpVectorTimesMatrix:
-    case SpvOpMatrixTimesVector:
-    case SpvOpMatrixTimesMatrix:
-    case SpvOpOuterProduct:
-    case SpvOpDot:
-    case SpvOpIAddCarry:
-    case SpvOpISubBorrow:
-    case SpvOpUMulExtended:
-    case SpvOpSMulExtended:
-    case SpvOpAny:
-    case SpvOpAll:
-    case SpvOpIsNan:
-    case SpvOpIsInf:
-    case SpvOpIsFinite:
-    case SpvOpIsNormal:
-    case SpvOpSignBitSet:
-    case SpvOpLessOrGreater:
-    case SpvOpOrdered:
-    case SpvOpUnordered:
-    case SpvOpLogicalEqual:
-    case SpvOpLogicalNotEqual:
-    case SpvOpLogicalOr:
-    case SpvOpLogicalAnd:
-    case SpvOpLogicalNot:
-    case SpvOpSelect:
-    case SpvOpIEqual:
-    case SpvOpINotEqual:
-    case SpvOpUGreaterThan:
-    case SpvOpSGreaterThan:
-    case SpvOpUGreaterThanEqual:
-    case SpvOpSGreaterThanEqual:
-    case SpvOpULessThan:
-    case SpvOpSLessThan:
-    case SpvOpULessThanEqual:
-    case SpvOpSLessThanEqual:
-    case SpvOpFOrdEqual:
-    case SpvOpFUnordEqual:
-    case SpvOpFOrdNotEqual:
-    case SpvOpFUnordNotEqual:
-    case SpvOpFOrdLessThan:
-    case SpvOpFUnordLessThan:
-    case SpvOpFOrdGreaterThan:
-    case SpvOpFUnordGreaterThan:
-    case SpvOpFOrdLessThanEqual:
-    case SpvOpFUnordLessThanEqual:
-    case SpvOpFOrdGreaterThanEqual:
-    case SpvOpFUnordGreaterThanEqual:
-    case SpvOpShiftRightLogical:
-    case SpvOpShiftRightArithmetic:
-    case SpvOpShiftLeftLogical:
-    case SpvOpBitwiseOr:
-    case SpvOpBitwiseXor:
-    case SpvOpBitwiseAnd:
-    case SpvOpNot:
-    case SpvOpBitFieldInsert:
-    case SpvOpBitFieldSExtract:
-    case SpvOpBitFieldUExtract:
-    case SpvOpBitReverse:
-    case SpvOpBitCount:
-    case SpvOpCopyLogical:
+    case spv::Op::OpVectorExtractDynamic:
+    case spv::Op::OpVectorInsertDynamic:
+    case spv::Op::OpVectorShuffle:
+    case spv::Op::OpCompositeConstruct:
+    case spv::Op::OpCompositeExtract:
+    case spv::Op::OpCompositeInsert:
+    case spv::Op::OpCopyObject:
+    case spv::Op::OpTranspose:
+    case spv::Op::OpConvertFToU:
+    case spv::Op::OpConvertFToS:
+    case spv::Op::OpConvertSToF:
+    case spv::Op::OpConvertUToF:
+    case spv::Op::OpUConvert:
+    case spv::Op::OpSConvert:
+    case spv::Op::OpFConvert:
+    case spv::Op::OpQuantizeToF16:
+    case spv::Op::OpSatConvertSToU:
+    case spv::Op::OpSatConvertUToS:
+    case spv::Op::OpBitcast:
+    case spv::Op::OpSNegate:
+    case spv::Op::OpFNegate:
+    case spv::Op::OpIAdd:
+    case spv::Op::OpFAdd:
+    case spv::Op::OpISub:
+    case spv::Op::OpFSub:
+    case spv::Op::OpIMul:
+    case spv::Op::OpFMul:
+    case spv::Op::OpUDiv:
+    case spv::Op::OpSDiv:
+    case spv::Op::OpFDiv:
+    case spv::Op::OpUMod:
+    case spv::Op::OpSRem:
+    case spv::Op::OpSMod:
+    case spv::Op::OpFRem:
+    case spv::Op::OpFMod:
+    case spv::Op::OpVectorTimesScalar:
+    case spv::Op::OpMatrixTimesScalar:
+    case spv::Op::OpVectorTimesMatrix:
+    case spv::Op::OpMatrixTimesVector:
+    case spv::Op::OpMatrixTimesMatrix:
+    case spv::Op::OpOuterProduct:
+    case spv::Op::OpDot:
+    case spv::Op::OpIAddCarry:
+    case spv::Op::OpISubBorrow:
+    case spv::Op::OpUMulExtended:
+    case spv::Op::OpSMulExtended:
+    case spv::Op::OpAny:
+    case spv::Op::OpAll:
+    case spv::Op::OpIsNan:
+    case spv::Op::OpIsInf:
+    case spv::Op::OpIsFinite:
+    case spv::Op::OpIsNormal:
+    case spv::Op::OpSignBitSet:
+    case spv::Op::OpLessOrGreater:
+    case spv::Op::OpOrdered:
+    case spv::Op::OpUnordered:
+    case spv::Op::OpLogicalEqual:
+    case spv::Op::OpLogicalNotEqual:
+    case spv::Op::OpLogicalOr:
+    case spv::Op::OpLogicalAnd:
+    case spv::Op::OpLogicalNot:
+    case spv::Op::OpSelect:
+    case spv::Op::OpIEqual:
+    case spv::Op::OpINotEqual:
+    case spv::Op::OpUGreaterThan:
+    case spv::Op::OpSGreaterThan:
+    case spv::Op::OpUGreaterThanEqual:
+    case spv::Op::OpSGreaterThanEqual:
+    case spv::Op::OpULessThan:
+    case spv::Op::OpSLessThan:
+    case spv::Op::OpULessThanEqual:
+    case spv::Op::OpSLessThanEqual:
+    case spv::Op::OpFOrdEqual:
+    case spv::Op::OpFUnordEqual:
+    case spv::Op::OpFOrdNotEqual:
+    case spv::Op::OpFUnordNotEqual:
+    case spv::Op::OpFOrdLessThan:
+    case spv::Op::OpFUnordLessThan:
+    case spv::Op::OpFOrdGreaterThan:
+    case spv::Op::OpFUnordGreaterThan:
+    case spv::Op::OpFOrdLessThanEqual:
+    case spv::Op::OpFUnordLessThanEqual:
+    case spv::Op::OpFOrdGreaterThanEqual:
+    case spv::Op::OpFUnordGreaterThanEqual:
+    case spv::Op::OpShiftRightLogical:
+    case spv::Op::OpShiftRightArithmetic:
+    case spv::Op::OpShiftLeftLogical:
+    case spv::Op::OpBitwiseOr:
+    case spv::Op::OpBitwiseXor:
+    case spv::Op::OpBitwiseAnd:
+    case spv::Op::OpNot:
+    case spv::Op::OpBitFieldInsert:
+    case spv::Op::OpBitFieldSExtract:
+    case spv::Op::OpBitFieldUExtract:
+    case spv::Op::OpBitReverse:
+    case spv::Op::OpBitCount:
+    case spv::Op::OpCopyLogical:
       return true;
-    case SpvOpExtInst: {
+    case spv::Op::OpExtInst: {
       const auto* ext_inst_import =
           ir_context->get_def_use_mgr()->GetDef(inst.GetSingleWordInOperand(0));
 
@@ -346,53 +346,53 @@
     opt::IRContext* ir_context, const opt::Instruction& inst) {
   switch (inst.opcode()) {
       // Some simple instructions.
-    case SpvOpLoad:
-    case SpvOpCopyMemory:
+    case spv::Op::OpLoad:
+    case spv::Op::OpCopyMemory:
       // Image instructions.
-    case SpvOpImageSampleImplicitLod:
-    case SpvOpImageSampleExplicitLod:
-    case SpvOpImageSampleDrefImplicitLod:
-    case SpvOpImageSampleDrefExplicitLod:
-    case SpvOpImageSampleProjImplicitLod:
-    case SpvOpImageSampleProjExplicitLod:
-    case SpvOpImageSampleProjDrefImplicitLod:
-    case SpvOpImageSampleProjDrefExplicitLod:
-    case SpvOpImageFetch:
-    case SpvOpImageGather:
-    case SpvOpImageDrefGather:
-    case SpvOpImageRead:
-    case SpvOpImageSparseSampleImplicitLod:
-    case SpvOpImageSparseSampleExplicitLod:
-    case SpvOpImageSparseSampleDrefImplicitLod:
-    case SpvOpImageSparseSampleDrefExplicitLod:
-    case SpvOpImageSparseSampleProjImplicitLod:
-    case SpvOpImageSparseSampleProjExplicitLod:
-    case SpvOpImageSparseSampleProjDrefImplicitLod:
-    case SpvOpImageSparseSampleProjDrefExplicitLod:
-    case SpvOpImageSparseFetch:
-    case SpvOpImageSparseGather:
-    case SpvOpImageSparseDrefGather:
-    case SpvOpImageSparseRead:
+    case spv::Op::OpImageSampleImplicitLod:
+    case spv::Op::OpImageSampleExplicitLod:
+    case spv::Op::OpImageSampleDrefImplicitLod:
+    case spv::Op::OpImageSampleDrefExplicitLod:
+    case spv::Op::OpImageSampleProjImplicitLod:
+    case spv::Op::OpImageSampleProjExplicitLod:
+    case spv::Op::OpImageSampleProjDrefImplicitLod:
+    case spv::Op::OpImageSampleProjDrefExplicitLod:
+    case spv::Op::OpImageFetch:
+    case spv::Op::OpImageGather:
+    case spv::Op::OpImageDrefGather:
+    case spv::Op::OpImageRead:
+    case spv::Op::OpImageSparseSampleImplicitLod:
+    case spv::Op::OpImageSparseSampleExplicitLod:
+    case spv::Op::OpImageSparseSampleDrefImplicitLod:
+    case spv::Op::OpImageSparseSampleDrefExplicitLod:
+    case spv::Op::OpImageSparseSampleProjImplicitLod:
+    case spv::Op::OpImageSparseSampleProjExplicitLod:
+    case spv::Op::OpImageSparseSampleProjDrefImplicitLod:
+    case spv::Op::OpImageSparseSampleProjDrefExplicitLod:
+    case spv::Op::OpImageSparseFetch:
+    case spv::Op::OpImageSparseGather:
+    case spv::Op::OpImageSparseDrefGather:
+    case spv::Op::OpImageSparseRead:
       // Atomic instructions.
-    case SpvOpAtomicLoad:
-    case SpvOpAtomicExchange:
-    case SpvOpAtomicCompareExchange:
-    case SpvOpAtomicCompareExchangeWeak:
-    case SpvOpAtomicIIncrement:
-    case SpvOpAtomicIDecrement:
-    case SpvOpAtomicIAdd:
-    case SpvOpAtomicISub:
-    case SpvOpAtomicSMin:
-    case SpvOpAtomicUMin:
-    case SpvOpAtomicSMax:
-    case SpvOpAtomicUMax:
-    case SpvOpAtomicAnd:
-    case SpvOpAtomicOr:
-    case SpvOpAtomicXor:
-    case SpvOpAtomicFlagTestAndSet:
+    case spv::Op::OpAtomicLoad:
+    case spv::Op::OpAtomicExchange:
+    case spv::Op::OpAtomicCompareExchange:
+    case spv::Op::OpAtomicCompareExchangeWeak:
+    case spv::Op::OpAtomicIIncrement:
+    case spv::Op::OpAtomicIDecrement:
+    case spv::Op::OpAtomicIAdd:
+    case spv::Op::OpAtomicISub:
+    case spv::Op::OpAtomicSMin:
+    case spv::Op::OpAtomicUMin:
+    case spv::Op::OpAtomicSMax:
+    case spv::Op::OpAtomicUMax:
+    case spv::Op::OpAtomicAnd:
+    case spv::Op::OpAtomicOr:
+    case spv::Op::OpAtomicXor:
+    case spv::Op::OpAtomicFlagTestAndSet:
       return true;
       // Extensions.
-    case SpvOpExtInst: {
+    case spv::Op::OpExtInst: {
       if (GetExtensionSet(ir_context, inst) != kExtensionSetName) {
         return false;
       }
@@ -419,53 +419,53 @@
 
   switch (inst.opcode()) {
       // Simple instructions.
-    case SpvOpLoad:
+    case spv::Op::OpLoad:
       // Image instructions.
-    case SpvOpImageSampleImplicitLod:
-    case SpvOpImageSampleExplicitLod:
-    case SpvOpImageSampleDrefImplicitLod:
-    case SpvOpImageSampleDrefExplicitLod:
-    case SpvOpImageSampleProjImplicitLod:
-    case SpvOpImageSampleProjExplicitLod:
-    case SpvOpImageSampleProjDrefImplicitLod:
-    case SpvOpImageSampleProjDrefExplicitLod:
-    case SpvOpImageFetch:
-    case SpvOpImageGather:
-    case SpvOpImageDrefGather:
-    case SpvOpImageRead:
-    case SpvOpImageSparseSampleImplicitLod:
-    case SpvOpImageSparseSampleExplicitLod:
-    case SpvOpImageSparseSampleDrefImplicitLod:
-    case SpvOpImageSparseSampleDrefExplicitLod:
-    case SpvOpImageSparseSampleProjImplicitLod:
-    case SpvOpImageSparseSampleProjExplicitLod:
-    case SpvOpImageSparseSampleProjDrefImplicitLod:
-    case SpvOpImageSparseSampleProjDrefExplicitLod:
-    case SpvOpImageSparseFetch:
-    case SpvOpImageSparseGather:
-    case SpvOpImageSparseDrefGather:
-    case SpvOpImageSparseRead:
+    case spv::Op::OpImageSampleImplicitLod:
+    case spv::Op::OpImageSampleExplicitLod:
+    case spv::Op::OpImageSampleDrefImplicitLod:
+    case spv::Op::OpImageSampleDrefExplicitLod:
+    case spv::Op::OpImageSampleProjImplicitLod:
+    case spv::Op::OpImageSampleProjExplicitLod:
+    case spv::Op::OpImageSampleProjDrefImplicitLod:
+    case spv::Op::OpImageSampleProjDrefExplicitLod:
+    case spv::Op::OpImageFetch:
+    case spv::Op::OpImageGather:
+    case spv::Op::OpImageDrefGather:
+    case spv::Op::OpImageRead:
+    case spv::Op::OpImageSparseSampleImplicitLod:
+    case spv::Op::OpImageSparseSampleExplicitLod:
+    case spv::Op::OpImageSparseSampleDrefImplicitLod:
+    case spv::Op::OpImageSparseSampleDrefExplicitLod:
+    case spv::Op::OpImageSparseSampleProjImplicitLod:
+    case spv::Op::OpImageSparseSampleProjExplicitLod:
+    case spv::Op::OpImageSparseSampleProjDrefImplicitLod:
+    case spv::Op::OpImageSparseSampleProjDrefExplicitLod:
+    case spv::Op::OpImageSparseFetch:
+    case spv::Op::OpImageSparseGather:
+    case spv::Op::OpImageSparseDrefGather:
+    case spv::Op::OpImageSparseRead:
       // Atomic instructions.
-    case SpvOpAtomicLoad:
-    case SpvOpAtomicExchange:
-    case SpvOpAtomicCompareExchange:
-    case SpvOpAtomicCompareExchangeWeak:
-    case SpvOpAtomicIIncrement:
-    case SpvOpAtomicIDecrement:
-    case SpvOpAtomicIAdd:
-    case SpvOpAtomicISub:
-    case SpvOpAtomicSMin:
-    case SpvOpAtomicUMin:
-    case SpvOpAtomicSMax:
-    case SpvOpAtomicUMax:
-    case SpvOpAtomicAnd:
-    case SpvOpAtomicOr:
-    case SpvOpAtomicXor:
-    case SpvOpAtomicFlagTestAndSet:
+    case spv::Op::OpAtomicLoad:
+    case spv::Op::OpAtomicExchange:
+    case spv::Op::OpAtomicCompareExchange:
+    case spv::Op::OpAtomicCompareExchangeWeak:
+    case spv::Op::OpAtomicIIncrement:
+    case spv::Op::OpAtomicIDecrement:
+    case spv::Op::OpAtomicIAdd:
+    case spv::Op::OpAtomicISub:
+    case spv::Op::OpAtomicSMin:
+    case spv::Op::OpAtomicUMin:
+    case spv::Op::OpAtomicSMax:
+    case spv::Op::OpAtomicUMax:
+    case spv::Op::OpAtomicAnd:
+    case spv::Op::OpAtomicOr:
+    case spv::Op::OpAtomicXor:
+    case spv::Op::OpAtomicFlagTestAndSet:
       return inst.GetSingleWordInOperand(0);
-    case SpvOpCopyMemory:
+    case spv::Op::OpCopyMemory:
       return inst.GetSingleWordInOperand(1);
-    case SpvOpExtInst: {
+    case spv::Op::OpExtInst: {
       assert(GetExtensionSet(ir_context, inst) == kExtensionSetName &&
              "Extension set is not supported");
 
@@ -493,31 +493,31 @@
     opt::IRContext* ir_context, const opt::Instruction& inst) {
   switch (inst.opcode()) {
       // Simple Instructions.
-    case SpvOpStore:
-    case SpvOpCopyMemory:
+    case spv::Op::OpStore:
+    case spv::Op::OpCopyMemory:
       // Image instructions.
-    case SpvOpImageWrite:
+    case spv::Op::OpImageWrite:
       // Atomic instructions.
-    case SpvOpAtomicStore:
-    case SpvOpAtomicExchange:
-    case SpvOpAtomicCompareExchange:
-    case SpvOpAtomicCompareExchangeWeak:
-    case SpvOpAtomicIIncrement:
-    case SpvOpAtomicIDecrement:
-    case SpvOpAtomicIAdd:
-    case SpvOpAtomicISub:
-    case SpvOpAtomicSMin:
-    case SpvOpAtomicUMin:
-    case SpvOpAtomicSMax:
-    case SpvOpAtomicUMax:
-    case SpvOpAtomicAnd:
-    case SpvOpAtomicOr:
-    case SpvOpAtomicXor:
-    case SpvOpAtomicFlagTestAndSet:
-    case SpvOpAtomicFlagClear:
+    case spv::Op::OpAtomicStore:
+    case spv::Op::OpAtomicExchange:
+    case spv::Op::OpAtomicCompareExchange:
+    case spv::Op::OpAtomicCompareExchangeWeak:
+    case spv::Op::OpAtomicIIncrement:
+    case spv::Op::OpAtomicIDecrement:
+    case spv::Op::OpAtomicIAdd:
+    case spv::Op::OpAtomicISub:
+    case spv::Op::OpAtomicSMin:
+    case spv::Op::OpAtomicUMin:
+    case spv::Op::OpAtomicSMax:
+    case spv::Op::OpAtomicUMax:
+    case spv::Op::OpAtomicAnd:
+    case spv::Op::OpAtomicOr:
+    case spv::Op::OpAtomicXor:
+    case spv::Op::OpAtomicFlagTestAndSet:
+    case spv::Op::OpAtomicFlagClear:
       return true;
       // Extensions.
-    case SpvOpExtInst: {
+    case spv::Op::OpExtInst: {
       if (GetExtensionSet(ir_context, inst) != kExtensionSetName) {
         return false;
       }
@@ -537,28 +537,28 @@
          "|inst| is not a memory write instruction");
 
   switch (inst.opcode()) {
-    case SpvOpStore:
-    case SpvOpCopyMemory:
-    case SpvOpImageWrite:
-    case SpvOpAtomicStore:
-    case SpvOpAtomicExchange:
-    case SpvOpAtomicCompareExchange:
-    case SpvOpAtomicCompareExchangeWeak:
-    case SpvOpAtomicIIncrement:
-    case SpvOpAtomicIDecrement:
-    case SpvOpAtomicIAdd:
-    case SpvOpAtomicISub:
-    case SpvOpAtomicSMin:
-    case SpvOpAtomicUMin:
-    case SpvOpAtomicSMax:
-    case SpvOpAtomicUMax:
-    case SpvOpAtomicAnd:
-    case SpvOpAtomicOr:
-    case SpvOpAtomicXor:
-    case SpvOpAtomicFlagTestAndSet:
-    case SpvOpAtomicFlagClear:
+    case spv::Op::OpStore:
+    case spv::Op::OpCopyMemory:
+    case spv::Op::OpImageWrite:
+    case spv::Op::OpAtomicStore:
+    case spv::Op::OpAtomicExchange:
+    case spv::Op::OpAtomicCompareExchange:
+    case spv::Op::OpAtomicCompareExchangeWeak:
+    case spv::Op::OpAtomicIIncrement:
+    case spv::Op::OpAtomicIDecrement:
+    case spv::Op::OpAtomicIAdd:
+    case spv::Op::OpAtomicISub:
+    case spv::Op::OpAtomicSMin:
+    case spv::Op::OpAtomicUMin:
+    case spv::Op::OpAtomicSMax:
+    case spv::Op::OpAtomicUMax:
+    case spv::Op::OpAtomicAnd:
+    case spv::Op::OpAtomicOr:
+    case spv::Op::OpAtomicXor:
+    case spv::Op::OpAtomicFlagTestAndSet:
+    case spv::Op::OpAtomicFlagClear:
       return inst.GetSingleWordInOperand(0);
-    case SpvOpExtInst: {
+    case spv::Op::OpExtInst: {
       assert(GetExtensionSet(ir_context, inst) == kExtensionSetName &&
              "Extension set is not supported");
 
@@ -590,9 +590,9 @@
 bool TransformationMoveInstructionDown::IsBarrierInstruction(
     const opt::Instruction& inst) {
   switch (inst.opcode()) {
-    case SpvOpMemoryBarrier:
-    case SpvOpControlBarrier:
-    case SpvOpMemoryNamedBarrier:
+    case spv::Op::OpMemoryBarrier:
+    case spv::Op::OpControlBarrier:
+    case spv::Op::OpMemoryNamedBarrier:
       return true;
     default:
       return false;
diff --git a/source/fuzz/transformation_mutate_pointer.cpp b/source/fuzz/transformation_mutate_pointer.cpp
index 516a0d6..a1620cc 100644
--- a/source/fuzz/transformation_mutate_pointer.cpp
+++ b/source/fuzz/transformation_mutate_pointer.cpp
@@ -51,7 +51,7 @@
   // Check that it is possible to insert OpLoad and OpStore before
   // |insert_before_inst|. We are only using OpLoad here since the result does
   // not depend on the opcode.
-  if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLoad,
+  if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpLoad,
                                                     insert_before_inst)) {
     return false;
   }
@@ -100,7 +100,7 @@
 
   // Back up the original value.
   auto backup_instruction = MakeUnique<opt::Instruction>(
-      ir_context, SpvOpLoad, pointee_type_id, message_.fresh_id(),
+      ir_context, spv::Op::OpLoad, pointee_type_id, message_.fresh_id(),
       opt::Instruction::OperandList{
           {SPV_OPERAND_TYPE_ID, {message_.pointer_id()}}});
   auto backup_instruction_ptr = backup_instruction.get();
@@ -110,7 +110,7 @@
 
   // Insert a new value.
   auto new_value_instruction = MakeUnique<opt::Instruction>(
-      ir_context, SpvOpStore, 0, 0,
+      ir_context, spv::Op::OpStore, 0, 0,
       opt::Instruction::OperandList{
           {SPV_OPERAND_TYPE_ID, {message_.pointer_id()}},
           {SPV_OPERAND_TYPE_ID,
@@ -123,7 +123,7 @@
 
   // Restore the original value.
   auto restore_instruction = MakeUnique<opt::Instruction>(
-      ir_context, SpvOpStore, 0, 0,
+      ir_context, spv::Op::OpStore, 0, 0,
       opt::Instruction::OperandList{
           {SPV_OPERAND_TYPE_ID, {message_.pointer_id()}},
           {SPV_OPERAND_TYPE_ID, {message_.fresh_id()}}});
@@ -145,8 +145,9 @@
     opt::IRContext* ir_context, const opt::Instruction& inst) {
   // |inst| must have both result id and type id and it may not cause undefined
   // behaviour.
-  if (!inst.result_id() || !inst.type_id() || inst.opcode() == SpvOpUndef ||
-      inst.opcode() == SpvOpConstantNull) {
+  if (!inst.result_id() || !inst.type_id() ||
+      inst.opcode() == spv::Op::OpUndef ||
+      inst.opcode() == spv::Op::OpConstantNull) {
     return false;
   }
 
@@ -155,15 +156,16 @@
   assert(type_inst != nullptr && "|inst| has invalid type id");
 
   // |inst| must be a pointer.
-  if (type_inst->opcode() != SpvOpTypePointer) {
+  if (type_inst->opcode() != spv::Op::OpTypePointer) {
     return false;
   }
 
   // |inst| must have a supported storage class.
-  switch (static_cast<SpvStorageClass>(type_inst->GetSingleWordInOperand(0))) {
-    case SpvStorageClassFunction:
-    case SpvStorageClassPrivate:
-    case SpvStorageClassWorkgroup:
+  switch (
+      static_cast<spv::StorageClass>(type_inst->GetSingleWordInOperand(0))) {
+    case spv::StorageClass::Function:
+    case spv::StorageClass::Private:
+    case spv::StorageClass::Workgroup:
       break;
     default:
       return false;
diff --git a/source/fuzz/transformation_outline_function.cpp b/source/fuzz/transformation_outline_function.cpp
index 3140fa6..4ab68d0 100644
--- a/source/fuzz/transformation_outline_function.cpp
+++ b/source/fuzz/transformation_outline_function.cpp
@@ -107,7 +107,7 @@
   // The entry and exit block ids must indeed refer to blocks.
   for (auto block_id : {message_.entry_block(), message_.exit_block()}) {
     auto block_label = ir_context->get_def_use_mgr()->GetDef(block_id);
-    if (!block_label || block_label->opcode() != SpvOpLabel) {
+    if (!block_label || block_label->opcode() != spv::Op::OpLabel) {
       return false;
     }
   }
@@ -118,7 +118,7 @@
   // The entry block cannot start with OpVariable - this would mean that
   // outlining would remove a variable from the function containing the region
   // being outlined.
-  if (entry_block->begin()->opcode() == SpvOpVariable) {
+  if (entry_block->begin()->opcode() == spv::Op::OpVariable) {
     return false;
   }
 
@@ -136,7 +136,7 @@
   // The entry block cannot start with OpPhi.  This is to keep the
   // transformation logic simple.  (Another transformation to split the OpPhis
   // from a block could be applied to avoid this scenario.)
-  if (entry_block->begin()->opcode() == SpvOpPhi) {
+  if (entry_block->begin()->opcode() == spv::Op::OpPhi) {
     return false;
   }
 
@@ -257,10 +257,10 @@
     auto input_id_inst = ir_context->get_def_use_mgr()->GetDef(id);
     if (ir_context->get_def_use_mgr()
             ->GetDef(input_id_inst->type_id())
-            ->opcode() == SpvOpTypePointer) {
+            ->opcode() == spv::Op::OpTypePointer) {
       switch (input_id_inst->opcode()) {
-        case SpvOpFunctionParameter:
-        case SpvOpVariable:
+        case spv::Op::OpFunctionParameter:
+        case spv::Op::OpVariable:
           // These are OK.
           break;
         default:
@@ -286,7 +286,7 @@
         // function)
         || ir_context->get_def_use_mgr()
                    ->GetDef(fuzzerutil::GetTypeId(ir_context, id))
-                   ->opcode() == SpvOpTypePointer) {
+                   ->opcode() == spv::Op::OpTypePointer) {
       return false;
     }
   }
@@ -608,7 +608,7 @@
         auto output_id_type =
             ir_context->get_def_use_mgr()->GetDef(output_id)->type_id();
         if (ir_context->get_def_use_mgr()->GetDef(output_id_type)->opcode() ==
-            SpvOpTypeVoid) {
+            spv::Op::OpTypeVoid) {
           // We cannot add a void field to a struct.  We instead use OpUndef to
           // handle void output ids.
           continue;
@@ -617,7 +617,7 @@
       }
       // Add a new struct type to the module.
       ir_context->module()->AddType(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpTypeStruct, 0,
+          ir_context, spv::Op::OpTypeStruct, 0,
           message_.new_function_struct_return_type_id(),
           std::move(struct_member_types)));
       // The return type for the function is the newly-created struct.
@@ -638,7 +638,7 @@
     // Add a new function type to the module, and record that this is the type
     // id for the new function.
     ir_context->module()->AddType(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpTypeFunction, 0, message_.new_function_type_id(),
+        ir_context, spv::Op::OpTypeFunction, 0, message_.new_function_type_id(),
         function_type_operands));
     function_type_id = message_.new_function_type_id();
   }
@@ -647,10 +647,11 @@
   // and the return type and function type prepared above.
   std::unique_ptr<opt::Function> outlined_function =
       MakeUnique<opt::Function>(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpFunction, return_type_id, message_.new_function_id(),
+          ir_context, spv::Op::OpFunction, return_type_id,
+          message_.new_function_id(),
           opt::Instruction::OperandList(
               {{spv_operand_type_t ::SPV_OPERAND_TYPE_LITERAL_INTEGER,
-                {SpvFunctionControlMaskNone}},
+                {uint32_t(spv::FunctionControlMask::MaskNone)}},
                {spv_operand_type_t::SPV_OPERAND_TYPE_ID,
                 {function_type_id}}})));
 
@@ -659,7 +660,7 @@
   for (auto id : region_input_ids) {
     uint32_t fresh_id = input_id_to_fresh_id_map.at(id);
     outlined_function->AddParameter(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpFunctionParameter,
+        ir_context, spv::Op::OpFunctionParameter,
         ir_context->get_def_use_mgr()->GetDef(id)->type_id(), fresh_id,
         opt::Instruction::OperandList()));
 
@@ -788,7 +789,8 @@
   // |message_.new_function_region_entry_block| as its id.
   std::unique_ptr<opt::BasicBlock> outlined_region_entry_block =
       MakeUnique<opt::BasicBlock>(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpLabel, 0, message_.new_function_region_entry_block(),
+          ir_context, spv::Op::OpLabel, 0,
+          message_.new_function_region_entry_block(),
           opt::Instruction::OperandList()));
 
   if (&original_region_entry_block == &original_region_exit_block) {
@@ -854,8 +856,8 @@
   // the cloned exit block.
   for (auto inst_it = outlined_region_exit_block->begin();
        inst_it != outlined_region_exit_block->end();) {
-    if (inst_it->opcode() == SpvOpLoopMerge ||
-        inst_it->opcode() == SpvOpSelectionMerge) {
+    if (inst_it->opcode() == spv::Op::OpLoopMerge ||
+        inst_it->opcode() == spv::Op::OpSelectionMerge) {
       inst_it = inst_it.Erase();
     } else if (inst_it->IsBlockTerminator()) {
       inst_it = inst_it.Erase();
@@ -870,7 +872,7 @@
     // The case where there are no region output ids is simple: we just add
     // OpReturn.
     outlined_region_exit_block->AddInstruction(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpReturn, 0, 0, opt::Instruction::OperandList()));
+        ir_context, spv::Op::OpReturn, 0, 0, opt::Instruction::OperandList()));
   } else {
     // In the case where there are output ids, we add an OpCompositeConstruct
     // instruction to pack all the non-void output values into a struct, and
@@ -879,23 +881,24 @@
     for (uint32_t id : region_output_ids) {
       if (ir_context->get_def_use_mgr()
               ->GetDef(output_id_to_type_id.at(id))
-              ->opcode() != SpvOpTypeVoid) {
+              ->opcode() != spv::Op::OpTypeVoid) {
         struct_member_operands.push_back(
             {SPV_OPERAND_TYPE_ID, {output_id_to_fresh_id_map.at(id)}});
       }
     }
     outlined_region_exit_block->AddInstruction(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpCompositeConstruct,
+        ir_context, spv::Op::OpCompositeConstruct,
         message_.new_function_struct_return_type_id(),
         message_.new_callee_result_id(), struct_member_operands));
     outlined_region_exit_block->AddInstruction(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpReturnValue, 0, 0,
+        ir_context, spv::Op::OpReturnValue, 0, 0,
         opt::Instruction::OperandList(
             {{SPV_OPERAND_TYPE_ID, {message_.new_callee_result_id()}}})));
   }
 
-  outlined_function->SetFunctionEnd(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpFunctionEnd, 0, 0, opt::Instruction::OperandList()));
+  outlined_function->SetFunctionEnd(
+      MakeUnique<opt::Instruction>(ir_context, spv::Op::OpFunctionEnd, 0, 0,
+                                   opt::Instruction::OperandList()));
 }
 
 void TransformationOutlineFunction::ShrinkOriginalRegion(
@@ -963,7 +966,7 @@
   }
 
   original_region_entry_block->AddInstruction(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpFunctionCall, return_type_id,
+      ir_context, spv::Op::OpFunctionCall, return_type_id,
       message_.new_caller_result_id(), function_call_operands));
 
   // If there are output ids, the function call will return a struct.  For each
@@ -975,15 +978,15 @@
   for (uint32_t output_id : region_output_ids) {
     uint32_t output_type_id = output_id_to_type_id.at(output_id);
     if (ir_context->get_def_use_mgr()->GetDef(output_type_id)->opcode() ==
-        SpvOpTypeVoid) {
+        spv::Op::OpTypeVoid) {
       original_region_entry_block->AddInstruction(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpUndef, output_type_id, output_id,
+          ir_context, spv::Op::OpUndef, output_type_id, output_id,
           opt::Instruction::OperandList()));
       // struct_member_index is not incremented since there was no struct member
       // associated with this void-typed output id.
     } else {
       original_region_entry_block->AddInstruction(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpCompositeExtract, output_type_id, output_id,
+          ir_context, spv::Op::OpCompositeExtract, output_type_id, output_id,
           opt::Instruction::OperandList(
               {{SPV_OPERAND_TYPE_ID, {message_.new_caller_result_id()}},
                {SPV_OPERAND_TYPE_LITERAL_INTEGER, {struct_member_index}}})));
diff --git a/source/fuzz/transformation_permute_function_parameters.cpp b/source/fuzz/transformation_permute_function_parameters.cpp
index 5663d72..b666cdf 100644
--- a/source/fuzz/transformation_permute_function_parameters.cpp
+++ b/source/fuzz/transformation_permute_function_parameters.cpp
@@ -43,7 +43,7 @@
   // Check that function exists
   const auto* function =
       fuzzerutil::FindFunction(ir_context, message_.function_id());
-  if (!function || function->DefInst().opcode() != SpvOpFunction ||
+  if (!function || function->DefInst().opcode() != spv::Op::OpFunction ||
       fuzzerutil::FunctionIsEntryPoint(ir_context, function->result_id())) {
     return false;
   }
diff --git a/source/fuzz/transformation_permute_phi_operands.cpp b/source/fuzz/transformation_permute_phi_operands.cpp
index 7ee7a82..f2f4057 100644
--- a/source/fuzz/transformation_permute_phi_operands.cpp
+++ b/source/fuzz/transformation_permute_phi_operands.cpp
@@ -39,7 +39,7 @@
   // Check that |message_.result_id| is valid.
   const auto* inst =
       ir_context->get_def_use_mgr()->GetDef(message_.result_id());
-  if (!inst || inst->opcode() != SpvOpPhi) {
+  if (!inst || inst->opcode() != spv::Op::OpPhi) {
     return false;
   }
 
diff --git a/source/fuzz/transformation_propagate_instruction_down.cpp b/source/fuzz/transformation_propagate_instruction_down.cpp
index c3b7c4d..4b98784 100644
--- a/source/fuzz/transformation_propagate_instruction_down.cpp
+++ b/source/fuzz/transformation_propagate_instruction_down.cpp
@@ -144,7 +144,7 @@
         ->block(merge_block_id)
         ->begin()
         ->InsertBefore(MakeUnique<opt::Instruction>(
-            ir_context, SpvOpPhi, inst_to_propagate->type_id(),
+            ir_context, spv::Op::OpPhi, inst_to_propagate->type_id(),
             message_.phi_fresh_id(), std::move(in_operands)));
 
     fuzzerutil::UpdateModuleIdBound(ir_context, message_.phi_fresh_id());
@@ -234,115 +234,115 @@
   return result;
 }
 
-bool TransformationPropagateInstructionDown::IsOpcodeSupported(SpvOp opcode) {
+bool TransformationPropagateInstructionDown::IsOpcodeSupported(spv::Op opcode) {
   // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3605):
   //  We only support "simple" instructions that don't work with memory.
   //  We should extend this so that we support the ones that modify the memory
   //  too.
   switch (opcode) {
-    case SpvOpUndef:
-    case SpvOpAccessChain:
-    case SpvOpInBoundsAccessChain:
-    case SpvOpArrayLength:
-    case SpvOpVectorExtractDynamic:
-    case SpvOpVectorInsertDynamic:
-    case SpvOpVectorShuffle:
-    case SpvOpCompositeConstruct:
-    case SpvOpCompositeExtract:
-    case SpvOpCompositeInsert:
-    case SpvOpCopyObject:
-    case SpvOpTranspose:
-    case SpvOpConvertFToU:
-    case SpvOpConvertFToS:
-    case SpvOpConvertSToF:
-    case SpvOpConvertUToF:
-    case SpvOpUConvert:
-    case SpvOpSConvert:
-    case SpvOpFConvert:
-    case SpvOpQuantizeToF16:
-    case SpvOpSatConvertSToU:
-    case SpvOpSatConvertUToS:
-    case SpvOpBitcast:
-    case SpvOpSNegate:
-    case SpvOpFNegate:
-    case SpvOpIAdd:
-    case SpvOpFAdd:
-    case SpvOpISub:
-    case SpvOpFSub:
-    case SpvOpIMul:
-    case SpvOpFMul:
-    case SpvOpUDiv:
-    case SpvOpSDiv:
-    case SpvOpFDiv:
-    case SpvOpUMod:
-    case SpvOpSRem:
-    case SpvOpSMod:
-    case SpvOpFRem:
-    case SpvOpFMod:
-    case SpvOpVectorTimesScalar:
-    case SpvOpMatrixTimesScalar:
-    case SpvOpVectorTimesMatrix:
-    case SpvOpMatrixTimesVector:
-    case SpvOpMatrixTimesMatrix:
-    case SpvOpOuterProduct:
-    case SpvOpDot:
-    case SpvOpIAddCarry:
-    case SpvOpISubBorrow:
-    case SpvOpUMulExtended:
-    case SpvOpSMulExtended:
-    case SpvOpAny:
-    case SpvOpAll:
-    case SpvOpIsNan:
-    case SpvOpIsInf:
-    case SpvOpIsFinite:
-    case SpvOpIsNormal:
-    case SpvOpSignBitSet:
-    case SpvOpLessOrGreater:
-    case SpvOpOrdered:
-    case SpvOpUnordered:
-    case SpvOpLogicalEqual:
-    case SpvOpLogicalNotEqual:
-    case SpvOpLogicalOr:
-    case SpvOpLogicalAnd:
-    case SpvOpLogicalNot:
-    case SpvOpSelect:
-    case SpvOpIEqual:
-    case SpvOpINotEqual:
-    case SpvOpUGreaterThan:
-    case SpvOpSGreaterThan:
-    case SpvOpUGreaterThanEqual:
-    case SpvOpSGreaterThanEqual:
-    case SpvOpULessThan:
-    case SpvOpSLessThan:
-    case SpvOpULessThanEqual:
-    case SpvOpSLessThanEqual:
-    case SpvOpFOrdEqual:
-    case SpvOpFUnordEqual:
-    case SpvOpFOrdNotEqual:
-    case SpvOpFUnordNotEqual:
-    case SpvOpFOrdLessThan:
-    case SpvOpFUnordLessThan:
-    case SpvOpFOrdGreaterThan:
-    case SpvOpFUnordGreaterThan:
-    case SpvOpFOrdLessThanEqual:
-    case SpvOpFUnordLessThanEqual:
-    case SpvOpFOrdGreaterThanEqual:
-    case SpvOpFUnordGreaterThanEqual:
-    case SpvOpShiftRightLogical:
-    case SpvOpShiftRightArithmetic:
-    case SpvOpShiftLeftLogical:
-    case SpvOpBitwiseOr:
-    case SpvOpBitwiseXor:
-    case SpvOpBitwiseAnd:
-    case SpvOpNot:
-    case SpvOpBitFieldInsert:
-    case SpvOpBitFieldSExtract:
-    case SpvOpBitFieldUExtract:
-    case SpvOpBitReverse:
-    case SpvOpBitCount:
-    case SpvOpCopyLogical:
-    case SpvOpPtrEqual:
-    case SpvOpPtrNotEqual:
+    case spv::Op::OpUndef:
+    case spv::Op::OpAccessChain:
+    case spv::Op::OpInBoundsAccessChain:
+    case spv::Op::OpArrayLength:
+    case spv::Op::OpVectorExtractDynamic:
+    case spv::Op::OpVectorInsertDynamic:
+    case spv::Op::OpVectorShuffle:
+    case spv::Op::OpCompositeConstruct:
+    case spv::Op::OpCompositeExtract:
+    case spv::Op::OpCompositeInsert:
+    case spv::Op::OpCopyObject:
+    case spv::Op::OpTranspose:
+    case spv::Op::OpConvertFToU:
+    case spv::Op::OpConvertFToS:
+    case spv::Op::OpConvertSToF:
+    case spv::Op::OpConvertUToF:
+    case spv::Op::OpUConvert:
+    case spv::Op::OpSConvert:
+    case spv::Op::OpFConvert:
+    case spv::Op::OpQuantizeToF16:
+    case spv::Op::OpSatConvertSToU:
+    case spv::Op::OpSatConvertUToS:
+    case spv::Op::OpBitcast:
+    case spv::Op::OpSNegate:
+    case spv::Op::OpFNegate:
+    case spv::Op::OpIAdd:
+    case spv::Op::OpFAdd:
+    case spv::Op::OpISub:
+    case spv::Op::OpFSub:
+    case spv::Op::OpIMul:
+    case spv::Op::OpFMul:
+    case spv::Op::OpUDiv:
+    case spv::Op::OpSDiv:
+    case spv::Op::OpFDiv:
+    case spv::Op::OpUMod:
+    case spv::Op::OpSRem:
+    case spv::Op::OpSMod:
+    case spv::Op::OpFRem:
+    case spv::Op::OpFMod:
+    case spv::Op::OpVectorTimesScalar:
+    case spv::Op::OpMatrixTimesScalar:
+    case spv::Op::OpVectorTimesMatrix:
+    case spv::Op::OpMatrixTimesVector:
+    case spv::Op::OpMatrixTimesMatrix:
+    case spv::Op::OpOuterProduct:
+    case spv::Op::OpDot:
+    case spv::Op::OpIAddCarry:
+    case spv::Op::OpISubBorrow:
+    case spv::Op::OpUMulExtended:
+    case spv::Op::OpSMulExtended:
+    case spv::Op::OpAny:
+    case spv::Op::OpAll:
+    case spv::Op::OpIsNan:
+    case spv::Op::OpIsInf:
+    case spv::Op::OpIsFinite:
+    case spv::Op::OpIsNormal:
+    case spv::Op::OpSignBitSet:
+    case spv::Op::OpLessOrGreater:
+    case spv::Op::OpOrdered:
+    case spv::Op::OpUnordered:
+    case spv::Op::OpLogicalEqual:
+    case spv::Op::OpLogicalNotEqual:
+    case spv::Op::OpLogicalOr:
+    case spv::Op::OpLogicalAnd:
+    case spv::Op::OpLogicalNot:
+    case spv::Op::OpSelect:
+    case spv::Op::OpIEqual:
+    case spv::Op::OpINotEqual:
+    case spv::Op::OpUGreaterThan:
+    case spv::Op::OpSGreaterThan:
+    case spv::Op::OpUGreaterThanEqual:
+    case spv::Op::OpSGreaterThanEqual:
+    case spv::Op::OpULessThan:
+    case spv::Op::OpSLessThan:
+    case spv::Op::OpULessThanEqual:
+    case spv::Op::OpSLessThanEqual:
+    case spv::Op::OpFOrdEqual:
+    case spv::Op::OpFUnordEqual:
+    case spv::Op::OpFOrdNotEqual:
+    case spv::Op::OpFUnordNotEqual:
+    case spv::Op::OpFOrdLessThan:
+    case spv::Op::OpFUnordLessThan:
+    case spv::Op::OpFOrdGreaterThan:
+    case spv::Op::OpFUnordGreaterThan:
+    case spv::Op::OpFOrdLessThanEqual:
+    case spv::Op::OpFUnordLessThanEqual:
+    case spv::Op::OpFOrdGreaterThanEqual:
+    case spv::Op::OpFUnordGreaterThanEqual:
+    case spv::Op::OpShiftRightLogical:
+    case spv::Op::OpShiftRightArithmetic:
+    case spv::Op::OpShiftLeftLogical:
+    case spv::Op::OpBitwiseOr:
+    case spv::Op::OpBitwiseXor:
+    case spv::Op::OpBitwiseAnd:
+    case spv::Op::OpNot:
+    case spv::Op::OpBitFieldInsert:
+    case spv::Op::OpBitFieldSExtract:
+    case spv::Op::OpBitFieldUExtract:
+    case spv::Op::OpBitReverse:
+    case spv::Op::OpBitCount:
+    case spv::Op::OpCopyLogical:
+    case spv::Op::OpPtrEqual:
+    case spv::Op::OpPtrNotEqual:
       return true;
     default:
       return false;
@@ -408,7 +408,7 @@
   // use |inst|.
   for (auto successor_id : successor_ids) {
     for (const auto& maybe_phi_inst : *ir_context->cfg()->block(successor_id)) {
-      if (maybe_phi_inst.opcode() != SpvOpPhi) {
+      if (maybe_phi_inst.opcode() != spv::Op::OpPhi) {
         // OpPhis can be intermixed with OpLine and OpNoLine.
         continue;
       }
@@ -446,7 +446,7 @@
         // |phi_block_id| dominates |user|'s block (or its predecessor if the
         // user is an OpPhi). We can't use fuzzerutil::IdIsAvailableAtUse since
         // the id in question hasn't yet been created in the module.
-        auto block_id_to_dominate = user->opcode() == SpvOpPhi
+        auto block_id_to_dominate = user->opcode() == spv::Op::OpPhi
                                         ? user->GetSingleWordOperand(index + 1)
                                         : user_block->id();
 
@@ -465,7 +465,7 @@
 
 opt::Instruction*
 TransformationPropagateInstructionDown::GetFirstInsertBeforeInstruction(
-    opt::IRContext* ir_context, uint32_t block_id, SpvOp opcode) {
+    opt::IRContext* ir_context, uint32_t block_id, spv::Op opcode) {
   auto* block = ir_context->cfg()->block(block_id);
 
   auto it = block->begin();
@@ -572,7 +572,7 @@
   // OpPhi instructions cannot have operands of pointer types.
   if (propagate_type->AsPointer() &&
       !ir_context->get_feature_mgr()->HasCapability(
-          SpvCapabilityVariablePointersStorageBuffer)) {
+          spv::Capability::VariablePointersStorageBuffer)) {
     return 0;
   }
 
diff --git a/source/fuzz/transformation_propagate_instruction_down.h b/source/fuzz/transformation_propagate_instruction_down.h
index 560d7dc..9133928 100644
--- a/source/fuzz/transformation_propagate_instruction_down.h
+++ b/source/fuzz/transformation_propagate_instruction_down.h
@@ -120,12 +120,12 @@
                                                      uint32_t block_id);
 
   // Returns true if |opcode| is supported by this transformation.
-  static bool IsOpcodeSupported(SpvOp opcode);
+  static bool IsOpcodeSupported(spv::Op opcode);
 
   // Returns the first instruction in the |block| that allows us to insert
   // |opcode| above itself. Returns nullptr is no such instruction exists.
   static opt::Instruction* GetFirstInsertBeforeInstruction(
-      opt::IRContext* ir_context, uint32_t block_id, SpvOp opcode);
+      opt::IRContext* ir_context, uint32_t block_id, spv::Op opcode);
 
   // Returns a result id of a basic block, where an OpPhi instruction can be
   // inserted. Returns nullptr if it's not possible to create an OpPhi. The
diff --git a/source/fuzz/transformation_propagate_instruction_up.cpp b/source/fuzz/transformation_propagate_instruction_up.cpp
index bf0e663..f9674fa 100644
--- a/source/fuzz/transformation_propagate_instruction_up.cpp
+++ b/source/fuzz/transformation_propagate_instruction_up.cpp
@@ -23,7 +23,7 @@
 
 uint32_t GetResultIdFromLabelId(const opt::Instruction& phi_inst,
                                 uint32_t label_id) {
-  assert(phi_inst.opcode() == SpvOpPhi && "|phi_inst| is not an OpPhi");
+  assert(phi_inst.opcode() == spv::Op::OpPhi && "|phi_inst| is not an OpPhi");
 
   for (uint32_t i = 1; i < phi_inst.NumInOperands(); i += 2) {
     if (phi_inst.GetSingleWordInOperand(i) == label_id) {
@@ -66,7 +66,7 @@
     assert(dependency && "Operand has invalid id");
 
     if (ir_context->get_instr_block(dependency) == inst_block &&
-        dependency->opcode() != SpvOpPhi) {
+        dependency->opcode() != spv::Op::OpPhi) {
       // |dependency| is "valid" if it's an OpPhi from the same basic block or
       // an instruction from a different basic block.
       return false;
@@ -173,7 +173,7 @@
         continue;
       }
 
-      assert(dependency_inst->opcode() == SpvOpPhi &&
+      assert(dependency_inst->opcode() == spv::Op::OpPhi &&
              "Propagated instruction can depend only on OpPhis from the same "
              "basic block or instructions from different basic blocks");
 
@@ -191,7 +191,7 @@
 
   // Insert an OpPhi instruction into the basic block of |inst|.
   ir_context->get_instr_block(inst)->begin()->InsertBefore(
-      MakeUnique<opt::Instruction>(ir_context, SpvOpPhi, inst->type_id(),
+      MakeUnique<opt::Instruction>(ir_context, spv::Op::OpPhi, inst->type_id(),
                                    inst->result_id(),
                                    std::move(op_phi_operands)));
 
@@ -210,115 +210,115 @@
   return result;
 }
 
-bool TransformationPropagateInstructionUp::IsOpcodeSupported(SpvOp opcode) {
+bool TransformationPropagateInstructionUp::IsOpcodeSupported(spv::Op opcode) {
   // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3605):
   //  We only support "simple" instructions that don't work with memory.
   //  We should extend this so that we support the ones that modify the memory
   //  too.
   switch (opcode) {
-    case SpvOpUndef:
-    case SpvOpAccessChain:
-    case SpvOpInBoundsAccessChain:
-    case SpvOpArrayLength:
-    case SpvOpVectorExtractDynamic:
-    case SpvOpVectorInsertDynamic:
-    case SpvOpVectorShuffle:
-    case SpvOpCompositeConstruct:
-    case SpvOpCompositeExtract:
-    case SpvOpCompositeInsert:
-    case SpvOpCopyObject:
-    case SpvOpTranspose:
-    case SpvOpConvertFToU:
-    case SpvOpConvertFToS:
-    case SpvOpConvertSToF:
-    case SpvOpConvertUToF:
-    case SpvOpUConvert:
-    case SpvOpSConvert:
-    case SpvOpFConvert:
-    case SpvOpQuantizeToF16:
-    case SpvOpSatConvertSToU:
-    case SpvOpSatConvertUToS:
-    case SpvOpBitcast:
-    case SpvOpSNegate:
-    case SpvOpFNegate:
-    case SpvOpIAdd:
-    case SpvOpFAdd:
-    case SpvOpISub:
-    case SpvOpFSub:
-    case SpvOpIMul:
-    case SpvOpFMul:
-    case SpvOpUDiv:
-    case SpvOpSDiv:
-    case SpvOpFDiv:
-    case SpvOpUMod:
-    case SpvOpSRem:
-    case SpvOpSMod:
-    case SpvOpFRem:
-    case SpvOpFMod:
-    case SpvOpVectorTimesScalar:
-    case SpvOpMatrixTimesScalar:
-    case SpvOpVectorTimesMatrix:
-    case SpvOpMatrixTimesVector:
-    case SpvOpMatrixTimesMatrix:
-    case SpvOpOuterProduct:
-    case SpvOpDot:
-    case SpvOpIAddCarry:
-    case SpvOpISubBorrow:
-    case SpvOpUMulExtended:
-    case SpvOpSMulExtended:
-    case SpvOpAny:
-    case SpvOpAll:
-    case SpvOpIsNan:
-    case SpvOpIsInf:
-    case SpvOpIsFinite:
-    case SpvOpIsNormal:
-    case SpvOpSignBitSet:
-    case SpvOpLessOrGreater:
-    case SpvOpOrdered:
-    case SpvOpUnordered:
-    case SpvOpLogicalEqual:
-    case SpvOpLogicalNotEqual:
-    case SpvOpLogicalOr:
-    case SpvOpLogicalAnd:
-    case SpvOpLogicalNot:
-    case SpvOpSelect:
-    case SpvOpIEqual:
-    case SpvOpINotEqual:
-    case SpvOpUGreaterThan:
-    case SpvOpSGreaterThan:
-    case SpvOpUGreaterThanEqual:
-    case SpvOpSGreaterThanEqual:
-    case SpvOpULessThan:
-    case SpvOpSLessThan:
-    case SpvOpULessThanEqual:
-    case SpvOpSLessThanEqual:
-    case SpvOpFOrdEqual:
-    case SpvOpFUnordEqual:
-    case SpvOpFOrdNotEqual:
-    case SpvOpFUnordNotEqual:
-    case SpvOpFOrdLessThan:
-    case SpvOpFUnordLessThan:
-    case SpvOpFOrdGreaterThan:
-    case SpvOpFUnordGreaterThan:
-    case SpvOpFOrdLessThanEqual:
-    case SpvOpFUnordLessThanEqual:
-    case SpvOpFOrdGreaterThanEqual:
-    case SpvOpFUnordGreaterThanEqual:
-    case SpvOpShiftRightLogical:
-    case SpvOpShiftRightArithmetic:
-    case SpvOpShiftLeftLogical:
-    case SpvOpBitwiseOr:
-    case SpvOpBitwiseXor:
-    case SpvOpBitwiseAnd:
-    case SpvOpNot:
-    case SpvOpBitFieldInsert:
-    case SpvOpBitFieldSExtract:
-    case SpvOpBitFieldUExtract:
-    case SpvOpBitReverse:
-    case SpvOpBitCount:
-    case SpvOpCopyLogical:
-    case SpvOpPtrEqual:
-    case SpvOpPtrNotEqual:
+    case spv::Op::OpUndef:
+    case spv::Op::OpAccessChain:
+    case spv::Op::OpInBoundsAccessChain:
+    case spv::Op::OpArrayLength:
+    case spv::Op::OpVectorExtractDynamic:
+    case spv::Op::OpVectorInsertDynamic:
+    case spv::Op::OpVectorShuffle:
+    case spv::Op::OpCompositeConstruct:
+    case spv::Op::OpCompositeExtract:
+    case spv::Op::OpCompositeInsert:
+    case spv::Op::OpCopyObject:
+    case spv::Op::OpTranspose:
+    case spv::Op::OpConvertFToU:
+    case spv::Op::OpConvertFToS:
+    case spv::Op::OpConvertSToF:
+    case spv::Op::OpConvertUToF:
+    case spv::Op::OpUConvert:
+    case spv::Op::OpSConvert:
+    case spv::Op::OpFConvert:
+    case spv::Op::OpQuantizeToF16:
+    case spv::Op::OpSatConvertSToU:
+    case spv::Op::OpSatConvertUToS:
+    case spv::Op::OpBitcast:
+    case spv::Op::OpSNegate:
+    case spv::Op::OpFNegate:
+    case spv::Op::OpIAdd:
+    case spv::Op::OpFAdd:
+    case spv::Op::OpISub:
+    case spv::Op::OpFSub:
+    case spv::Op::OpIMul:
+    case spv::Op::OpFMul:
+    case spv::Op::OpUDiv:
+    case spv::Op::OpSDiv:
+    case spv::Op::OpFDiv:
+    case spv::Op::OpUMod:
+    case spv::Op::OpSRem:
+    case spv::Op::OpSMod:
+    case spv::Op::OpFRem:
+    case spv::Op::OpFMod:
+    case spv::Op::OpVectorTimesScalar:
+    case spv::Op::OpMatrixTimesScalar:
+    case spv::Op::OpVectorTimesMatrix:
+    case spv::Op::OpMatrixTimesVector:
+    case spv::Op::OpMatrixTimesMatrix:
+    case spv::Op::OpOuterProduct:
+    case spv::Op::OpDot:
+    case spv::Op::OpIAddCarry:
+    case spv::Op::OpISubBorrow:
+    case spv::Op::OpUMulExtended:
+    case spv::Op::OpSMulExtended:
+    case spv::Op::OpAny:
+    case spv::Op::OpAll:
+    case spv::Op::OpIsNan:
+    case spv::Op::OpIsInf:
+    case spv::Op::OpIsFinite:
+    case spv::Op::OpIsNormal:
+    case spv::Op::OpSignBitSet:
+    case spv::Op::OpLessOrGreater:
+    case spv::Op::OpOrdered:
+    case spv::Op::OpUnordered:
+    case spv::Op::OpLogicalEqual:
+    case spv::Op::OpLogicalNotEqual:
+    case spv::Op::OpLogicalOr:
+    case spv::Op::OpLogicalAnd:
+    case spv::Op::OpLogicalNot:
+    case spv::Op::OpSelect:
+    case spv::Op::OpIEqual:
+    case spv::Op::OpINotEqual:
+    case spv::Op::OpUGreaterThan:
+    case spv::Op::OpSGreaterThan:
+    case spv::Op::OpUGreaterThanEqual:
+    case spv::Op::OpSGreaterThanEqual:
+    case spv::Op::OpULessThan:
+    case spv::Op::OpSLessThan:
+    case spv::Op::OpULessThanEqual:
+    case spv::Op::OpSLessThanEqual:
+    case spv::Op::OpFOrdEqual:
+    case spv::Op::OpFUnordEqual:
+    case spv::Op::OpFOrdNotEqual:
+    case spv::Op::OpFUnordNotEqual:
+    case spv::Op::OpFOrdLessThan:
+    case spv::Op::OpFUnordLessThan:
+    case spv::Op::OpFOrdGreaterThan:
+    case spv::Op::OpFUnordGreaterThan:
+    case spv::Op::OpFOrdLessThanEqual:
+    case spv::Op::OpFUnordLessThanEqual:
+    case spv::Op::OpFOrdGreaterThanEqual:
+    case spv::Op::OpFUnordGreaterThanEqual:
+    case spv::Op::OpShiftRightLogical:
+    case spv::Op::OpShiftRightArithmetic:
+    case spv::Op::OpShiftLeftLogical:
+    case spv::Op::OpBitwiseOr:
+    case spv::Op::OpBitwiseXor:
+    case spv::Op::OpBitwiseAnd:
+    case spv::Op::OpNot:
+    case spv::Op::OpBitFieldInsert:
+    case spv::Op::OpBitFieldSExtract:
+    case spv::Op::OpBitFieldUExtract:
+    case spv::Op::OpBitReverse:
+    case spv::Op::OpBitCount:
+    case spv::Op::OpCopyLogical:
+    case spv::Op::OpPtrEqual:
+    case spv::Op::OpPtrNotEqual:
       return true;
     default:
       return false;
@@ -338,7 +338,7 @@
     // - it must be supported by this transformation
     // - it may depend only on instructions from different basic blocks or on
     //   OpPhi instructions from the same basic block.
-    if (inst.opcode() == SpvOpPhi || !IsOpcodeSupported(inst.opcode()) ||
+    if (inst.opcode() == spv::Op::OpPhi || !IsOpcodeSupported(inst.opcode()) ||
         !inst.type_id() || !inst.result_id()) {
       continue;
     }
@@ -353,7 +353,7 @@
     }
 
     if (!ir_context->get_feature_mgr()->HasCapability(
-            SpvCapabilityVariablePointersStorageBuffer) &&
+            spv::Capability::VariablePointersStorageBuffer) &&
         ContainsPointers(*inst_type)) {
       // OpPhi supports pointer operands only with VariablePointers or
       // VariablePointersStorageBuffer capabilities.
@@ -377,7 +377,7 @@
     opt::IRContext* ir_context, uint32_t block_id) {
   // Check that |block_id| is valid.
   const auto* label_inst = ir_context->get_def_use_mgr()->GetDef(block_id);
-  if (!label_inst || label_inst->opcode() != SpvOpLabel) {
+  if (!label_inst || label_inst->opcode() != spv::Op::OpLabel) {
     return false;
   }
 
diff --git a/source/fuzz/transformation_propagate_instruction_up.h b/source/fuzz/transformation_propagate_instruction_up.h
index 0ca051b..93aa365 100644
--- a/source/fuzz/transformation_propagate_instruction_up.h
+++ b/source/fuzz/transformation_propagate_instruction_up.h
@@ -80,7 +80,7 @@
                                                      uint32_t block_id);
 
   // Returns true if |opcode| is supported by this transformation.
-  static bool IsOpcodeSupported(SpvOp opcode);
+  static bool IsOpcodeSupported(spv::Op opcode);
 
   protobufs::TransformationPropagateInstructionUp message_;
 };
diff --git a/source/fuzz/transformation_push_id_through_variable.cpp b/source/fuzz/transformation_push_id_through_variable.cpp
index 55a57a1..2372d70 100644
--- a/source/fuzz/transformation_push_id_through_variable.cpp
+++ b/source/fuzz/transformation_push_id_through_variable.cpp
@@ -53,9 +53,9 @@
 
   // It must be valid to insert the OpStore and OpLoad instruction before it.
   if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
-          SpvOpStore, instruction_to_insert_before) ||
+          spv::Op::OpStore, instruction_to_insert_before) ||
       !fuzzerutil::CanInsertOpcodeBeforeInstruction(
-          SpvOpLoad, instruction_to_insert_before)) {
+          spv::Op::OpLoad, instruction_to_insert_before)) {
     return false;
   }
 
@@ -75,14 +75,16 @@
   // A pointer type instruction pointing to the value type must be defined.
   auto pointer_type_id = fuzzerutil::MaybeGetPointerType(
       ir_context, value_instruction->type_id(),
-      static_cast<SpvStorageClass>(message_.variable_storage_class()));
+      static_cast<spv::StorageClass>(message_.variable_storage_class()));
   if (!pointer_type_id) {
     return false;
   }
 
   // |message_.variable_storage_class| must be private or function.
-  assert((message_.variable_storage_class() == SpvStorageClassPrivate ||
-          message_.variable_storage_class() == SpvStorageClassFunction) &&
+  assert((message_.variable_storage_class() ==
+              (uint32_t)spv::StorageClass::Private ||
+          message_.variable_storage_class() ==
+              (uint32_t)spv::StorageClass::Function) &&
          "The variable storage class must be private or function.");
 
   // Check that initializer is valid.
@@ -111,14 +113,15 @@
   // A pointer type instruction pointing to the value type must be defined.
   auto pointer_type_id = fuzzerutil::MaybeGetPointerType(
       ir_context, value_instruction->type_id(),
-      static_cast<SpvStorageClass>(message_.variable_storage_class()));
+      static_cast<spv::StorageClass>(message_.variable_storage_class()));
   assert(pointer_type_id && "The required pointer type must be available.");
 
   // Adds whether a global or local variable.
-  if (message_.variable_storage_class() == SpvStorageClassPrivate) {
+  if (spv::StorageClass(message_.variable_storage_class()) ==
+      spv::StorageClass::Private) {
     opt::Instruction* global_variable = fuzzerutil::AddGlobalVariable(
         ir_context, message_.variable_id(), pointer_type_id,
-        SpvStorageClassPrivate, message_.initializer_id());
+        spv::StorageClass::Private, message_.initializer_id());
     ir_context->get_def_use_mgr()->AnalyzeInstDefUse(global_variable);
   } else {
     opt::Function* function =
@@ -138,13 +141,13 @@
   fuzzerutil::UpdateModuleIdBound(ir_context, message_.value_synonym_id());
   opt::Instruction* load_instruction =
       insert_before->InsertBefore(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpLoad, value_instruction->type_id(),
+          ir_context, spv::Op::OpLoad, value_instruction->type_id(),
           message_.value_synonym_id(),
           opt::Instruction::OperandList(
               {{SPV_OPERAND_TYPE_ID, {message_.variable_id()}}})));
   opt::Instruction* store_instruction =
       load_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpStore, 0, 0,
+          ir_context, spv::Op::OpStore, 0, 0,
           opt::Instruction::OperandList(
               {{SPV_OPERAND_TYPE_ID, {message_.variable_id()}},
                {SPV_OPERAND_TYPE_ID, {message_.value_id()}}})));
diff --git a/source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.cpp b/source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.cpp
index e1977a6..03e9737 100644
--- a/source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.cpp
+++ b/source/fuzz/transformation_replace_add_sub_mul_with_carrying_extended.cpp
@@ -97,20 +97,20 @@
 
   // Determine the opcode of the new instruction that computes the result into a
   // struct.
-  SpvOp new_instruction_opcode;
+  spv::Op new_instruction_opcode;
 
   switch (original_instruction->opcode()) {
-    case SpvOpIAdd:
-      new_instruction_opcode = SpvOpIAddCarry;
+    case spv::Op::OpIAdd:
+      new_instruction_opcode = spv::Op::OpIAddCarry;
       break;
-    case SpvOpISub:
-      new_instruction_opcode = SpvOpISubBorrow;
+    case spv::Op::OpISub:
+      new_instruction_opcode = spv::Op::OpISubBorrow;
       break;
-    case SpvOpIMul:
+    case spv::Op::OpIMul:
       if (!operand_is_signed) {
-        new_instruction_opcode = SpvOpUMulExtended;
+        new_instruction_opcode = spv::Op::OpUMulExtended;
       } else {
-        new_instruction_opcode = SpvOpSMulExtended;
+        new_instruction_opcode = spv::Op::OpSMulExtended;
       }
       break;
     default:
@@ -148,7 +148,7 @@
   // takes the first component of the struct which represents low-order bits of
   // the operation. This is the original result.
   original_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpCompositeExtract, original_instruction->type_id(),
+      ir_context, spv::Op::OpCompositeExtract, original_instruction->type_id(),
       message_.result_id(),
       opt::Instruction::OperandList(
           {{SPV_OPERAND_TYPE_ID, {message_.struct_fresh_id()}},
@@ -168,9 +168,9 @@
 
   // Only instructions OpIAdd, OpISub, OpIMul are supported.
   switch (instruction_opcode) {
-    case SpvOpIAdd:
-    case SpvOpISub:
-    case SpvOpIMul:
+    case spv::Op::OpIAdd:
+    case spv::Op::OpISub:
+    case spv::Op::OpIMul:
       break;
     default:
       return false;
@@ -201,8 +201,8 @@
   auto type = ir_context->get_type_mgr()->GetType(instruction.type_id());
 
   switch (instruction_opcode) {
-    case SpvOpIAdd:
-    case SpvOpISub: {
+    case spv::Op::OpIAdd:
+    case spv::Op::OpISub: {
       // In case of OpIAdd and OpISub if the operand is a vector, the component
       // type must be unsigned. Otherwise (if the operand is an int), the
       // operand must be unsigned.
diff --git a/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.cpp b/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.cpp
index 2429351..efd1555 100644
--- a/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.cpp
+++ b/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.cpp
@@ -28,7 +28,8 @@
 // operator |binop|, returns true if it is certain that 'lhs binop rhs'
 // evaluates to |required_value|.
 template <typename T>
-bool float_binop_evaluates_to(T lhs, T rhs, SpvOp binop, bool required_value) {
+bool float_binop_evaluates_to(T lhs, T rhs, spv::Op binop,
+                              bool required_value) {
   // Infinity and NaN values are conservatively treated as out of scope.
   if (!std::isfinite(lhs) || !std::isfinite(rhs)) {
     return false;
@@ -37,20 +38,20 @@
   // The following captures the binary operators that spirv-fuzz can actually
   // generate when turning a boolean constant into a binary expression.
   switch (binop) {
-    case SpvOpFOrdGreaterThanEqual:
-    case SpvOpFUnordGreaterThanEqual:
+    case spv::Op::OpFOrdGreaterThanEqual:
+    case spv::Op::OpFUnordGreaterThanEqual:
       binop_result = (lhs >= rhs);
       break;
-    case SpvOpFOrdGreaterThan:
-    case SpvOpFUnordGreaterThan:
+    case spv::Op::OpFOrdGreaterThan:
+    case spv::Op::OpFUnordGreaterThan:
       binop_result = (lhs > rhs);
       break;
-    case SpvOpFOrdLessThanEqual:
-    case SpvOpFUnordLessThanEqual:
+    case spv::Op::OpFOrdLessThanEqual:
+    case spv::Op::OpFUnordLessThanEqual:
       binop_result = (lhs <= rhs);
       break;
-    case SpvOpFOrdLessThan:
-    case SpvOpFUnordLessThan:
+    case spv::Op::OpFOrdLessThan:
+    case spv::Op::OpFUnordLessThan:
       binop_result = (lhs < rhs);
       break;
     default:
@@ -61,20 +62,20 @@
 
 // Analogous to 'float_binop_evaluates_to', but for signed int values.
 template <typename T>
-bool signed_int_binop_evaluates_to(T lhs, T rhs, SpvOp binop,
+bool signed_int_binop_evaluates_to(T lhs, T rhs, spv::Op binop,
                                    bool required_value) {
   bool binop_result;
   switch (binop) {
-    case SpvOpSGreaterThanEqual:
+    case spv::Op::OpSGreaterThanEqual:
       binop_result = (lhs >= rhs);
       break;
-    case SpvOpSGreaterThan:
+    case spv::Op::OpSGreaterThan:
       binop_result = (lhs > rhs);
       break;
-    case SpvOpSLessThanEqual:
+    case spv::Op::OpSLessThanEqual:
       binop_result = (lhs <= rhs);
       break;
-    case SpvOpSLessThan:
+    case spv::Op::OpSLessThan:
       binop_result = (lhs < rhs);
       break;
     default:
@@ -85,20 +86,20 @@
 
 // Analogous to 'float_binop_evaluates_to', but for unsigned int values.
 template <typename T>
-bool unsigned_int_binop_evaluates_to(T lhs, T rhs, SpvOp binop,
+bool unsigned_int_binop_evaluates_to(T lhs, T rhs, spv::Op binop,
                                      bool required_value) {
   bool binop_result;
   switch (binop) {
-    case SpvOpUGreaterThanEqual:
+    case spv::Op::OpUGreaterThanEqual:
       binop_result = (lhs >= rhs);
       break;
-    case SpvOpUGreaterThan:
+    case spv::Op::OpUGreaterThan:
       binop_result = (lhs > rhs);
       break;
-    case SpvOpULessThanEqual:
+    case spv::Op::OpULessThanEqual:
       binop_result = (lhs <= rhs);
       break;
-    case SpvOpULessThan:
+    case spv::Op::OpULessThan:
       binop_result = (lhs < rhs);
       break;
     default:
@@ -118,12 +119,12 @@
 TransformationReplaceBooleanConstantWithConstantBinary::
     TransformationReplaceBooleanConstantWithConstantBinary(
         const protobufs::IdUseDescriptor& id_use_descriptor, uint32_t lhs_id,
-        uint32_t rhs_id, SpvOp comparison_opcode,
+        uint32_t rhs_id, spv::Op comparison_opcode,
         uint32_t fresh_id_for_binary_operation) {
   *message_.mutable_id_use_descriptor() = id_use_descriptor;
   message_.set_lhs_id(lhs_id);
   message_.set_rhs_id(rhs_id);
-  message_.set_opcode(comparison_opcode);
+  message_.set_opcode(uint32_t(comparison_opcode));
   message_.set_fresh_id_for_binary_operation(fresh_id_for_binary_operation);
 }
 
@@ -141,8 +142,8 @@
   if (!boolean_constant) {
     return false;
   }
-  if (!(boolean_constant->opcode() == SpvOpConstantFalse ||
-        boolean_constant->opcode() == SpvOpConstantTrue)) {
+  if (!(boolean_constant->opcode() == spv::Op::OpConstantFalse ||
+        boolean_constant->opcode() == spv::Op::OpConstantTrue)) {
     return false;
   }
 
@@ -152,7 +153,7 @@
   if (!lhs_constant_inst) {
     return false;
   }
-  if (lhs_constant_inst->opcode() != SpvOpConstant) {
+  if (lhs_constant_inst->opcode() != spv::Op::OpConstant) {
     return false;
   }
 
@@ -162,7 +163,7 @@
   if (!rhs_constant_inst) {
     return false;
   }
-  if (rhs_constant_inst->opcode() != SpvOpConstant) {
+  if (rhs_constant_inst->opcode() != spv::Op::OpConstant) {
     return false;
   }
 
@@ -176,9 +177,10 @@
       ir_context->get_constant_mgr()->FindDeclaredConstant(message_.lhs_id());
   auto rhs_constant =
       ir_context->get_constant_mgr()->FindDeclaredConstant(message_.rhs_id());
-  bool expected_result = (boolean_constant->opcode() == SpvOpConstantTrue);
+  bool expected_result =
+      (boolean_constant->opcode() == spv::Op::OpConstantTrue);
 
-  const auto binary_opcode = static_cast<SpvOp>(message_.opcode());
+  const auto binary_opcode = static_cast<spv::Op>(message_.opcode());
 
   // We consider the floating point, signed and unsigned integer cases
   // separately.  In each case the logic is very similar.
@@ -247,7 +249,7 @@
   // a binary operator before an OpVariable, but in any case (b) the
   // constant we would be replacing is the initializer constant of the
   // OpVariable, and this cannot be the result of a binary operation.
-  if (instruction->opcode() == SpvOpVariable) {
+  if (instruction->opcode() == spv::Op::OpVariable) {
     return false;
   }
 
@@ -268,7 +270,7 @@
       {SPV_OPERAND_TYPE_ID, {message_.lhs_id()}},
       {SPV_OPERAND_TYPE_ID, {message_.rhs_id()}}};
   auto binary_instruction = MakeUnique<opt::Instruction>(
-      ir_context, static_cast<SpvOp>(message_.opcode()),
+      ir_context, static_cast<spv::Op>(message_.opcode()),
       ir_context->get_type_mgr()->GetId(&bool_type),
       message_.fresh_id_for_binary_operation(), operands);
   opt::Instruction* result = binary_instruction.get();
@@ -279,7 +281,7 @@
   // If |instruction_before_which_to_insert| is an OpPhi instruction,
   // then |binary_instruction| will be inserted into the parent block associated
   // with the OpPhi variable operand.
-  if (instruction_containing_constant_use->opcode() == SpvOpPhi) {
+  if (instruction_containing_constant_use->opcode() == spv::Op::OpPhi) {
     instruction_before_which_to_insert =
         ir_context->cfg()
             ->block(instruction_containing_constant_use->GetSingleWordInOperand(
@@ -293,8 +295,9 @@
   {
     opt::Instruction* previous_node =
         instruction_before_which_to_insert->PreviousNode();
-    if (previous_node && (previous_node->opcode() == SpvOpLoopMerge ||
-                          previous_node->opcode() == SpvOpSelectionMerge)) {
+    if (previous_node &&
+        (previous_node->opcode() == spv::Op::OpLoopMerge ||
+         previous_node->opcode() == spv::Op::OpSelectionMerge)) {
       instruction_before_which_to_insert = previous_node;
     }
   }
diff --git a/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h b/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h
index 97c66bf..4d48bf2 100644
--- a/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h
+++ b/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h
@@ -32,7 +32,7 @@
 
   TransformationReplaceBooleanConstantWithConstantBinary(
       const protobufs::IdUseDescriptor& id_use_descriptor, uint32_t lhs_id,
-      uint32_t rhs_id, SpvOp comparison_opcode,
+      uint32_t rhs_id, spv::Op comparison_opcode,
       uint32_t fresh_id_for_binary_operation);
 
   // - |message_.fresh_id_for_binary_operation| must not already be used by the
diff --git a/source/fuzz/transformation_replace_branch_from_dead_block_with_exit.cpp b/source/fuzz/transformation_replace_branch_from_dead_block_with_exit.cpp
index 9ea7cb6..4150bb1 100644
--- a/source/fuzz/transformation_replace_branch_from_dead_block_with_exit.cpp
+++ b/source/fuzz/transformation_replace_branch_from_dead_block_with_exit.cpp
@@ -26,10 +26,10 @@
 
 TransformationReplaceBranchFromDeadBlockWithExit::
     TransformationReplaceBranchFromDeadBlockWithExit(uint32_t block_id,
-                                                     SpvOp opcode,
+                                                     spv::Op opcode,
                                                      uint32_t return_value_id) {
   message_.set_block_id(block_id);
-  message_.set_opcode(opcode);
+  message_.set_opcode(uint32_t(opcode));
   message_.set_return_value_id(return_value_id);
 }
 
@@ -45,11 +45,11 @@
     return false;
   }
   auto function_return_type_id = block->GetParent()->type_id();
-  switch (message_.opcode()) {
-    case SpvOpKill:
+  switch (spv::Op(message_.opcode())) {
+    case spv::Op::OpKill:
       for (auto& entry_point : ir_context->module()->entry_points()) {
-        if (entry_point.GetSingleWordInOperand(0) !=
-            SpvExecutionModelFragment) {
+        if (spv::ExecutionModel(entry_point.GetSingleWordInOperand(0)) !=
+            spv::ExecutionModel::Fragment) {
           // OpKill is only allowed in a fragment shader.  This is a
           // conservative check: if the module contains a non-fragment entry
           // point then adding an OpKill might lead to OpKill being used in a
@@ -58,15 +58,15 @@
         }
       }
       break;
-    case SpvOpReturn:
+    case spv::Op::OpReturn:
       if (ir_context->get_def_use_mgr()
               ->GetDef(function_return_type_id)
-              ->opcode() != SpvOpTypeVoid) {
+              ->opcode() != spv::Op::OpTypeVoid) {
         // OpReturn is only allowed in a function with void return type.
         return false;
       }
       break;
-    case SpvOpReturnValue: {
+    case spv::Op::OpReturnValue: {
       // If the terminator is to be changed to OpReturnValue, with
       // |message_.return_value_id| being the value that will be returned, then
       // |message_.return_value_id| must have a compatible type and be available
@@ -83,7 +83,7 @@
       break;
     }
     default:
-      assert(message_.opcode() == SpvOpUnreachable &&
+      assert(spv::Op(message_.opcode()) == spv::Op::OpUnreachable &&
              "Invalid early exit opcode.");
       break;
   }
@@ -95,7 +95,7 @@
   // If the successor block has OpPhi instructions then arguments related to
   // |message_.block_id| need to be removed from these instruction.
   auto block = ir_context->get_instr_block(message_.block_id());
-  assert(block->terminator()->opcode() == SpvOpBranch &&
+  assert(block->terminator()->opcode() == spv::Op::OpBranch &&
          "Precondition: the block must end with OpBranch.");
   auto successor = ir_context->get_instr_block(
       block->terminator()->GetSingleWordInOperand(0));
@@ -114,12 +114,12 @@
 
   // Rewrite the terminator of |message_.block_id|.
   opt::Instruction::OperandList new_terminator_in_operands;
-  if (message_.opcode() == SpvOpReturnValue) {
+  if (spv::Op(message_.opcode()) == spv::Op::OpReturnValue) {
     new_terminator_in_operands.push_back(
         {SPV_OPERAND_TYPE_ID, {message_.return_value_id()}});
   }
   auto terminator = block->terminator();
-  terminator->SetOpcode(static_cast<SpvOp>(message_.opcode()));
+  terminator->SetOpcode(static_cast<spv::Op>(message_.opcode()));
   terminator->SetInOperands(std::move(new_terminator_in_operands));
   ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
 }
@@ -145,7 +145,7 @@
     return false;
   }
   // The block's terminator must be OpBranch.
-  if (block.terminator()->opcode() != SpvOpBranch) {
+  if (block.terminator()->opcode() != spv::Op::OpBranch) {
     return false;
   }
   if (ir_context->GetStructuredCFGAnalysis()->IsInContinueConstruct(
@@ -164,7 +164,7 @@
   // Make sure that domination rules are satisfied when we remove the branch
   // from the |block| to its |successor|.
   return fuzzerutil::NewTerminatorPreservesDominationRules(
-      ir_context, block.id(), {ir_context, SpvOpUnreachable});
+      ir_context, block.id(), {ir_context, spv::Op::OpUnreachable});
 }
 
 }  // namespace fuzz
diff --git a/source/fuzz/transformation_replace_branch_from_dead_block_with_exit.h b/source/fuzz/transformation_replace_branch_from_dead_block_with_exit.h
index 89667fc..9a5d42e 100644
--- a/source/fuzz/transformation_replace_branch_from_dead_block_with_exit.h
+++ b/source/fuzz/transformation_replace_branch_from_dead_block_with_exit.h
@@ -30,7 +30,7 @@
       protobufs::TransformationReplaceBranchFromDeadBlockWithExit message);
 
   TransformationReplaceBranchFromDeadBlockWithExit(uint32_t block_id,
-                                                   SpvOp opcode,
+                                                   spv::Op opcode,
                                                    uint32_t return_value_id);
 
   // - |message_.block_id| must be the id of a dead block that is not part of
diff --git a/source/fuzz/transformation_replace_constant_with_uniform.cpp b/source/fuzz/transformation_replace_constant_with_uniform.cpp
index c6698c0..7174e6a 100644
--- a/source/fuzz/transformation_replace_constant_with_uniform.cpp
+++ b/source/fuzz/transformation_replace_constant_with_uniform.cpp
@@ -67,15 +67,15 @@
   // The type id for the access chain is a uniform pointer with base type
   // matching the given constant id type.
   auto type_and_pointer_type =
-      ir_context->get_type_mgr()->GetTypeAndPointerType(constant_type_id,
-                                                        SpvStorageClassUniform);
+      ir_context->get_type_mgr()->GetTypeAndPointerType(
+          constant_type_id, spv::StorageClass::Uniform);
   assert(type_and_pointer_type.first != nullptr);
   assert(type_and_pointer_type.second != nullptr);
   auto pointer_to_uniform_constant_type_id =
       ir_context->get_type_mgr()->GetId(type_and_pointer_type.second.get());
 
   return MakeUnique<opt::Instruction>(
-      ir_context, SpvOpAccessChain, pointer_to_uniform_constant_type_id,
+      ir_context, spv::Op::OpAccessChain, pointer_to_uniform_constant_type_id,
       message_.fresh_id_for_access_chain(), operands_for_access_chain);
 }
 
@@ -84,9 +84,9 @@
     spvtools::opt::IRContext* ir_context, uint32_t constant_type_id) const {
   opt::Instruction::OperandList operands_for_load = {
       {SPV_OPERAND_TYPE_ID, {message_.fresh_id_for_access_chain()}}};
-  return MakeUnique<opt::Instruction>(ir_context, SpvOpLoad, constant_type_id,
-                                      message_.fresh_id_for_load(),
-                                      operands_for_load);
+  return MakeUnique<opt::Instruction>(
+      ir_context, spv::Op::OpLoad, constant_type_id,
+      message_.fresh_id_for_load(), operands_for_load);
 }
 
 opt::Instruction*
@@ -99,7 +99,7 @@
   }
 
   // The use might be in an OpPhi instruction.
-  if (result->opcode() == SpvOpPhi) {
+  if (result->opcode() == spv::Op::OpPhi) {
     // OpPhi instructions must be the first instructions in a block. Thus, we
     // can't insert above the OpPhi instruction. Given the predecessor block
     // that corresponds to the id use, get the last instruction in that block
@@ -108,18 +108,19 @@
         ir_context,
         result->GetSingleWordInOperand(
             message_.id_use_descriptor().in_operand_index() + 1),
-        SpvOpLoad);
+        spv::Op::OpLoad);
   }
 
   // The only operand that we could've replaced in the OpBranchConditional is
   // the condition id. But that operand has a boolean type and uniform variables
   // can't store booleans (see the spec on OpTypeBool). Thus, |result| can't be
   // an OpBranchConditional.
-  assert(result->opcode() != SpvOpBranchConditional &&
+  assert(result->opcode() != spv::Op::OpBranchConditional &&
          "OpBranchConditional has no operands to replace");
 
-  assert(fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLoad, result) &&
-         "We should be able to insert OpLoad and OpAccessChain at this point");
+  assert(
+      fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpLoad, result) &&
+      "We should be able to insert OpLoad and OpAccessChain at this point");
   return result;
 }
 
@@ -191,15 +192,15 @@
 
   // The use must not be a variable initializer; these are required to be
   // constants, so it would be illegal to replace one with a uniform access.
-  if (instruction_using_constant->opcode() == SpvOpVariable) {
+  if (instruction_using_constant->opcode() == spv::Op::OpVariable) {
     return false;
   }
 
   // The module needs to have a uniform pointer type suitable for indexing into
   // the uniform variable, i.e. matching the type of the constant we wish to
   // replace with a uniform.
-  opt::analysis::Pointer pointer_to_type_of_constant(declared_constant->type(),
-                                                     SpvStorageClassUniform);
+  opt::analysis::Pointer pointer_to_type_of_constant(
+      declared_constant->type(), spv::StorageClass::Uniform);
   if (!ir_context->get_type_mgr()->GetId(&pointer_to_type_of_constant)) {
     return false;
   }
diff --git a/source/fuzz/transformation_replace_copy_memory_with_load_store.cpp b/source/fuzz/transformation_replace_copy_memory_with_load_store.cpp
index de9d1fd..8f14145 100644
--- a/source/fuzz/transformation_replace_copy_memory_with_load_store.cpp
+++ b/source/fuzz/transformation_replace_copy_memory_with_load_store.cpp
@@ -45,7 +45,7 @@
   auto copy_memory_instruction = FindInstruction(
       message_.copy_memory_instruction_descriptor(), ir_context);
   if (!copy_memory_instruction ||
-      copy_memory_instruction->opcode() != SpvOpCopyMemory) {
+      copy_memory_instruction->opcode() != spv::Op::OpCopyMemory) {
     return false;
   }
   return true;
@@ -57,7 +57,7 @@
       message_.copy_memory_instruction_descriptor(), ir_context);
   // |copy_memory_instruction| must be defined.
   assert(copy_memory_instruction &&
-         copy_memory_instruction->opcode() == SpvOpCopyMemory &&
+         copy_memory_instruction->opcode() == spv::Op::OpCopyMemory &&
          "The required OpCopyMemory instruction must be defined.");
 
   // Integrity check: Both operands must be pointers.
@@ -78,8 +78,8 @@
   (void)target_type_opcode;
   (void)source_type_opcode;
 
-  assert(target_type_opcode == SpvOpTypePointer &&
-         source_type_opcode == SpvOpTypePointer &&
+  assert(target_type_opcode == spv::Op::OpTypePointer &&
+         source_type_opcode == spv::Op::OpTypePointer &&
          "Operands must be of type OpTypePointer");
 
   // Integrity check: |source| and |target| must point to the same type.
@@ -100,12 +100,12 @@
   fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
   FindInstruction(message_.copy_memory_instruction_descriptor(), ir_context)
       ->InsertBefore(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpStore, 0, 0,
+          ir_context, spv::Op::OpStore, 0, 0,
           opt::Instruction::OperandList(
               {{SPV_OPERAND_TYPE_ID, {target->result_id()}},
                {SPV_OPERAND_TYPE_ID, {message_.fresh_id()}}})))
       ->InsertBefore(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpLoad, target_pointee_type, message_.fresh_id(),
+          ir_context, spv::Op::OpLoad, target_pointee_type, message_.fresh_id(),
           opt::Instruction::OperandList(
               {{SPV_OPERAND_TYPE_ID, {source->result_id()}}})));
 
diff --git a/source/fuzz/transformation_replace_copy_object_with_store_load.cpp b/source/fuzz/transformation_replace_copy_object_with_store_load.cpp
index e0643bf..f08a734 100644
--- a/source/fuzz/transformation_replace_copy_object_with_store_load.cpp
+++ b/source/fuzz/transformation_replace_copy_object_with_store_load.cpp
@@ -46,7 +46,7 @@
 
   // This must be a defined OpCopyObject instruction.
   if (!copy_object_instruction ||
-      copy_object_instruction->opcode() != SpvOpCopyObject) {
+      copy_object_instruction->opcode() != spv::Op::OpCopyObject) {
     return false;
   }
 
@@ -54,14 +54,14 @@
   // because we cannot define a pointer to pointer.
   if (ir_context->get_def_use_mgr()
           ->GetDef(copy_object_instruction->type_id())
-          ->opcode() == SpvOpTypePointer) {
+          ->opcode() == spv::Op::OpTypePointer) {
     return false;
   }
 
   // A pointer type instruction pointing to the value type must be defined.
   auto pointer_type_id = fuzzerutil::MaybeGetPointerType(
       ir_context, copy_object_instruction->type_id(),
-      static_cast<SpvStorageClass>(message_.variable_storage_class()));
+      static_cast<spv::StorageClass>(message_.variable_storage_class()));
   if (!pointer_type_id) {
     return false;
   }
@@ -74,8 +74,10 @@
     return false;
   }
   // |message_.variable_storage_class| must be Private or Function.
-  return message_.variable_storage_class() == SpvStorageClassPrivate ||
-         message_.variable_storage_class() == SpvStorageClassFunction;
+  return spv::StorageClass(message_.variable_storage_class()) ==
+             spv::StorageClass::Private ||
+         spv::StorageClass(message_.variable_storage_class()) ==
+             spv::StorageClass::Function;
 }
 
 void TransformationReplaceCopyObjectWithStoreLoad::Apply(
@@ -85,7 +87,7 @@
       ir_context->get_def_use_mgr()->GetDef(message_.copy_object_result_id());
   // |copy_object_instruction| must be defined.
   assert(copy_object_instruction &&
-         copy_object_instruction->opcode() == SpvOpCopyObject &&
+         copy_object_instruction->opcode() == spv::Op::OpCopyObject &&
          "The required OpCopyObject instruction must be defined.");
 
   opt::BasicBlock* enclosing_block =
@@ -96,14 +98,15 @@
   // A pointer type instruction pointing to the value type must be defined.
   auto pointer_type_id = fuzzerutil::MaybeGetPointerType(
       ir_context, copy_object_instruction->type_id(),
-      static_cast<SpvStorageClass>(message_.variable_storage_class()));
+      static_cast<spv::StorageClass>(message_.variable_storage_class()));
   assert(pointer_type_id && "The required pointer type must be available.");
 
   // Adds a global or local variable (according to the storage class).
-  if (message_.variable_storage_class() == SpvStorageClassPrivate) {
+  if (spv::StorageClass(message_.variable_storage_class()) ==
+      spv::StorageClass::Private) {
     opt::Instruction* new_global = fuzzerutil::AddGlobalVariable(
         ir_context, message_.fresh_variable_id(), pointer_type_id,
-        SpvStorageClassPrivate, message_.variable_initializer_id());
+        spv::StorageClass::Private, message_.variable_initializer_id());
     ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_global);
   } else {
     opt::Function* function =
@@ -120,13 +123,13 @@
   fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_variable_id());
   opt::Instruction* load_instruction =
       copy_object_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpLoad, copy_object_instruction->type_id(),
+          ir_context, spv::Op::OpLoad, copy_object_instruction->type_id(),
           message_.copy_object_result_id(),
           opt::Instruction::OperandList(
               {{SPV_OPERAND_TYPE_ID, {message_.fresh_variable_id()}}})));
   opt::Instruction* store_instruction =
       load_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpStore, 0, 0,
+          ir_context, spv::Op::OpStore, 0, 0,
           opt::Instruction::OperandList(
               {{SPV_OPERAND_TYPE_ID, {message_.fresh_variable_id()}},
                {SPV_OPERAND_TYPE_ID, {src_operand}}})));
diff --git a/source/fuzz/transformation_replace_irrelevant_id.cpp b/source/fuzz/transformation_replace_irrelevant_id.cpp
index a71f96a..7f64063 100644
--- a/source/fuzz/transformation_replace_irrelevant_id.cpp
+++ b/source/fuzz/transformation_replace_irrelevant_id.cpp
@@ -65,7 +65,7 @@
   }
 
   // The replacement id must not be the result of an OpFunction instruction.
-  if (replacement_id_def->opcode() == SpvOpFunction) {
+  if (replacement_id_def->opcode() == spv::Op::OpFunction) {
     return false;
   }
 
@@ -130,7 +130,7 @@
     AttemptsToReplaceVariableInitializerWithNonConstant(
         const opt::Instruction& use_instruction,
         const opt::Instruction& replacement_for_use) {
-  return use_instruction.opcode() == SpvOpVariable &&
+  return use_instruction.opcode() == spv::Op::OpVariable &&
          !spvOpcodeIsConstant(replacement_for_use.opcode());
 }
 
diff --git a/source/fuzz/transformation_replace_linear_algebra_instruction.cpp b/source/fuzz/transformation_replace_linear_algebra_instruction.cpp
index 2430cca..fb7b294 100644
--- a/source/fuzz/transformation_replace_linear_algebra_instruction.cpp
+++ b/source/fuzz/transformation_replace_linear_algebra_instruction.cpp
@@ -68,28 +68,28 @@
       FindInstruction(message_.instruction_descriptor(), ir_context);
 
   switch (linear_algebra_instruction->opcode()) {
-    case SpvOpTranspose:
+    case spv::Op::OpTranspose:
       ReplaceOpTranspose(ir_context, linear_algebra_instruction);
       break;
-    case SpvOpVectorTimesScalar:
+    case spv::Op::OpVectorTimesScalar:
       ReplaceOpVectorTimesScalar(ir_context, linear_algebra_instruction);
       break;
-    case SpvOpMatrixTimesScalar:
+    case spv::Op::OpMatrixTimesScalar:
       ReplaceOpMatrixTimesScalar(ir_context, linear_algebra_instruction);
       break;
-    case SpvOpVectorTimesMatrix:
+    case spv::Op::OpVectorTimesMatrix:
       ReplaceOpVectorTimesMatrix(ir_context, linear_algebra_instruction);
       break;
-    case SpvOpMatrixTimesVector:
+    case spv::Op::OpMatrixTimesVector:
       ReplaceOpMatrixTimesVector(ir_context, linear_algebra_instruction);
       break;
-    case SpvOpMatrixTimesMatrix:
+    case spv::Op::OpMatrixTimesMatrix:
       ReplaceOpMatrixTimesMatrix(ir_context, linear_algebra_instruction);
       break;
-    case SpvOpOuterProduct:
+    case spv::Op::OpOuterProduct:
       ReplaceOpOuterProduct(ir_context, linear_algebra_instruction);
       break;
-    case SpvOpDot:
+    case spv::Op::OpDot:
       ReplaceOpDot(ir_context, linear_algebra_instruction);
       break;
     default:
@@ -112,7 +112,7 @@
   // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3354):
   // Right now we only support certain operations.
   switch (instruction->opcode()) {
-    case SpvOpTranspose: {
+    case spv::Op::OpTranspose: {
       // For each matrix row, |2 * matrix_column_count| OpCompositeExtract and 1
       // OpCompositeConstruct will be inserted.
       auto matrix_instruction = ir_context->get_def_use_mgr()->GetDef(
@@ -130,7 +130,7 @@
                                       ->element_count();
       return matrix_row_count * (2 * matrix_column_count + 1);
     }
-    case SpvOpVectorTimesScalar:
+    case spv::Op::OpVectorTimesScalar:
       // For each vector component, 1 OpCompositeExtract and 1 OpFMul will be
       // inserted.
       return 2 *
@@ -140,7 +140,7 @@
                                ->type_id())
                  ->AsVector()
                  ->element_count();
-    case SpvOpMatrixTimesScalar: {
+    case spv::Op::OpMatrixTimesScalar: {
       // For each matrix column, |1 + column.size| OpCompositeExtract,
       // |column.size| OpFMul and 1 OpCompositeConstruct instructions will be
       // inserted.
@@ -154,7 +154,7 @@
                       ->AsVector()
                       ->element_count());
     }
-    case SpvOpVectorTimesMatrix: {
+    case spv::Op::OpVectorTimesMatrix: {
       // For each vector component, 1 OpCompositeExtract instruction will be
       // inserted. For each matrix column, |1 + vector_component_count|
       // OpCompositeExtract, |vector_component_count| OpFMul and
@@ -175,7 +175,7 @@
               ->element_count();
       return vector_component_count * (3 * matrix_column_count + 1);
     }
-    case SpvOpMatrixTimesVector: {
+    case spv::Op::OpMatrixTimesVector: {
       // For each matrix column, |1 + matrix_row_count| OpCompositeExtract
       // will be inserted. For each matrix row, |matrix_column_count| OpFMul and
       // |matrix_column_count - 1| OpFAdd instructions will be inserted. For
@@ -197,7 +197,7 @@
       return 3 * matrix_column_count * matrix_row_count +
              2 * matrix_column_count - matrix_row_count;
     }
-    case SpvOpMatrixTimesMatrix: {
+    case spv::Op::OpMatrixTimesMatrix: {
       // For each matrix 2 column, 1 OpCompositeExtract, 1 OpCompositeConstruct,
       // |3 * matrix_1_row_count * matrix_1_column_count| OpCompositeExtract,
       // |matrix_1_row_count * matrix_1_column_count| OpFMul,
@@ -228,7 +228,7 @@
       return matrix_2_column_count *
              (2 + matrix_1_row_count * (5 * matrix_1_column_count - 1));
     }
-    case SpvOpOuterProduct: {
+    case spv::Op::OpOuterProduct: {
       // For each |vector_2| component, |vector_1_component_count + 1|
       // OpCompositeExtract, |vector_1_component_count| OpFMul and 1
       // OpCompositeConstruct instructions will be inserted.
@@ -248,7 +248,7 @@
               ->element_count();
       return 2 * vector_2_component_count * (vector_1_component_count + 1);
     }
-    case SpvOpDot:
+    case spv::Op::OpDot:
       // For each pair of vector components, 2 OpCompositeExtract and 1 OpFMul
       // will be inserted. The first two OpFMul instructions will result the
       // first OpFAdd instruction to be inserted. For each remaining OpFMul, 1
@@ -299,7 +299,7 @@
       // Extracts the matrix column.
       uint32_t matrix_column_id = message_.fresh_ids(fresh_id_index++);
       linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpCompositeExtract,
+          ir_context, spv::Op::OpCompositeExtract,
           ir_context->get_type_mgr()->GetId(matrix_column_type),
           matrix_column_id,
           opt::Instruction::OperandList(
@@ -309,7 +309,7 @@
       // Extracts the matrix column component.
       column_component_ids[j] = message_.fresh_ids(fresh_id_index++);
       linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpCompositeExtract,
+          ir_context, spv::Op::OpCompositeExtract,
           ir_context->get_type_mgr()->GetId(matrix_column_component_type),
           column_component_ids[j],
           opt::Instruction::OperandList(
@@ -324,14 +324,14 @@
     }
     result_column_ids[i] = message_.fresh_ids(fresh_id_index++);
     linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpCompositeConstruct,
+        ir_context, spv::Op::OpCompositeConstruct,
         ir_context->get_type_mgr()->GetId(resulting_matrix_column_type),
         result_column_ids[i], opt::Instruction::OperandList(in_operands)));
   }
 
   // The OpTranspose instruction is changed to an OpCompositeConstruct
   // instruction.
-  linear_algebra_instruction->SetOpcode(SpvOpCompositeConstruct);
+  linear_algebra_instruction->SetOpcode(spv::Op::OpCompositeConstruct);
   linear_algebra_instruction->SetInOperand(0, {result_column_ids[0]});
   for (uint32_t i = 1; i < result_column_ids.size(); i++) {
     linear_algebra_instruction->AddOperand(
@@ -363,7 +363,8 @@
     uint32_t vector_extract_id = message_.fresh_ids(fresh_id_index++);
     fuzzerutil::UpdateModuleIdBound(ir_context, vector_extract_id);
     linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpCompositeExtract, scalar->type_id(), vector_extract_id,
+        ir_context, spv::Op::OpCompositeExtract, scalar->type_id(),
+        vector_extract_id,
         opt::Instruction::OperandList(
             {{SPV_OPERAND_TYPE_ID, {vector->result_id()}},
              {SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}})));
@@ -373,7 +374,7 @@
     float_multiplication_ids[i] = float_multiplication_id;
     fuzzerutil::UpdateModuleIdBound(ir_context, float_multiplication_id);
     linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpFMul, scalar->type_id(), float_multiplication_id,
+        ir_context, spv::Op::OpFMul, scalar->type_id(), float_multiplication_id,
         opt::Instruction::OperandList(
             {{SPV_OPERAND_TYPE_ID, {vector_extract_id}},
              {SPV_OPERAND_TYPE_ID, {scalar->result_id()}}})));
@@ -381,7 +382,7 @@
 
   // The OpVectorTimesScalar instruction is changed to an OpCompositeConstruct
   // instruction.
-  linear_algebra_instruction->SetOpcode(SpvOpCompositeConstruct);
+  linear_algebra_instruction->SetOpcode(spv::Op::OpCompositeConstruct);
   linear_algebra_instruction->SetInOperand(0, {float_multiplication_ids[0]});
   linear_algebra_instruction->SetInOperand(1, {float_multiplication_ids[1]});
   for (uint32_t i = 2; i < float_multiplication_ids.size(); i++) {
@@ -418,7 +419,7 @@
     uint32_t matrix_extract_id = message_.fresh_ids(fresh_id_index++);
     fuzzerutil::UpdateModuleIdBound(ir_context, matrix_extract_id);
     linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpCompositeExtract,
+        ir_context, spv::Op::OpCompositeExtract,
         ir_context->get_type_mgr()->GetId(matrix_column_type),
         matrix_extract_id,
         opt::Instruction::OperandList(
@@ -432,8 +433,8 @@
       uint32_t column_extract_id = message_.fresh_ids(fresh_id_index++);
       fuzzerutil::UpdateModuleIdBound(ir_context, column_extract_id);
       linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpCompositeExtract, scalar_instruction->type_id(),
-          column_extract_id,
+          ir_context, spv::Op::OpCompositeExtract,
+          scalar_instruction->type_id(), column_extract_id,
           opt::Instruction::OperandList(
               {{SPV_OPERAND_TYPE_ID, {matrix_extract_id}},
                {SPV_OPERAND_TYPE_LITERAL_INTEGER, {j}}})));
@@ -442,7 +443,7 @@
       float_multiplication_ids[j] = message_.fresh_ids(fresh_id_index++);
       fuzzerutil::UpdateModuleIdBound(ir_context, float_multiplication_ids[j]);
       linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpFMul, scalar_instruction->type_id(),
+          ir_context, spv::Op::OpFMul, scalar_instruction->type_id(),
           float_multiplication_ids[j],
           opt::Instruction::OperandList(
               {{SPV_OPERAND_TYPE_ID, {column_extract_id}},
@@ -458,14 +459,14 @@
     composite_construct_ids[i] = message_.fresh_ids(fresh_id_index++);
     fuzzerutil::UpdateModuleIdBound(ir_context, composite_construct_ids[i]);
     linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpCompositeConstruct,
+        ir_context, spv::Op::OpCompositeConstruct,
         ir_context->get_type_mgr()->GetId(matrix_column_type),
         composite_construct_ids[i], composite_construct_in_operands));
   }
 
   // The OpMatrixTimesScalar instruction is changed to an OpCompositeConstruct
   // instruction.
-  linear_algebra_instruction->SetOpcode(SpvOpCompositeConstruct);
+  linear_algebra_instruction->SetOpcode(spv::Op::OpCompositeConstruct);
   linear_algebra_instruction->SetInOperand(0, {composite_construct_ids[0]});
   linear_algebra_instruction->SetInOperand(1, {composite_construct_ids[1]});
   for (uint32_t i = 2; i < composite_construct_ids.size(); i++) {
@@ -495,7 +496,7 @@
   for (uint32_t i = 0; i < vector_component_count; i++) {
     vector_component_ids[i] = message_.fresh_ids(fresh_id_index++);
     linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpCompositeExtract,
+        ir_context, spv::Op::OpCompositeExtract,
         ir_context->get_type_mgr()->GetId(vector_component_type),
         vector_component_ids[i],
         opt::Instruction::OperandList(
@@ -520,7 +521,7 @@
     // Extracts matrix column.
     uint32_t matrix_extract_id = message_.fresh_ids(fresh_id_index++);
     linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpCompositeExtract,
+        ir_context, spv::Op::OpCompositeExtract,
         ir_context->get_type_mgr()->GetId(matrix_column_type),
         matrix_extract_id,
         opt::Instruction::OperandList(
@@ -532,7 +533,7 @@
       // Extracts column component.
       uint32_t column_extract_id = message_.fresh_ids(fresh_id_index++);
       linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpCompositeExtract,
+          ir_context, spv::Op::OpCompositeExtract,
           ir_context->get_type_mgr()->GetId(vector_component_type),
           column_extract_id,
           opt::Instruction::OperandList(
@@ -542,7 +543,7 @@
       // Multiplies corresponding vector and column components.
       float_multiplication_ids[j] = message_.fresh_ids(fresh_id_index++);
       linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpFMul,
+          ir_context, spv::Op::OpFMul,
           ir_context->get_type_mgr()->GetId(vector_component_type),
           float_multiplication_ids[j],
           opt::Instruction::OperandList(
@@ -555,7 +556,7 @@
     uint32_t float_add_id = message_.fresh_ids(fresh_id_index++);
     float_add_ids.push_back(float_add_id);
     linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpFAdd,
+        ir_context, spv::Op::OpFAdd,
         ir_context->get_type_mgr()->GetId(vector_component_type), float_add_id,
         opt::Instruction::OperandList(
             {{SPV_OPERAND_TYPE_ID, {float_multiplication_ids[0]}},
@@ -564,7 +565,7 @@
       float_add_id = message_.fresh_ids(fresh_id_index++);
       float_add_ids.push_back(float_add_id);
       linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpFAdd,
+          ir_context, spv::Op::OpFAdd,
           ir_context->get_type_mgr()->GetId(vector_component_type),
           float_add_id,
           opt::Instruction::OperandList(
@@ -577,7 +578,7 @@
 
   // The OpVectorTimesMatrix instruction is changed to an OpCompositeConstruct
   // instruction.
-  linear_algebra_instruction->SetOpcode(SpvOpCompositeConstruct);
+  linear_algebra_instruction->SetOpcode(spv::Op::OpCompositeConstruct);
   linear_algebra_instruction->SetInOperand(0, {result_component_ids[0]});
   linear_algebra_instruction->SetInOperand(1, {result_component_ids[1]});
   for (uint32_t i = 2; i < result_component_ids.size(); i++) {
@@ -611,7 +612,7 @@
   for (uint32_t i = 0; i < matrix_column_count; i++) {
     matrix_column_ids[i] = message_.fresh_ids(fresh_id_index++);
     linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpCompositeExtract,
+        ir_context, spv::Op::OpCompositeExtract,
         ir_context->get_type_mgr()->GetId(matrix_column_type),
         matrix_column_ids[i],
         opt::Instruction::OperandList(
@@ -632,7 +633,7 @@
   for (uint32_t i = 0; i < matrix_column_count; i++) {
     vector_component_ids[i] = message_.fresh_ids(fresh_id_index++);
     linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpCompositeExtract,
+        ir_context, spv::Op::OpCompositeExtract,
         ir_context->get_type_mgr()->GetId(vector_component_type),
         vector_component_ids[i],
         opt::Instruction::OperandList(
@@ -647,7 +648,7 @@
       // Extracts column component.
       uint32_t column_extract_id = message_.fresh_ids(fresh_id_index++);
       linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpCompositeExtract,
+          ir_context, spv::Op::OpCompositeExtract,
           ir_context->get_type_mgr()->GetId(vector_component_type),
           column_extract_id,
           opt::Instruction::OperandList(
@@ -657,7 +658,7 @@
       // Multiplies corresponding vector and column components.
       float_multiplication_ids[j] = message_.fresh_ids(fresh_id_index++);
       linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpFMul,
+          ir_context, spv::Op::OpFMul,
           ir_context->get_type_mgr()->GetId(vector_component_type),
           float_multiplication_ids[j],
           opt::Instruction::OperandList(
@@ -670,7 +671,7 @@
     uint32_t float_add_id = message_.fresh_ids(fresh_id_index++);
     float_add_ids.push_back(float_add_id);
     linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpFAdd,
+        ir_context, spv::Op::OpFAdd,
         ir_context->get_type_mgr()->GetId(vector_component_type), float_add_id,
         opt::Instruction::OperandList(
             {{SPV_OPERAND_TYPE_ID, {float_multiplication_ids[0]}},
@@ -679,7 +680,7 @@
       float_add_id = message_.fresh_ids(fresh_id_index++);
       float_add_ids.push_back(float_add_id);
       linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpFAdd,
+          ir_context, spv::Op::OpFAdd,
           ir_context->get_type_mgr()->GetId(vector_component_type),
           float_add_id,
           opt::Instruction::OperandList(
@@ -692,7 +693,7 @@
 
   // The OpMatrixTimesVector instruction is changed to an OpCompositeConstruct
   // instruction.
-  linear_algebra_instruction->SetOpcode(SpvOpCompositeConstruct);
+  linear_algebra_instruction->SetOpcode(spv::Op::OpCompositeConstruct);
   linear_algebra_instruction->SetInOperand(0, {result_component_ids[0]});
   linear_algebra_instruction->SetInOperand(1, {result_component_ids[1]});
   for (uint32_t i = 2; i < result_component_ids.size(); i++) {
@@ -743,7 +744,7 @@
     // Extracts matrix 2 column.
     uint32_t matrix_2_column_id = message_.fresh_ids(fresh_id_index++);
     linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpCompositeExtract,
+        ir_context, spv::Op::OpCompositeExtract,
         ir_context->get_type_mgr()->GetId(matrix_2_column_type),
         matrix_2_column_id,
         opt::Instruction::OperandList(
@@ -757,7 +758,7 @@
         // Extracts matrix 1 column.
         uint32_t matrix_1_column_id = message_.fresh_ids(fresh_id_index++);
         linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-            ir_context, SpvOpCompositeExtract,
+            ir_context, spv::Op::OpCompositeExtract,
             ir_context->get_type_mgr()->GetId(matrix_1_column_type),
             matrix_1_column_id,
             opt::Instruction::OperandList(
@@ -768,7 +769,7 @@
         uint32_t matrix_1_column_component_id =
             message_.fresh_ids(fresh_id_index++);
         linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-            ir_context, SpvOpCompositeExtract,
+            ir_context, spv::Op::OpCompositeExtract,
             ir_context->get_type_mgr()->GetId(matrix_1_column_component_type),
             matrix_1_column_component_id,
             opt::Instruction::OperandList(
@@ -779,7 +780,7 @@
         uint32_t matrix_2_column_component_id =
             message_.fresh_ids(fresh_id_index++);
         linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-            ir_context, SpvOpCompositeExtract,
+            ir_context, spv::Op::OpCompositeExtract,
             ir_context->get_type_mgr()->GetId(matrix_1_column_component_type),
             matrix_2_column_component_id,
             opt::Instruction::OperandList(
@@ -789,7 +790,7 @@
         // Multiplies corresponding matrix 1 and matrix 2 column components.
         float_multiplication_ids[k] = message_.fresh_ids(fresh_id_index++);
         linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-            ir_context, SpvOpFMul,
+            ir_context, spv::Op::OpFMul,
             ir_context->get_type_mgr()->GetId(matrix_1_column_component_type),
             float_multiplication_ids[k],
             opt::Instruction::OperandList(
@@ -802,7 +803,7 @@
       uint32_t float_add_id = message_.fresh_ids(fresh_id_index++);
       float_add_ids.push_back(float_add_id);
       linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpFAdd,
+          ir_context, spv::Op::OpFAdd,
           ir_context->get_type_mgr()->GetId(matrix_1_column_component_type),
           float_add_id,
           opt::Instruction::OperandList(
@@ -812,7 +813,7 @@
         float_add_id = message_.fresh_ids(fresh_id_index++);
         float_add_ids.push_back(float_add_id);
         linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-            ir_context, SpvOpFAdd,
+            ir_context, spv::Op::OpFAdd,
             ir_context->get_type_mgr()->GetId(matrix_1_column_component_type),
             float_add_id,
             opt::Instruction::OperandList(
@@ -830,14 +831,14 @@
     }
     result_column_ids[i] = message_.fresh_ids(fresh_id_index++);
     linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpCompositeConstruct,
+        ir_context, spv::Op::OpCompositeConstruct,
         ir_context->get_type_mgr()->GetId(matrix_1_column_type),
         result_column_ids[i], opt::Instruction::OperandList(in_operands)));
   }
 
   // The OpMatrixTimesMatrix instruction is changed to an OpCompositeConstruct
   // instruction.
-  linear_algebra_instruction->SetOpcode(SpvOpCompositeConstruct);
+  linear_algebra_instruction->SetOpcode(spv::Op::OpCompositeConstruct);
   linear_algebra_instruction->SetInOperand(0, {result_column_ids[0]});
   linear_algebra_instruction->SetInOperand(1, {result_column_ids[1]});
   for (uint32_t i = 2; i < result_column_ids.size(); i++) {
@@ -880,7 +881,7 @@
     // Extracts |vector_2| component.
     uint32_t vector_2_component_id = message_.fresh_ids(fresh_id_index++);
     linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpCompositeExtract,
+        ir_context, spv::Op::OpCompositeExtract,
         ir_context->get_type_mgr()->GetId(vector_1_component_type),
         vector_2_component_id,
         opt::Instruction::OperandList(
@@ -892,7 +893,7 @@
       // Extracts |vector_1| component.
       uint32_t vector_1_component_id = message_.fresh_ids(fresh_id_index++);
       linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpCompositeExtract,
+          ir_context, spv::Op::OpCompositeExtract,
           ir_context->get_type_mgr()->GetId(vector_1_component_type),
           vector_1_component_id,
           opt::Instruction::OperandList(
@@ -902,7 +903,7 @@
       // Multiplies |vector_1| and |vector_2| components.
       column_component_ids[j] = message_.fresh_ids(fresh_id_index++);
       linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpFMul,
+          ir_context, spv::Op::OpFMul,
           ir_context->get_type_mgr()->GetId(vector_1_component_type),
           column_component_ids[j],
           opt::Instruction::OperandList(
@@ -917,13 +918,13 @@
     }
     result_column_ids[i] = message_.fresh_ids(fresh_id_index++);
     linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpCompositeConstruct, vector_1_instruction->type_id(),
-        result_column_ids[i], in_operands));
+        ir_context, spv::Op::OpCompositeConstruct,
+        vector_1_instruction->type_id(), result_column_ids[i], in_operands));
   }
 
   // The OpOuterProduct instruction is changed to an OpCompositeConstruct
   // instruction.
-  linear_algebra_instruction->SetOpcode(SpvOpCompositeConstruct);
+  linear_algebra_instruction->SetOpcode(spv::Op::OpCompositeConstruct);
   linear_algebra_instruction->SetInOperand(0, {result_column_ids[0]});
   linear_algebra_instruction->SetInOperand(1, {result_column_ids[1]});
   for (uint32_t i = 2; i < result_column_ids.size(); i++) {
@@ -956,7 +957,7 @@
     uint32_t vector_1_extract_id = message_.fresh_ids(fresh_id_index++);
     fuzzerutil::UpdateModuleIdBound(ir_context, vector_1_extract_id);
     linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpCompositeExtract,
+        ir_context, spv::Op::OpCompositeExtract,
         linear_algebra_instruction->type_id(), vector_1_extract_id,
         opt::Instruction::OperandList(
             {{SPV_OPERAND_TYPE_ID, {vector_1->result_id()}},
@@ -966,7 +967,7 @@
     uint32_t vector_2_extract_id = message_.fresh_ids(fresh_id_index++);
     fuzzerutil::UpdateModuleIdBound(ir_context, vector_2_extract_id);
     linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpCompositeExtract,
+        ir_context, spv::Op::OpCompositeExtract,
         linear_algebra_instruction->type_id(), vector_2_extract_id,
         opt::Instruction::OperandList(
             {{SPV_OPERAND_TYPE_ID, {vector_2->result_id()}},
@@ -976,7 +977,7 @@
     float_multiplication_ids[i] = message_.fresh_ids(fresh_id_index++);
     fuzzerutil::UpdateModuleIdBound(ir_context, float_multiplication_ids[i]);
     linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpFMul, linear_algebra_instruction->type_id(),
+        ir_context, spv::Op::OpFMul, linear_algebra_instruction->type_id(),
         float_multiplication_ids[i],
         opt::Instruction::OperandList(
             {{SPV_OPERAND_TYPE_ID, {vector_1_extract_id}},
@@ -986,7 +987,7 @@
   // If the vector has 2 components, then there will be 2 float multiplication
   // instructions.
   if (vectors_component_count == 2) {
-    linear_algebra_instruction->SetOpcode(SpvOpFAdd);
+    linear_algebra_instruction->SetOpcode(spv::Op::OpFAdd);
     linear_algebra_instruction->SetInOperand(0, {float_multiplication_ids[0]});
     linear_algebra_instruction->SetInOperand(1, {float_multiplication_ids[1]});
   } else {
@@ -997,7 +998,7 @@
     float_add_ids.push_back(float_add_id);
     fuzzerutil::UpdateModuleIdBound(ir_context, float_add_id);
     linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpFAdd, linear_algebra_instruction->type_id(),
+        ir_context, spv::Op::OpFAdd, linear_algebra_instruction->type_id(),
         float_add_id,
         opt::Instruction::OperandList(
             {{SPV_OPERAND_TYPE_ID, {float_multiplication_ids[0]}},
@@ -1010,7 +1011,7 @@
       fuzzerutil::UpdateModuleIdBound(ir_context, float_add_id);
       float_add_ids.push_back(float_add_id);
       linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpFAdd, linear_algebra_instruction->type_id(),
+          ir_context, spv::Op::OpFAdd, linear_algebra_instruction->type_id(),
           float_add_id,
           opt::Instruction::OperandList(
               {{SPV_OPERAND_TYPE_ID, {float_multiplication_ids[i]}},
@@ -1019,7 +1020,7 @@
 
     // The last OpFAdd instruction is got by changing some of the OpDot
     // instruction attributes.
-    linear_algebra_instruction->SetOpcode(SpvOpFAdd);
+    linear_algebra_instruction->SetOpcode(spv::Op::OpFAdd);
     linear_algebra_instruction->SetInOperand(
         0, {float_multiplication_ids[float_multiplication_ids.size() - 1]});
     linear_algebra_instruction->SetInOperand(
diff --git a/source/fuzz/transformation_replace_load_store_with_copy_memory.cpp b/source/fuzz/transformation_replace_load_store_with_copy_memory.cpp
index e75337f..36610f2 100644
--- a/source/fuzz/transformation_replace_load_store_with_copy_memory.cpp
+++ b/source/fuzz/transformation_replace_load_store_with_copy_memory.cpp
@@ -48,14 +48,14 @@
   // The OpLoad instruction must be defined.
   auto load_instruction =
       FindInstruction(message_.load_instruction_descriptor(), ir_context);
-  if (!load_instruction || load_instruction->opcode() != SpvOpLoad) {
+  if (!load_instruction || load_instruction->opcode() != spv::Op::OpLoad) {
     return false;
   }
 
   // The OpStore instruction must be defined.
   auto store_instruction =
       FindInstruction(message_.store_instruction_descriptor(), ir_context);
-  if (!store_instruction || store_instruction->opcode() != SpvOpStore) {
+  if (!store_instruction || store_instruction->opcode() != spv::Op::OpStore) {
     return false;
   }
 
@@ -69,7 +69,7 @@
   // Get storage class of the variable pointed by the source operand in OpLoad.
   opt::Instruction* source_id = ir_context->get_def_use_mgr()->GetDef(
       load_instruction->GetSingleWordOperand(2));
-  SpvStorageClass storage_class = fuzzerutil::GetStorageClassFromPointerType(
+  spv::StorageClass storage_class = fuzzerutil::GetStorageClassFromPointerType(
       ir_context, source_id->type_id());
 
   // Iterate over all instructions between |load_instruction| and
@@ -99,11 +99,11 @@
   // OpLoad and OpStore instructions must be defined.
   auto load_instruction =
       FindInstruction(message_.load_instruction_descriptor(), ir_context);
-  assert(load_instruction && load_instruction->opcode() == SpvOpLoad &&
+  assert(load_instruction && load_instruction->opcode() == spv::Op::OpLoad &&
          "The required OpLoad instruction must be defined.");
   auto store_instruction =
       FindInstruction(message_.store_instruction_descriptor(), ir_context);
-  assert(store_instruction && store_instruction->opcode() == SpvOpStore &&
+  assert(store_instruction && store_instruction->opcode() == spv::Op::OpStore &&
          "The required OpStore instruction must be defined.");
 
   // Intermediate values of the OpLoad and the OpStore must match.
@@ -121,7 +121,7 @@
 
   // Insert the OpCopyMemory instruction before the OpStore instruction.
   store_instruction->InsertBefore(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpCopyMemory, 0, 0,
+      ir_context, spv::Op::OpCopyMemory, 0, 0,
       opt::Instruction::OperandList(
           {{SPV_OPERAND_TYPE_ID, {target_variable_id}},
            {SPV_OPERAND_TYPE_ID, {source_variable_id}}})));
@@ -133,14 +133,14 @@
 }
 
 bool TransformationReplaceLoadStoreWithCopyMemory::IsMemoryWritingOpCode(
-    SpvOp op_code) {
+    spv::Op op_code) {
   if (spvOpcodeIsAtomicOp(op_code)) {
-    return op_code != SpvOpAtomicLoad;
+    return op_code != spv::Op::OpAtomicLoad;
   }
   switch (op_code) {
-    case SpvOpStore:
-    case SpvOpCopyMemory:
-    case SpvOpCopyMemorySized:
+    case spv::Op::OpStore:
+    case spv::Op::OpCopyMemory:
+    case spv::Op::OpCopyMemorySized:
       return true;
     default:
       return false;
@@ -148,10 +148,10 @@
 }
 
 bool TransformationReplaceLoadStoreWithCopyMemory::IsMemoryBarrierOpCode(
-    SpvOp op_code) {
+    spv::Op op_code) {
   switch (op_code) {
-    case SpvOpMemoryBarrier:
-    case SpvOpMemoryNamedBarrier:
+    case spv::Op::OpMemoryBarrier:
+    case spv::Op::OpMemoryNamedBarrier:
       return true;
     default:
       return false;
@@ -159,13 +159,13 @@
 }
 
 bool TransformationReplaceLoadStoreWithCopyMemory::
-    IsStorageClassSafeAcrossMemoryBarriers(SpvStorageClass storage_class) {
+    IsStorageClassSafeAcrossMemoryBarriers(spv::StorageClass storage_class) {
   switch (storage_class) {
-    case SpvStorageClassUniformConstant:
-    case SpvStorageClassInput:
-    case SpvStorageClassUniform:
-    case SpvStorageClassPrivate:
-    case SpvStorageClassFunction:
+    case spv::StorageClass::UniformConstant:
+    case spv::StorageClass::Input:
+    case spv::StorageClass::Uniform:
+    case spv::StorageClass::Private:
+    case spv::StorageClass::Function:
       return true;
     default:
       return false;
diff --git a/source/fuzz/transformation_replace_load_store_with_copy_memory.h b/source/fuzz/transformation_replace_load_store_with_copy_memory.h
index bb4d27e..43c754e 100644
--- a/source/fuzz/transformation_replace_load_store_with_copy_memory.h
+++ b/source/fuzz/transformation_replace_load_store_with_copy_memory.h
@@ -52,17 +52,17 @@
 
   // Checks if the instruction that has an |op_code| might write to
   // the source operand of the OpLoad instruction.
-  static bool IsMemoryWritingOpCode(SpvOp op_code);
+  static bool IsMemoryWritingOpCode(spv::Op op_code);
 
   // Checks if the instruction that has an |op_code| is a memory barrier that
   // could interfere with the source operand of the OpLoad instruction
-  static bool IsMemoryBarrierOpCode(SpvOp op_code);
+  static bool IsMemoryBarrierOpCode(spv::Op op_code);
 
   // Checks if the |storage_class| of the source operand of the OpLoad
   // instruction implies that this variable cannot change (due to other threads)
   // across memory barriers.
   static bool IsStorageClassSafeAcrossMemoryBarriers(
-      SpvStorageClass storage_class);
+      spv::StorageClass storage_class);
 
   std::unordered_set<uint32_t> GetFreshIds() const override;
 
diff --git a/source/fuzz/transformation_replace_opphi_id_from_dead_predecessor.cpp b/source/fuzz/transformation_replace_opphi_id_from_dead_predecessor.cpp
index 84ca1ab..eeda68d 100644
--- a/source/fuzz/transformation_replace_opphi_id_from_dead_predecessor.cpp
+++ b/source/fuzz/transformation_replace_opphi_id_from_dead_predecessor.cpp
@@ -38,7 +38,7 @@
     const TransformationContext& transformation_context) const {
   // |opphi_id| must be the id of an OpPhi instruction.
   auto opphi_def = ir_context->get_def_use_mgr()->GetDef(message_.opphi_id());
-  if (!opphi_def || opphi_def->opcode() != SpvOpPhi) {
+  if (!opphi_def || opphi_def->opcode() != spv::Op::OpPhi) {
     return false;
   }
 
diff --git a/source/fuzz/transformation_replace_opselect_with_conditional_branch.cpp b/source/fuzz/transformation_replace_opselect_with_conditional_branch.cpp
index c0e6e44..b2010a9 100644
--- a/source/fuzz/transformation_replace_opselect_with_conditional_branch.cpp
+++ b/source/fuzz/transformation_replace_opselect_with_conditional_branch.cpp
@@ -50,7 +50,7 @@
       ir_context->get_def_use_mgr()->GetDef(message_.select_id());
 
   // The instruction must exist and it must be an OpSelect instruction.
-  if (!instruction || instruction->opcode() != SpvOpSelect) {
+  if (!instruction || instruction->opcode() != spv::Op::OpSelect) {
     return false;
   }
 
@@ -90,7 +90,7 @@
   // The predecessor must not be the header of a construct and it must end with
   // OpBranch.
   if (predecessor->GetMergeInst() != nullptr ||
-      predecessor->terminator()->opcode() != SpvOpBranch) {
+      predecessor->terminator()->opcode() != spv::Op::OpBranch) {
     return false;
   }
 
@@ -115,13 +115,14 @@
       fuzzerutil::UpdateModuleIdBound(ir_context, id);
 
       // Create the new block.
-      auto new_block = MakeUnique<opt::BasicBlock>(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpLabel, 0, id, opt::Instruction::OperandList{}));
+      auto new_block = MakeUnique<opt::BasicBlock>(
+          MakeUnique<opt::Instruction>(ir_context, spv::Op::OpLabel, 0, id,
+                                       opt::Instruction::OperandList{}));
 
       // Add an unconditional branch from the new block to the instruction
       // block.
       new_block->AddInstruction(MakeUnique<opt::Instruction>(
-          ir_context, SpvOpBranch, 0, 0,
+          ir_context, spv::Op::OpBranch, 0, 0,
           opt::Instruction::OperandList{{SPV_OPERAND_TYPE_ID, {block->id()}}}));
 
       // Insert the new block right after the predecessor of the instruction
@@ -136,10 +137,11 @@
   // Add an OpSelectionMerge instruction to the predecessor block, where the
   // merge block is the instruction block.
   predecessor->AddInstruction(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpSelectionMerge, 0, 0,
-      opt::Instruction::OperandList{{SPV_OPERAND_TYPE_ID, {block->id()}},
-                                    {SPV_OPERAND_TYPE_SELECTION_CONTROL,
-                                     {SpvSelectionControlMaskNone}}}));
+      ir_context, spv::Op::OpSelectionMerge, 0, 0,
+      opt::Instruction::OperandList{
+          {SPV_OPERAND_TYPE_ID, {block->id()}},
+          {SPV_OPERAND_TYPE_SELECTION_CONTROL,
+           {uint32_t(spv::SelectionControlMask::MaskNone)}}}));
 
   // |if_block| will be the true block, if it has been created, the instruction
   // block otherwise.
@@ -158,7 +160,7 @@
   // Add a conditional branching instruction to the predecessor, branching to
   // |if_block| if the condition is true and to |if_false| otherwise.
   predecessor->AddInstruction(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpBranchConditional, 0, 0,
+      ir_context, spv::Op::OpBranchConditional, 0, 0,
       opt::Instruction::OperandList{
           {SPV_OPERAND_TYPE_ID, {instruction->GetSingleWordInOperand(0)}},
           {SPV_OPERAND_TYPE_ID, {if_block}},
@@ -177,7 +179,7 @@
   // Replace the OpSelect instruction in the merge block with an OpPhi.
   // This:          OpSelect %type %cond %if %else
   // will become:   OpPhi %type %if %if_pred %else %else_pred
-  instruction->SetOpcode(SpvOpPhi);
+  instruction->SetOpcode(spv::Op::OpPhi);
   std::vector<opt::Operand> operands;
 
   operands.emplace_back(instruction->GetInOperand(1));
diff --git a/source/fuzz/transformation_replace_parameter_with_global.cpp b/source/fuzz/transformation_replace_parameter_with_global.cpp
index caf6716..e80dfe9 100644
--- a/source/fuzz/transformation_replace_parameter_with_global.cpp
+++ b/source/fuzz/transformation_replace_parameter_with_global.cpp
@@ -41,7 +41,7 @@
   // Check that |parameter_id| is valid.
   const auto* param_inst =
       ir_context->get_def_use_mgr()->GetDef(message_.parameter_id());
-  if (!param_inst || param_inst->opcode() != SpvOpFunctionParameter) {
+  if (!param_inst || param_inst->opcode() != spv::Op::OpFunctionParameter) {
     return false;
   }
 
@@ -69,7 +69,7 @@
 
   // Check that pointer type for the global variable exists in the module.
   if (!fuzzerutil::MaybeGetPointerType(ir_context, param_inst->type_id(),
-                                       SpvStorageClassPrivate)) {
+                                       spv::StorageClass::Private)) {
     return false;
   }
 
@@ -91,8 +91,8 @@
   fuzzerutil::AddGlobalVariable(
       ir_context, message_.global_variable_fresh_id(),
       fuzzerutil::MaybeGetPointerType(ir_context, param_inst->type_id(),
-                                      SpvStorageClassPrivate),
-      SpvStorageClassPrivate,
+                                      spv::StorageClass::Private),
+      spv::StorageClass::Private,
       fuzzerutil::MaybeGetZeroConstant(ir_context, *transformation_context,
                                        param_inst->type_id(), false));
 
@@ -103,16 +103,17 @@
   // Insert an OpLoad instruction right after OpVariable instructions.
   auto it = function->begin()->begin();
   while (it != function->begin()->end() &&
-         !fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLoad, it)) {
+         !fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpLoad, it)) {
     ++it;
   }
 
-  assert(fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLoad, it) &&
+  assert(fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpLoad, it) &&
          "Can't insert OpLoad or OpCopyMemory into the first basic block of "
          "the function");
 
   it.InsertBefore(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpLoad, param_inst->type_id(), param_inst->result_id(),
+      ir_context, spv::Op::OpLoad, param_inst->type_id(),
+      param_inst->result_id(),
       opt::Instruction::OperandList{
           {SPV_OPERAND_TYPE_ID, {message_.global_variable_fresh_id()}}}));
 
@@ -132,13 +133,14 @@
 
   // Update all relevant OpFunctionCall instructions.
   for (auto* inst : fuzzerutil::GetCallers(ir_context, function->result_id())) {
-    assert(fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpStore, inst) &&
-           "Can't insert OpStore right before the function call");
+    assert(
+        fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpStore, inst) &&
+        "Can't insert OpStore right before the function call");
 
     // Insert an OpStore before the OpFunctionCall. +1 since the first
     // operand of OpFunctionCall is an id of the function.
     inst->InsertBefore(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpStore, 0, 0,
+        ir_context, spv::Op::OpStore, 0, 0,
         opt::Instruction::OperandList{
             {SPV_OPERAND_TYPE_ID, {message_.global_variable_fresh_id()}},
             {SPV_OPERAND_TYPE_ID,
diff --git a/source/fuzz/transformation_replace_params_with_struct.cpp b/source/fuzz/transformation_replace_params_with_struct.cpp
index 13eeccb..c8af14a 100644
--- a/source/fuzz/transformation_replace_params_with_struct.cpp
+++ b/source/fuzz/transformation_replace_params_with_struct.cpp
@@ -142,7 +142,7 @@
 
   // Add new parameter to the function.
   function->AddParameter(MakeUnique<opt::Instruction>(
-      ir_context, SpvOpFunctionParameter, struct_type_id,
+      ir_context, spv::Op::OpFunctionParameter, struct_type_id,
       message_.fresh_parameter_id(), opt::Instruction::OperandList()));
 
   fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_parameter_id());
@@ -182,8 +182,8 @@
     auto fresh_composite_id =
         caller_id_to_fresh_composite_id.at(inst->result_id());
     inst->InsertBefore(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpCompositeConstruct, struct_type_id, fresh_composite_id,
-        std::move(composite_components)));
+        ir_context, spv::Op::OpCompositeConstruct, struct_type_id,
+        fresh_composite_id, std::move(composite_components)));
 
     // Add a new operand to the OpFunctionCall instruction.
     inst->AddOperand({SPV_OPERAND_TYPE_ID, {fresh_composite_id}});
@@ -200,19 +200,19 @@
     // Skip all OpVariable instructions.
     auto iter = function->begin()->begin();
     while (iter != function->begin()->end() &&
-           !fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCompositeExtract,
-                                                         iter)) {
+           !fuzzerutil::CanInsertOpcodeBeforeInstruction(
+               spv::Op::OpCompositeExtract, iter)) {
       ++iter;
     }
 
-    assert(fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCompositeExtract,
-                                                        iter) &&
+    assert(fuzzerutil::CanInsertOpcodeBeforeInstruction(
+               spv::Op::OpCompositeExtract, iter) &&
            "Can't extract parameter's value from the structure");
 
     // Insert OpCompositeExtract instructions to unpack parameters' values from
     // the struct type.
     iter.InsertBefore(MakeUnique<opt::Instruction>(
-        ir_context, SpvOpCompositeExtract, param_inst->type_id(),
+        ir_context, spv::Op::OpCompositeExtract, param_inst->type_id(),
         param_inst->result_id(),
         opt::Instruction::OperandList{
             {SPV_OPERAND_TYPE_ID, {message_.fresh_parameter_id()}},
diff --git a/source/fuzz/transformation_set_function_control.cpp b/source/fuzz/transformation_set_function_control.cpp
index 02a8c9f..ef48171 100644
--- a/source/fuzz/transformation_set_function_control.cpp
+++ b/source/fuzz/transformation_set_function_control.cpp
@@ -40,9 +40,9 @@
 
   // Check (via an assertion) that function control mask doesn't have any bad
   // bits set.
-  uint32_t acceptable_function_control_bits =
-      SpvFunctionControlInlineMask | SpvFunctionControlDontInlineMask |
-      SpvFunctionControlPureMask | SpvFunctionControlConstMask;
+  uint32_t acceptable_function_control_bits = uint32_t(
+      spv::FunctionControlMask::Inline | spv::FunctionControlMask::DontInline |
+      spv::FunctionControlMask::Pure | spv::FunctionControlMask::Const);
   // The following is to keep release-mode compilers happy as this variable is
   // only used in an assertion.
   (void)(acceptable_function_control_bits);
@@ -51,17 +51,19 @@
 
   // Check (via an assertion) that function control mask does not have both
   // Inline and DontInline bits set.
-  assert(!((message_.function_control() & SpvFunctionControlInlineMask) &&
-           (message_.function_control() & SpvFunctionControlDontInlineMask)) &&
+  assert(!((message_.function_control() &
+            (uint32_t)spv::FunctionControlMask::Inline) &&
+           (message_.function_control() &
+            (uint32_t)spv::FunctionControlMask::DontInline)) &&
          "It is not OK to set both the 'Inline' and 'DontInline' bits of a "
          "function control mask");
 
   // Check that Const and Pure are only present if they were present on the
   // original function
   for (auto mask_bit :
-       {SpvFunctionControlPureMask, SpvFunctionControlConstMask}) {
-    if ((message_.function_control() & mask_bit) &&
-        !(existing_function_control_mask & mask_bit)) {
+       {spv::FunctionControlMask::Pure, spv::FunctionControlMask::Const}) {
+    if ((message_.function_control() & uint32_t(mask_bit)) &&
+        !(existing_function_control_mask & uint32_t(mask_bit))) {
       return false;
     }
   }
diff --git a/source/fuzz/transformation_set_loop_control.cpp b/source/fuzz/transformation_set_loop_control.cpp
index 1449960..dc9ee7c 100644
--- a/source/fuzz/transformation_set_loop_control.cpp
+++ b/source/fuzz/transformation_set_loop_control.cpp
@@ -38,18 +38,20 @@
     return false;
   }
   auto merge_inst = block->GetMergeInst();
-  if (!merge_inst || merge_inst->opcode() != SpvOpLoopMerge) {
+  if (!merge_inst || merge_inst->opcode() != spv::Op::OpLoopMerge) {
     return false;
   }
 
   // We assert that the transformation does not try to set any meaningless bits
   // of the loop control mask.
-  uint32_t all_loop_control_mask_bits_set =
-      SpvLoopControlUnrollMask | SpvLoopControlDontUnrollMask |
-      SpvLoopControlDependencyInfiniteMask |
-      SpvLoopControlDependencyLengthMask | SpvLoopControlMinIterationsMask |
-      SpvLoopControlMaxIterationsMask | SpvLoopControlIterationMultipleMask |
-      SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask;
+  uint32_t all_loop_control_mask_bits_set = uint32_t(
+      spv::LoopControlMask::Unroll | spv::LoopControlMask::DontUnroll |
+      spv::LoopControlMask::DependencyInfinite |
+      spv::LoopControlMask::DependencyLength |
+      spv::LoopControlMask::MinIterations |
+      spv::LoopControlMask::MaxIterations |
+      spv::LoopControlMask::IterationMultiple |
+      spv::LoopControlMask::PeelCount | spv::LoopControlMask::PartialCount);
 
   // The variable is only used in an assertion; the following keeps release-mode
   // compilers happy.
@@ -65,10 +67,11 @@
 
   // Check that there is no attempt to set one of the loop controls that
   // requires guarantees to hold.
-  for (SpvLoopControlMask mask :
-       {SpvLoopControlDependencyInfiniteMask,
-        SpvLoopControlDependencyLengthMask, SpvLoopControlMinIterationsMask,
-        SpvLoopControlMaxIterationsMask, SpvLoopControlIterationMultipleMask}) {
+  for (spv::LoopControlMask mask : {spv::LoopControlMask::DependencyInfinite,
+                                    spv::LoopControlMask::DependencyLength,
+                                    spv::LoopControlMask::MinIterations,
+                                    spv::LoopControlMask::MaxIterations,
+                                    spv::LoopControlMask::IterationMultiple}) {
     // We have a problem if this loop control bit was not set in the original
     // loop control mask but is set by the transformation.
     if (LoopControlBitIsAddedByTransformation(mask,
@@ -78,33 +81,36 @@
   }
 
   // Check that PeelCount and PartialCount are supported if used.
-  if ((message_.loop_control() & SpvLoopControlPeelCountMask) &&
+  if ((message_.loop_control() & uint32_t(spv::LoopControlMask::PeelCount)) &&
       !PeelCountIsSupported(ir_context)) {
     return false;
   }
 
-  if ((message_.loop_control() & SpvLoopControlPartialCountMask) &&
+  if ((message_.loop_control() &
+       uint32_t(spv::LoopControlMask::PartialCount)) &&
       !PartialCountIsSupported(ir_context)) {
     return false;
   }
 
   if (message_.peel_count() > 0 &&
-      !(message_.loop_control() & SpvLoopControlPeelCountMask)) {
+      !(message_.loop_control() & uint32_t(spv::LoopControlMask::PeelCount))) {
     // Peel count provided, but peel count mask bit not set.
     return false;
   }
 
   if (message_.partial_count() > 0 &&
-      !(message_.loop_control() & SpvLoopControlPartialCountMask)) {
+      !(message_.loop_control() &
+        uint32_t(spv::LoopControlMask::PartialCount))) {
     // Partial count provided, but partial count mask bit not set.
     return false;
   }
 
   // We must not set both 'don't unroll' and one of 'peel count' or 'partial
   // count'.
-  return !((message_.loop_control() & SpvLoopControlDontUnrollMask) &&
-           (message_.loop_control() &
-            (SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask)));
+  return !(
+      (message_.loop_control() & uint32_t(spv::LoopControlMask::DontUnroll)) &&
+      (message_.loop_control() & uint32_t(spv::LoopControlMask::PeelCount |
+                                          spv::LoopControlMask::PartialCount)));
 }
 
 void TransformationSetLoopControl::Apply(
@@ -133,13 +139,14 @@
 
   uint32_t literal_index = 0;  // Indexes into the literals from the original
   // instruction.
-  for (SpvLoopControlMask mask :
-       {SpvLoopControlDependencyLengthMask, SpvLoopControlMinIterationsMask,
-        SpvLoopControlMaxIterationsMask, SpvLoopControlIterationMultipleMask}) {
+  for (spv::LoopControlMask mask : {spv::LoopControlMask::DependencyLength,
+                                    spv::LoopControlMask::MinIterations,
+                                    spv::LoopControlMask::MaxIterations,
+                                    spv::LoopControlMask::IterationMultiple}) {
     // Check whether the bit was set in the original loop control mask.
-    if (existing_loop_control_mask & mask) {
+    if (existing_loop_control_mask & uint32_t(mask)) {
       // Check whether the bit is set in the new loop control mask.
-      if (message_.loop_control() & mask) {
+      if (message_.loop_control() & uint32_t(mask)) {
         // Add the associated literal to our sequence of replacement operands.
         new_operands.push_back(
             {SPV_OPERAND_TYPE_LITERAL_INTEGER,
@@ -154,13 +161,13 @@
 
   // If PeelCount is set in the new mask, |message_.peel_count| provides the
   // associated peel count.
-  if (message_.loop_control() & SpvLoopControlPeelCountMask) {
+  if (message_.loop_control() & uint32_t(spv::LoopControlMask::PeelCount)) {
     new_operands.push_back(
         {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.peel_count()}});
   }
 
   // Similar, but for PartialCount.
-  if (message_.loop_control() & SpvLoopControlPartialCountMask) {
+  if (message_.loop_control() & uint32_t(spv::LoopControlMask::PartialCount)) {
     new_operands.push_back(
         {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.partial_count()}});
   }
@@ -177,10 +184,11 @@
 }
 
 bool TransformationSetLoopControl::LoopControlBitIsAddedByTransformation(
-    SpvLoopControlMask loop_control_single_bit_mask,
+    spv::LoopControlMask loop_control_single_bit_mask,
     uint32_t existing_loop_control_mask) const {
-  return !(loop_control_single_bit_mask & existing_loop_control_mask) &&
-         (loop_control_single_bit_mask & message_.loop_control());
+  return !(uint32_t(loop_control_single_bit_mask) &
+           existing_loop_control_mask) &&
+         (uint32_t(loop_control_single_bit_mask) & message_.loop_control());
 }
 
 bool TransformationSetLoopControl::PartialCountIsSupported(
diff --git a/source/fuzz/transformation_set_loop_control.h b/source/fuzz/transformation_set_loop_control.h
index bc17c8a..d57447b 100644
--- a/source/fuzz/transformation_set_loop_control.h
+++ b/source/fuzz/transformation_set_loop_control.h
@@ -71,7 +71,7 @@
   // Returns true if and only if |loop_single_bit_mask| is *not* set in
   // |existing_loop_control| but *is* set in |message_.loop_control|.
   bool LoopControlBitIsAddedByTransformation(
-      SpvLoopControlMask loop_control_single_bit_mask,
+      spv::LoopControlMask loop_control_single_bit_mask,
       uint32_t existing_loop_control_mask) const;
 
   protobufs::TransformationSetLoopControl message_;
diff --git a/source/fuzz/transformation_set_memory_operands_mask.cpp b/source/fuzz/transformation_set_memory_operands_mask.cpp
index 5a986ad..16d591a 100644
--- a/source/fuzz/transformation_set_memory_operands_mask.cpp
+++ b/source/fuzz/transformation_set_memory_operands_mask.cpp
@@ -48,10 +48,13 @@
     // which they were applied during fuzzing, hence why these are assertions
     // rather than applicability checks.
     assert(message_.memory_operands_mask_index() == 1);
-    assert(message_.memory_access_instruction().target_instruction_opcode() ==
-               SpvOpCopyMemory ||
-           message_.memory_access_instruction().target_instruction_opcode() ==
-               SpvOpCopyMemorySized);
+    assert(
+        spv::Op(
+            message_.memory_access_instruction().target_instruction_opcode()) ==
+            spv::Op::OpCopyMemory ||
+        spv::Op(
+            message_.memory_access_instruction().target_instruction_opcode()) ==
+            spv::Op::OpCopyMemorySized);
     assert(MultipleMemoryOperandMasksAreSupported(ir_context) &&
            "Multiple memory operand masks are not supported for this SPIR-V "
            "version.");
@@ -73,12 +76,12 @@
   uint32_t original_mask =
       original_mask_in_operand_index < instruction->NumInOperands()
           ? instruction->GetSingleWordInOperand(original_mask_in_operand_index)
-          : static_cast<uint32_t>(SpvMemoryAccessMaskNone);
+          : static_cast<uint32_t>(spv::MemoryAccessMask::MaskNone);
   uint32_t new_mask = message_.memory_operands_mask();
 
   // Volatile must not be removed
-  if ((original_mask & SpvMemoryAccessVolatileMask) &&
-      !(new_mask & SpvMemoryAccessVolatileMask)) {
+  if ((original_mask & uint32_t(spv::MemoryAccessMask::Volatile)) &&
+      !(new_mask & uint32_t(spv::MemoryAccessMask::Volatile))) {
     return false;
   }
 
@@ -87,10 +90,10 @@
   // their Volatile and Nontemporal flags to the same value (this works
   // because valid manipulation of Volatile is checked above, and the manner
   // in which Nontemporal is manipulated does not matter).
-  return (original_mask | SpvMemoryAccessVolatileMask |
-          SpvMemoryAccessNontemporalMask) ==
-         (new_mask | SpvMemoryAccessVolatileMask |
-          SpvMemoryAccessNontemporalMask);
+  return (original_mask | uint32_t(spv::MemoryAccessMask::Volatile) |
+          uint32_t(spv::MemoryAccessMask::Nontemporal)) ==
+         (new_mask | uint32_t(spv::MemoryAccessMask::Volatile) |
+          uint32_t(spv::MemoryAccessMask::Nontemporal));
 }
 
 void TransformationSetMemoryOperandsMask::Apply(
@@ -106,8 +109,8 @@
     if (message_.memory_operands_mask_index() == 1 &&
         GetInOperandIndexForMask(*instruction, 0) >=
             instruction->NumInOperands()) {
-      instruction->AddOperand(
-          {SPV_OPERAND_TYPE_MEMORY_ACCESS, {SpvMemoryAccessMaskNone}});
+      instruction->AddOperand({SPV_OPERAND_TYPE_MEMORY_ACCESS,
+                               {uint32_t(spv::MemoryAccessMask::MaskNone)}});
     }
 
     instruction->AddOperand(
@@ -129,10 +132,10 @@
 bool TransformationSetMemoryOperandsMask::IsMemoryAccess(
     const opt::Instruction& instruction) {
   switch (instruction.opcode()) {
-    case SpvOpLoad:
-    case SpvOpStore:
-    case SpvOpCopyMemory:
-    case SpvOpCopyMemorySized:
+    case spv::Op::OpLoad:
+    case spv::Op::OpStore:
+    case spv::Op::OpCopyMemory:
+    case spv::Op::OpCopyMemorySized:
       return true;
     default:
       return false;
@@ -145,16 +148,16 @@
   // for the instruction.
   uint32_t first_mask_in_operand_index = 0;
   switch (instruction.opcode()) {
-    case SpvOpLoad:
+    case spv::Op::OpLoad:
       first_mask_in_operand_index = kOpLoadMemoryOperandsMaskIndex;
       break;
-    case SpvOpStore:
+    case spv::Op::OpStore:
       first_mask_in_operand_index = kOpStoreMemoryOperandsMaskIndex;
       break;
-    case SpvOpCopyMemory:
+    case spv::Op::OpCopyMemory:
       first_mask_in_operand_index = kOpCopyMemoryFirstMemoryOperandsMaskIndex;
       break;
-    case SpvOpCopyMemorySized:
+    case spv::Op::OpCopyMemorySized:
       first_mask_in_operand_index =
           kOpCopyMemorySizedFirstMemoryOperandsMaskIndex;
       break;
@@ -192,12 +195,12 @@
   // Consider each bit that might have an associated extra input operand, and
   // count how many there are expected to be.
   uint32_t first_mask_extra_operand_count = 0;
-  for (auto mask_bit :
-       {SpvMemoryAccessAlignedMask, SpvMemoryAccessMakePointerAvailableMask,
-        SpvMemoryAccessMakePointerAvailableKHRMask,
-        SpvMemoryAccessMakePointerVisibleMask,
-        SpvMemoryAccessMakePointerVisibleKHRMask}) {
-    if (first_mask & mask_bit) {
+  for (auto mask_bit : {spv::MemoryAccessMask::Aligned,
+                        spv::MemoryAccessMask::MakePointerAvailable,
+                        spv::MemoryAccessMask::MakePointerAvailableKHR,
+                        spv::MemoryAccessMask::MakePointerVisible,
+                        spv::MemoryAccessMask::MakePointerVisibleKHR}) {
+    if (first_mask & uint32_t(mask_bit)) {
       first_mask_extra_operand_count++;
     }
   }
diff --git a/source/fuzz/transformation_set_selection_control.cpp b/source/fuzz/transformation_set_selection_control.cpp
index 6dddbdf..c6f68d9 100644
--- a/source/fuzz/transformation_set_selection_control.cpp
+++ b/source/fuzz/transformation_set_selection_control.cpp
@@ -29,14 +29,17 @@
 
 bool TransformationSetSelectionControl::IsApplicable(
     opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
-  assert((message_.selection_control() == SpvSelectionControlMaskNone ||
-          message_.selection_control() == SpvSelectionControlFlattenMask ||
-          message_.selection_control() == SpvSelectionControlDontFlattenMask) &&
+  assert((spv::SelectionControlMask(message_.selection_control()) ==
+              spv::SelectionControlMask::MaskNone ||
+          spv::SelectionControlMask(message_.selection_control()) ==
+              spv::SelectionControlMask::Flatten ||
+          spv::SelectionControlMask(message_.selection_control()) ==
+              spv::SelectionControlMask::DontFlatten) &&
          "Selection control should never be set to something other than "
          "'None', 'Flatten' or 'DontFlatten'");
   if (auto block = ir_context->get_instr_block(message_.block_id())) {
     if (auto merge_inst = block->GetMergeInst()) {
-      return merge_inst->opcode() == SpvOpSelectionMerge;
+      return merge_inst->opcode() == spv::Op::OpSelectionMerge;
     }
   }
   // Either the block did not exit, or did not end with OpSelectionMerge.
diff --git a/source/fuzz/transformation_split_block.cpp b/source/fuzz/transformation_split_block.cpp
index e15dffa..959bedc 100644
--- a/source/fuzz/transformation_split_block.cpp
+++ b/source/fuzz/transformation_split_block.cpp
@@ -64,19 +64,19 @@
          " block split point exists.");
 
   if (split_before->PreviousNode() &&
-      split_before->PreviousNode()->opcode() == SpvOpSelectionMerge) {
+      split_before->PreviousNode()->opcode() == spv::Op::OpSelectionMerge) {
     // We cannot split directly after a selection merge: this would separate
     // the merge from its associated branch or switch operation.
     return false;
   }
-  if (split_before->opcode() == SpvOpVariable) {
+  if (split_before->opcode() == spv::Op::OpVariable) {
     // We cannot split directly after a variable; variables in a function
     // must be contiguous in the entry block.
     return false;
   }
   // We cannot split before an OpPhi unless the OpPhi has exactly one
   // associated incoming edge.
-  if (split_before->opcode() == SpvOpPhi &&
+  if (split_before->opcode() == spv::Op::OpPhi &&
       split_before->NumInOperands() != 2) {
     return false;
   }
@@ -110,7 +110,7 @@
   // The split does not automatically add a branch between the two parts of
   // the original block, so we add one.
   auto branch_instruction = MakeUnique<opt::Instruction>(
-      ir_context, SpvOpBranch, 0, 0,
+      ir_context, spv::Op::OpBranch, 0, 0,
       std::initializer_list<opt::Operand>{opt::Operand(
           spv_operand_type_t::SPV_OPERAND_TYPE_ID, {message_.fresh_id()})});
   auto branch_instruction_ptr = branch_instruction.get();
diff --git a/source/fuzz/transformation_store.cpp b/source/fuzz/transformation_store.cpp
index c00cd34..6ba1c55 100644
--- a/source/fuzz/transformation_store.cpp
+++ b/source/fuzz/transformation_store.cpp
@@ -48,7 +48,7 @@
   // The pointer type must indeed be a pointer.
   auto pointer_type = ir_context->get_def_use_mgr()->GetDef(pointer->type_id());
   assert(pointer_type && "Type id must be defined.");
-  if (pointer_type->opcode() != SpvOpTypePointer) {
+  if (pointer_type->opcode() != spv::Op::OpTypePointer) {
     return false;
   }
 
@@ -59,8 +59,8 @@
 
   // We do not want to allow storing to null or undefined pointers.
   switch (pointer->opcode()) {
-    case SpvOpConstantNull:
-    case SpvOpUndef:
+    case spv::Op::OpConstantNull:
+    case spv::Op::OpUndef:
       return false;
     default:
       break;
@@ -75,11 +75,11 @@
   }
   // ... and it must be legitimate to insert a store before it.
   if (!message_.is_atomic() && !fuzzerutil::CanInsertOpcodeBeforeInstruction(
-                                   SpvOpStore, insert_before)) {
+                                   spv::Op::OpStore, insert_before)) {
     return false;
   }
   if (message_.is_atomic() && !fuzzerutil::CanInsertOpcodeBeforeInstruction(
-                                  SpvOpAtomicStore, insert_before)) {
+                                  spv::Op::OpAtomicStore, insert_before)) {
     return false;
   }
 
@@