Started on new transformation.
diff --git a/source/fuzz/CMakeLists.txt b/source/fuzz/CMakeLists.txt
index bc7d453..82920da 100644
--- a/source/fuzz/CMakeLists.txt
+++ b/source/fuzz/CMakeLists.txt
@@ -36,6 +36,7 @@
         fuzzer.h
         fuzzer_context.h
         fuzzer_pass.h
+        fuzzer_pass_add_dead_blocks.h
         fuzzer_pass_add_dead_breaks.h
         fuzzer_pass_add_dead_continues.h
         fuzzer_pass_add_no_contraction_decorations.h
@@ -65,6 +66,7 @@
         transformation_add_constant_boolean.h
         transformation_add_constant_composite.h
         transformation_add_constant_scalar.h
+        transformation_add_dead_block.h
         transformation_add_dead_break.h
         transformation_add_dead_continue.h
         transformation_add_function.h
@@ -104,6 +106,7 @@
         fuzzer.cpp
         fuzzer_context.cpp
         fuzzer_pass.cpp
+        fuzzer_pass_add_dead_blocks.cpp
         fuzzer_pass_add_dead_breaks.cpp
         fuzzer_pass_add_dead_continues.cpp
         fuzzer_pass_add_no_contraction_decorations.cpp
@@ -132,6 +135,7 @@
         transformation_add_constant_boolean.cpp
         transformation_add_constant_composite.cpp
         transformation_add_constant_scalar.cpp
+        transformation_add_dead_block.cpp
         transformation_add_dead_break.cpp
         transformation_add_dead_continue.cpp
         transformation_add_function.cpp
diff --git a/source/fuzz/fuzzer_pass_add_dead_blocks.cpp b/source/fuzz/fuzzer_pass_add_dead_blocks.cpp
new file mode 100644
index 0000000..f964146
--- /dev/null
+++ b/source/fuzz/fuzzer_pass_add_dead_blocks.cpp
@@ -0,0 +1,33 @@
+// Copyright (c) 2019 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/fuzz/fuzzer_pass_add_dead_blocks.h"
+
+namespace spvtools {
+namespace fuzz {
+
+FuzzerPassAddDeadBlocks::FuzzerPassAddDeadBlocks(
+    opt::IRContext* ir_context, FactManager* fact_manager,
+    FuzzerContext* fuzzer_context,
+    protobufs::TransformationSequence* transformations)
+    : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {}
+
+FuzzerPassAddDeadBlocks::~FuzzerPassAddDeadBlocks() = default;
+
+void FuzzerPassAddDeadBlocks::Apply() {
+  assert(false && "Implement");
+}
+
+}  // namespace fuzz
+}  // namespace spvtools
diff --git a/source/fuzz/fuzzer_pass_add_dead_blocks.h b/source/fuzz/fuzzer_pass_add_dead_blocks.h
new file mode 100644
index 0000000..0577151
--- /dev/null
+++ b/source/fuzz/fuzzer_pass_add_dead_blocks.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2019 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_BLOCKS_H_
+#define SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_BLOCKS_H_
+
+#include "source/fuzz/fuzzer_pass.h"
+
+namespace spvtools {
+namespace fuzz {
+
+// TODO comment
+class FuzzerPassAddDeadBlocks : public FuzzerPass {
+ public:
+  FuzzerPassAddDeadBlocks(opt::IRContext* ir_context, FactManager* fact_manager,
+                        FuzzerContext* fuzzer_context,
+                        protobufs::TransformationSequence* transformations);
+
+  ~FuzzerPassAddDeadBlocks();
+
+  void Apply() override;
+};
+
+}  // namespace fuzz
+}  // namespace spvtools
+
+#endif  // SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_BLOCKS_H_
diff --git a/source/fuzz/fuzzer_util.cpp b/source/fuzz/fuzzer_util.cpp
index 1c39da0..a6e3657 100644
--- a/source/fuzz/fuzzer_util.cpp
+++ b/source/fuzz/fuzzer_util.cpp
@@ -109,6 +109,19 @@
   return phi_index == static_cast<uint32_t>(phi_ids.size());
 }
 
+uint32_t MaybeGetBoolConstantId(opt::IRContext* context, bool value) {
+  opt::analysis::Bool bool_type;
+  auto registered_bool_type =
+          context->get_type_mgr()->GetRegisteredType(&bool_type);
+  if (!registered_bool_type) {
+    return 0;
+  }
+  opt::analysis::BoolConstant bool_constant(registered_bool_type->AsBool(),
+          value);
+  return context->get_constant_mgr()->FindDeclaredConstant(
+          &bool_constant, context->get_type_mgr()->GetId(&bool_type));
+}
+
 void AddUnreachableEdgeAndUpdateOpPhis(
     opt::IRContext* context, opt::BasicBlock* bb_from, opt::BasicBlock* bb_to,
     bool condition_value,
@@ -119,12 +132,8 @@
          "Precondition on terminator of bb_from is not satisfied");
 
   // Get the id of the boolean constant to be used as the condition.
-  opt::analysis::Bool bool_type;
-  opt::analysis::BoolConstant bool_constant(
-      context->get_type_mgr()->GetRegisteredType(&bool_type)->AsBool(),
-      condition_value);
-  uint32_t bool_id = context->get_constant_mgr()->FindDeclaredConstant(
-      &bool_constant, context->get_type_mgr()->GetId(&bool_type));
+  uint32_t bool_id = MaybeGetBoolConstantId(context, condition_value);
+  assert(bool_id && "Precondition that condition value must be available is not satisfied");
 
   const bool from_to_edge_already_exists = bb_from->IsSuccessor(bb_to);
   auto successor = bb_from->terminator()->GetSingleWordInOperand(0);
@@ -302,7 +311,8 @@
 bool IsValid(opt::IRContext* context) {
   std::vector<uint32_t> binary;
   context->module()->ToBinary(&binary, false);
-  return SpirvTools(context->grammar().target_env()).Validate(binary);
+  SpirvTools tools(context->grammar().target_env());
+  return tools.Validate(binary);
 }
 
 std::unique_ptr<opt::IRContext> CloneIRContext(opt::IRContext* context) {
@@ -317,6 +327,25 @@
   return type && !type->AsFunction();
 }
 
+bool IsMergeOrContinue(opt::IRContext* ir_context, uint32_t block_id) {
+  bool result = false;
+  ir_context->get_def_use_mgr()->WhileEachUse(
+          block_id,
+          [&result](
+                  const opt::Instruction* use_instruction,
+                  uint32_t /*unused*/) -> bool {
+              switch (use_instruction->opcode()) {
+                case SpvOpLoopMerge:
+                case SpvOpSelectionMerge:
+                  result = true;
+                  return false;
+                default:
+                  return true;
+              }
+          });
+  return result;
+}
+
 }  // namespace fuzzerutil
 
 }  // namespace fuzz
diff --git a/source/fuzz/fuzzer_util.h b/source/fuzz/fuzzer_util.h
index af3eb1b..dc477b7 100644
--- a/source/fuzz/fuzzer_util.h
+++ b/source/fuzz/fuzzer_util.h
@@ -49,8 +49,13 @@
     opt::IRContext* context, opt::BasicBlock* bb_from, opt::BasicBlock* bb_to,
     const google::protobuf::RepeatedField<google::protobuf::uint32>& phi_ids);
 
-// Requires that PhiIdsOkForNewEdge(context, bb_from, bb_to, phi_ids) holds,
-// and that bb_from ends with "OpBranch %some_block".  Turns OpBranch into
+// Returns the id of a boolean constant with value |value| if it exists in the
+// module, or 0 otherwise.
+uint32_t MaybeGetBoolConstantId(opt::IRContext* context, bool value);
+
+// Requires that a boolean constant with value |condition_value| is available,
+// that PhiIdsOkForNewEdge(context, bb_from, bb_to, phi_ids) holds, and that
+// bb_from ends with "OpBranch %some_block".  Turns OpBranch into
 // "OpBranchConditional |condition_value| ...", such that control will branch
 // to %some_block, with |bb_to| being the unreachable alternative.  Updates
 // OpPhi instructions in |bb_to| using |phi_ids| so that the new edge is valid.
@@ -120,6 +125,9 @@
 // type.
 bool IsNonFunctionTypeId(opt::IRContext* ir_context, uint32_t id);
 
+// Returns true if and only if |block_id| is a merge block or continue target
+bool IsMergeOrContinue(opt::IRContext* ir_context, uint32_t block_id);
+
 }  // namespace fuzzerutil
 
 }  // namespace fuzz
diff --git a/source/fuzz/protobufs/spvtoolsfuzz.proto b/source/fuzz/protobufs/spvtoolsfuzz.proto
index dbd1fb8..ef8074e 100644
--- a/source/fuzz/protobufs/spvtoolsfuzz.proto
+++ b/source/fuzz/protobufs/spvtoolsfuzz.proto
@@ -242,6 +242,7 @@
     TransformationAddGlobalVariable add_global_variable = 31;
     TransformationAddGlobalUndef add_global_undef = 32;
     TransformationAddFunction add_function = 33;
+    TransformationAddDeadBlock add_dead_block = 34;
     // Add additional option using the next available number.
   }
 }
@@ -275,7 +276,7 @@
 
 message TransformationAddConstantScalar {
 
-  // Adds a constant of the given scalar type
+  // Adds a constant of the given scalar type.
 
   // Id for the constant
   uint32 fresh_id = 1;
@@ -288,6 +289,29 @@
 
 }
 
+message TransformationAddDeadBlock {
+
+  // Adds a new block to the module that is statically reachable from an
+  // existing block, but dynamically unreachable.
+
+  // Fresh id for the dead block
+  uint32 fresh_id = 1;
+
+  // Id of an existing block terminated with OpBranch, such that this OpBranch
+  // can be replaced with an OpBranchConditional to its exiting successor or
+  // the dead block
+  uint32 existing_block = 2;
+
+  // Determines whether the condition associated with the OpBranchConditional
+  // is true or false
+  bool condition_value = 3;
+
+  // A sequence of ids suitable for extending OpPhi instructions at the
+  // successor of |existing_block| as a result of adding a new edge
+  repeated uint32 phi_id = 4;
+
+}
+
 message TransformationAddDeadBreak {
 
   // A transformation that turns a basic block that unconditionally branches to
diff --git a/source/fuzz/transformation.cpp b/source/fuzz/transformation.cpp
index 1489f85..3f5375e 100644
--- a/source/fuzz/transformation.cpp
+++ b/source/fuzz/transformation.cpp
@@ -19,6 +19,7 @@
 #include "source/fuzz/transformation_add_constant_boolean.h"
 #include "source/fuzz/transformation_add_constant_composite.h"
 #include "source/fuzz/transformation_add_constant_scalar.h"
+#include "source/fuzz/transformation_add_dead_block.h"
 #include "source/fuzz/transformation_add_dead_break.h"
 #include "source/fuzz/transformation_add_dead_continue.h"
 #include "source/fuzz/transformation_add_function.h"
@@ -68,6 +69,9 @@
     case protobufs::Transformation::TransformationCase::kAddConstantScalar:
       return MakeUnique<TransformationAddConstantScalar>(
           message.add_constant_scalar());
+    case protobufs::Transformation::TransformationCase::kAddDeadBlock:
+      return MakeUnique<TransformationAddDeadBlock>(
+          message.add_dead_block());
     case protobufs::Transformation::TransformationCase::kAddDeadBreak:
       return MakeUnique<TransformationAddDeadBreak>(message.add_dead_break());
     case protobufs::Transformation::TransformationCase::kAddDeadContinue:
diff --git a/source/fuzz/transformation_add_dead_block.cpp b/source/fuzz/transformation_add_dead_block.cpp
new file mode 100644
index 0000000..ff9cebc
--- /dev/null
+++ b/source/fuzz/transformation_add_dead_block.cpp
@@ -0,0 +1,107 @@
+// Copyright (c) 2019 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/fuzz/transformation_add_dead_block.h"
+
+#include "source/fuzz/fuzzer_util.h"
+
+namespace spvtools {
+namespace fuzz {
+
+TransformationAddDeadBlock::TransformationAddDeadBlock(
+    const spvtools::fuzz::protobufs::TransformationAddDeadBlock& message)
+    : message_(message) {}
+
+TransformationAddDeadBlock::TransformationAddDeadBlock(
+        uint32_t fresh_id, uint32_t existing_block,
+bool condition_value,
+        std::vector<uint32_t> phi_id) {
+  message_.set_fresh_id(fresh_id);
+  message_.set_existing_block(existing_block);
+  message_.set_condition_value(condition_value);
+  for (auto id : phi_id) {
+    message_.add_phi_id(id);
+  }
+}
+
+bool TransformationAddDeadBlock::IsApplicable(
+    opt::IRContext* context,
+    const spvtools::fuzz::FactManager& /*unused*/) const {
+  // The new block's id must be fresh.
+  if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
+    return false;
+  }
+
+  // First, we check that a constant with the same value as
+  // |message_.condition_value| is present.
+  if (!fuzzerutil::MaybeGetBoolConstantId(context, message_.condition_value())) {
+    // The required constant is not present, so the transformation cannot be
+    // applied.
+    return false;
+  }
+
+  // The existing block must indeed exist.
+  auto existing_block = fuzzerutil::MaybeFindBlock(context, message_.existing_block());
+  if (!existing_block) {
+    return false;
+  }
+
+  // It must not head a loop.
+  if (existing_block->IsLoopHeader()) {
+    return false;
+  }
+
+  // It must end with OpBranch.
+  if (existing_block->terminator()->opcode() != SpvOpBranch) {
+    return false;
+  }
+
+  // Its successor must not be a merge block nor continue target.
+  if (fuzzerutil::IsMergeOrContinue(context, existing_block->terminator()->GetSingleWordInOperand(0))) {
+    return false;
+  }
+  return true;
+}
+
+void TransformationAddDeadBlock::Apply(
+    opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const {
+  // TODO comment
+  fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
+  auto existing_block = context->cfg()->block(message_.existing_block());
+  auto successor_block_id = existing_block->terminator()->GetSingleWordInOperand(0);
+  auto bool_id = fuzzerutil::MaybeGetBoolConstantId(context, message_.condition_value());
+
+  auto enclosing_function = existing_block->GetParent();
+  std::unique_ptr<opt::BasicBlock> new_block =
+          MakeUnique<opt::BasicBlock>(MakeUnique<opt::Instruction>(
+                  context, SpvOpLabel, 0, message_.fresh_id(), opt::Instruction::OperandList()));
+  new_block->SetParent(enclosing_function);
+  new_block->AddInstruction(MakeUnique<opt::Instruction>(context, SpvOpBranch, 0, 0, opt::Instruction::OperandList({{SPV_OPERAND_TYPE_ID, {successor_block_id}}})));
+  existing_block->terminator()->SetOpcode(SpvOpBranchConditional);
+  existing_block->terminator()->SetInOperands(
+          {{SPV_OPERAND_TYPE_ID, {bool_id}},
+           {SPV_OPERAND_TYPE_ID, {message_.condition_value() ? successor_block_id : message_.fresh_id()}},
+           {SPV_OPERAND_TYPE_ID, {message_.condition_value() ? message_.fresh_id() : successor_block_id}}});
+  enclosing_function->InsertBasicBlockAfter(std::move(new_block), existing_block);
+  context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
+}
+
+protobufs::Transformation TransformationAddDeadBlock::ToMessage() const {
+  protobufs::Transformation result;
+  *result.mutable_add_dead_block() = message_;
+  return result;
+}
+
+}  // namespace fuzz
+}  // namespace spvtools
diff --git a/source/fuzz/transformation_add_dead_block.h b/source/fuzz/transformation_add_dead_block.h
new file mode 100644
index 0000000..203b9a9
--- /dev/null
+++ b/source/fuzz/transformation_add_dead_block.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2019 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_BLOCK_H_
+#define SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_BLOCK_H_
+
+#include "source/fuzz/fact_manager.h"
+#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
+#include "source/opt/ir_context.h"
+
+namespace spvtools {
+namespace fuzz {
+
+class TransformationAddDeadBlock : public Transformation {
+ public:
+  explicit TransformationAddDeadBlock(
+      const protobufs::TransformationAddDeadBlock& message);
+
+  TransformationAddDeadBlock(uint32_t fresh_id,
+                             uint32_t existing_block,
+                             bool condition_value,
+                             std::vector<uint32_t> phi_id);
+
+  // TODO comment
+  bool IsApplicable(opt::IRContext* context,
+                    const FactManager& fact_manager) const override;
+
+  // TODO comment
+  void Apply(opt::IRContext* context, FactManager* fact_manager) const override;
+
+  protobufs::Transformation ToMessage() const override;
+
+ private:
+  protobufs::TransformationAddDeadBlock message_;
+};
+
+}  // namespace fuzz
+}  // namespace spvtools
+
+#endif  // SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_BLOCK_H_
diff --git a/source/fuzz/transformation_add_dead_break.cpp b/source/fuzz/transformation_add_dead_break.cpp
index a37100b..9fa2df6 100644
--- a/source/fuzz/transformation_add_dead_break.cpp
+++ b/source/fuzz/transformation_add_dead_break.cpp
@@ -111,15 +111,7 @@
     opt::IRContext* context, const FactManager& /*unused*/) const {
   // First, we check that a constant with the same value as
   // |message_.break_condition_value| is present.
-  opt::analysis::Bool bool_type;
-  auto registered_bool_type =
-      context->get_type_mgr()->GetRegisteredType(&bool_type);
-  if (!registered_bool_type) {
-    return false;
-  }
-  opt::analysis::BoolConstant bool_constant(registered_bool_type->AsBool(),
-                                            message_.break_condition_value());
-  if (!context->get_constant_mgr()->FindConstant(&bool_constant)) {
+  if (!fuzzerutil::MaybeGetBoolConstantId(context, message_.break_condition_value())) {
     // The required constant is not present, so the transformation cannot be
     // applied.
     return false;
diff --git a/source/fuzz/transformation_add_dead_continue.cpp b/source/fuzz/transformation_add_dead_continue.cpp
index 0aacc5b..b614a23 100644
--- a/source/fuzz/transformation_add_dead_continue.cpp
+++ b/source/fuzz/transformation_add_dead_continue.cpp
@@ -37,15 +37,7 @@
     opt::IRContext* context, const FactManager& /*unused*/) const {
   // First, we check that a constant with the same value as
   // |message_.continue_condition_value| is present.
-  opt::analysis::Bool bool_type;
-  auto registered_bool_type =
-      context->get_type_mgr()->GetRegisteredType(&bool_type);
-  if (!registered_bool_type) {
-    return false;
-  }
-  opt::analysis::BoolConstant bool_constant(
-      registered_bool_type->AsBool(), message_.continue_condition_value());
-  if (!context->get_constant_mgr()->FindConstant(&bool_constant)) {
+  if (!fuzzerutil::MaybeGetBoolConstantId(context, message_.continue_condition_value())) {
     // The required constant is not present, so the transformation cannot be
     // applied.
     return false;
diff --git a/source/fuzz/transformation_outline_function.cpp b/source/fuzz/transformation_outline_function.cpp
index 1d1d48e..1937f24 100644
--- a/source/fuzz/transformation_outline_function.cpp
+++ b/source/fuzz/transformation_outline_function.cpp
@@ -151,22 +151,7 @@
 
   // For simplicity, we do not allow the exit block to be a merge block or
   // continue target.
-  bool exit_block_is_merge_or_continue = false;
-  context->get_def_use_mgr()->WhileEachUse(
-      exit_block->id(),
-      [&exit_block_is_merge_or_continue](
-          const opt::Instruction* use_instruction,
-          uint32_t /*unused*/) -> bool {
-        switch (use_instruction->opcode()) {
-          case SpvOpLoopMerge:
-          case SpvOpSelectionMerge:
-            exit_block_is_merge_or_continue = true;
-            return false;
-          default:
-            return true;
-        }
-      });
-  if (exit_block_is_merge_or_continue) {
+  if (fuzzerutil::IsMergeOrContinue(context, exit_block->id())) {
     return false;
   }
 
diff --git a/test/fuzz/CMakeLists.txt b/test/fuzz/CMakeLists.txt
index fb9e964..998754d 100644
--- a/test/fuzz/CMakeLists.txt
+++ b/test/fuzz/CMakeLists.txt
@@ -26,6 +26,7 @@
           transformation_add_constant_boolean_test.cpp
           transformation_add_constant_composite_test.cpp
           transformation_add_constant_scalar_test.cpp
+          transformation_add_dead_block_test.cpp
           transformation_add_dead_break_test.cpp
           transformation_add_dead_continue_test.cpp
           transformation_add_global_undef_test.cpp
diff --git a/test/fuzz/fuzz_test_util.cpp b/test/fuzz/fuzz_test_util.cpp
index 1d15ad6..c717961 100644
--- a/test/fuzz/fuzz_test_util.cpp
+++ b/test/fuzz/fuzz_test_util.cpp
@@ -76,6 +76,7 @@
   std::vector<uint32_t> binary;
   ir->module()->ToBinary(&binary, false);
   SpirvTools t(env);
+  t.SetMessageConsumer(kConsoleMessageConsumer);
   return t.Validate(binary);
 }
 
diff --git a/test/fuzz/transformation_add_dead_block_test.cpp b/test/fuzz/transformation_add_dead_block_test.cpp
new file mode 100644
index 0000000..1044647
--- /dev/null
+++ b/test/fuzz/transformation_add_dead_block_test.cpp
@@ -0,0 +1,94 @@
+// Copyright (c) 2019 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/fuzz/transformation_add_dead_block.h"
+#include "test/fuzz/fuzz_test_util.h"
+
+namespace spvtools {
+namespace fuzz {
+namespace {
+
+TEST(TransformationAddDeadBlockTest, BasicTest) {
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main"
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeBool
+          %7 = OpConstantTrue %6
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+               OpBranch %8
+          %8 = OpLabel
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_4;
+  const auto consumer = nullptr;
+  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  ASSERT_TRUE(IsValid(env, context.get()));
+
+  FactManager fact_manager;
+
+  // Id 4 is already in use
+  ASSERT_FALSE(TransformationAddDeadBlock(4, 5, true, {}).IsApplicable(context.get(), fact_manager));
+
+  // Id 7 is not a block
+  ASSERT_FALSE(TransformationAddDeadBlock(100, 7, true, {}).IsApplicable(context.get(), fact_manager));
+
+  TransformationAddDeadBlock transformation(100, 5, true, {});
+  ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager));
+  transformation.Apply(context.get(), &fact_manager);
+  ASSERT_TRUE(IsValid(env, context.get()));
+
+  std::string after_transformation = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main"
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeBool
+          %7 = OpConstantTrue %6
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+               OpSelectionMerge %8
+               OpBranchConditional %7 %8 %100
+        %100 = OpLabel
+               OpBranch %8
+          %8 = OpLabel
+               OpReturn
+               OpFunctionEnd
+  )";
+  ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
+}
+
+// Target block must not be merge or continue
+
+// Source block must not be loop head
+
+// Target block can start with OpPhi; need to give suitable ids in that case
+
+}  // namespace
+}  // namespace fuzz
+}  // namespace spvtools