Import Tint changes from Dawn

Changes:
  - 2b7406ad55581d2078aeb484a801cb348ade6323 [tint] Remove ast:: prefixes from AST transforms by James Price <jrprice@google.com>
  - b4acbb8bb096551f251cfa8533f21808527ce459 [tint] Introduce an ast::transform namespace by James Price <jrprice@google.com>
  - 7d2e204911bad07e2c1dba9eaaf1f55ad4f700a2 [tint] Move AST transforms to a subdirectory by James Price <jrprice@google.com>
  - f7a4d9fe5987c68f5d611038b2ddbaa75646c83d [tint] Change ast::builtin::test to ast::test by James Price <jrprice@google.com>
  - fd60f172367e8021c757110a6e3a4c086201fc17 [ir][spirv-writer] Fail when errors are present by James Price <jrprice@google.com>
GitOrigin-RevId: 2b7406ad55581d2078aeb484a801cb348ade6323
Change-Id: Ib02c574ebb416754337ba78cdcf9de9587354ea0
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/132503
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/include/tint/tint.h b/include/tint/tint.h
index 0c1c4d9..b5402b0 100644
--- a/include/tint/tint.h
+++ b/include/tint/tint.h
@@ -21,15 +21,15 @@
 // TODO(tint:88): When implementing support for an install target, all of these
 //                headers will need to be moved to include/tint/.
 
+#include "src/tint/ast/transform/first_index_offset.h"
+#include "src/tint/ast/transform/renamer.h"
+#include "src/tint/ast/transform/single_entry_point.h"
+#include "src/tint/ast/transform/substitute_override.h"
+#include "src/tint/ast/transform/vertex_pulling.h"
 #include "src/tint/diagnostic/printer.h"
 #include "src/tint/inspector/inspector.h"
 #include "src/tint/reader/reader.h"
-#include "src/tint/transform/first_index_offset.h"
 #include "src/tint/transform/manager.h"
-#include "src/tint/transform/renamer.h"
-#include "src/tint/transform/single_entry_point.h"
-#include "src/tint/transform/substitute_override.h"
-#include "src/tint/transform/vertex_pulling.h"
 #include "src/tint/type/manager.h"
 #include "src/tint/utils/unicode.h"
 #include "src/tint/writer/array_length_from_uniform_options.h"
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index 0a6f186..5d04077 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -356,108 +356,108 @@
 
 libtint_source_set("libtint_transform_src") {
   sources = [
-    "transform/add_block_attribute.cc",
-    "transform/add_block_attribute.h",
-    "transform/add_empty_entry_point.cc",
-    "transform/add_empty_entry_point.h",
-    "transform/array_length_from_uniform.cc",
-    "transform/array_length_from_uniform.h",
-    "transform/binding_remapper.cc",
-    "transform/binding_remapper.h",
-    "transform/builtin_polyfill.cc",
-    "transform/builtin_polyfill.h",
-    "transform/calculate_array_length.cc",
-    "transform/calculate_array_length.h",
-    "transform/canonicalize_entry_point_io.cc",
-    "transform/canonicalize_entry_point_io.h",
-    "transform/clamp_frag_depth.cc",
-    "transform/clamp_frag_depth.h",
-    "transform/combine_samplers.cc",
-    "transform/combine_samplers.h",
-    "transform/decompose_memory_access.cc",
-    "transform/decompose_memory_access.h",
-    "transform/decompose_strided_array.cc",
-    "transform/decompose_strided_array.h",
-    "transform/decompose_strided_matrix.cc",
-    "transform/decompose_strided_matrix.h",
-    "transform/demote_to_helper.cc",
-    "transform/demote_to_helper.h",
-    "transform/direct_variable_access.cc",
-    "transform/direct_variable_access.h",
-    "transform/disable_uniformity_analysis.cc",
-    "transform/disable_uniformity_analysis.h",
-    "transform/expand_compound_assignment.cc",
-    "transform/expand_compound_assignment.h",
-    "transform/first_index_offset.cc",
-    "transform/first_index_offset.h",
-    "transform/for_loop_to_loop.cc",
-    "transform/for_loop_to_loop.h",
-    "transform/localize_struct_array_assignment.cc",
-    "transform/localize_struct_array_assignment.h",
+    "ast/transform/add_block_attribute.cc",
+    "ast/transform/add_block_attribute.h",
+    "ast/transform/add_empty_entry_point.cc",
+    "ast/transform/add_empty_entry_point.h",
+    "ast/transform/array_length_from_uniform.cc",
+    "ast/transform/array_length_from_uniform.h",
+    "ast/transform/binding_remapper.cc",
+    "ast/transform/binding_remapper.h",
+    "ast/transform/builtin_polyfill.cc",
+    "ast/transform/builtin_polyfill.h",
+    "ast/transform/calculate_array_length.cc",
+    "ast/transform/calculate_array_length.h",
+    "ast/transform/canonicalize_entry_point_io.cc",
+    "ast/transform/canonicalize_entry_point_io.h",
+    "ast/transform/clamp_frag_depth.cc",
+    "ast/transform/clamp_frag_depth.h",
+    "ast/transform/combine_samplers.cc",
+    "ast/transform/combine_samplers.h",
+    "ast/transform/decompose_memory_access.cc",
+    "ast/transform/decompose_memory_access.h",
+    "ast/transform/decompose_strided_array.cc",
+    "ast/transform/decompose_strided_array.h",
+    "ast/transform/decompose_strided_matrix.cc",
+    "ast/transform/decompose_strided_matrix.h",
+    "ast/transform/demote_to_helper.cc",
+    "ast/transform/demote_to_helper.h",
+    "ast/transform/direct_variable_access.cc",
+    "ast/transform/direct_variable_access.h",
+    "ast/transform/disable_uniformity_analysis.cc",
+    "ast/transform/disable_uniformity_analysis.h",
+    "ast/transform/expand_compound_assignment.cc",
+    "ast/transform/expand_compound_assignment.h",
+    "ast/transform/first_index_offset.cc",
+    "ast/transform/first_index_offset.h",
+    "ast/transform/for_loop_to_loop.cc",
+    "ast/transform/for_loop_to_loop.h",
+    "ast/transform/localize_struct_array_assignment.cc",
+    "ast/transform/localize_struct_array_assignment.h",
+    "ast/transform/merge_return.cc",
+    "ast/transform/merge_return.h",
+    "ast/transform/module_scope_var_to_entry_point_param.cc",
+    "ast/transform/module_scope_var_to_entry_point_param.h",
+    "ast/transform/multiplanar_external_texture.cc",
+    "ast/transform/multiplanar_external_texture.h",
+    "ast/transform/num_workgroups_from_uniform.cc",
+    "ast/transform/num_workgroups_from_uniform.h",
+    "ast/transform/packed_vec3.cc",
+    "ast/transform/packed_vec3.h",
+    "ast/transform/pad_structs.cc",
+    "ast/transform/pad_structs.h",
+    "ast/transform/preserve_padding.cc",
+    "ast/transform/preserve_padding.h",
+    "ast/transform/promote_initializers_to_let.cc",
+    "ast/transform/promote_initializers_to_let.h",
+    "ast/transform/promote_side_effects_to_decl.cc",
+    "ast/transform/promote_side_effects_to_decl.h",
+    "ast/transform/remove_continue_in_switch.cc",
+    "ast/transform/remove_continue_in_switch.h",
+    "ast/transform/remove_phonies.cc",
+    "ast/transform/remove_phonies.h",
+    "ast/transform/remove_unreachable_statements.cc",
+    "ast/transform/remove_unreachable_statements.h",
+    "ast/transform/renamer.cc",
+    "ast/transform/renamer.h",
+    "ast/transform/robustness.cc",
+    "ast/transform/robustness.h",
+    "ast/transform/simplify_pointers.cc",
+    "ast/transform/simplify_pointers.h",
+    "ast/transform/single_entry_point.cc",
+    "ast/transform/single_entry_point.h",
+    "ast/transform/spirv_atomic.cc",
+    "ast/transform/spirv_atomic.h",
+    "ast/transform/std140.cc",
+    "ast/transform/std140.h",
+    "ast/transform/substitute_override.cc",
+    "ast/transform/substitute_override.h",
+    "ast/transform/texture_1d_to_2d.cc",
+    "ast/transform/texture_1d_to_2d.h",
+    "ast/transform/transform.cc",
+    "ast/transform/transform.h",
+    "ast/transform/truncate_interstage_variables.cc",
+    "ast/transform/truncate_interstage_variables.h",
+    "ast/transform/unshadow.cc",
+    "ast/transform/unshadow.h",
+    "ast/transform/utils/get_insertion_point.cc",
+    "ast/transform/utils/get_insertion_point.h",
+    "ast/transform/utils/hoist_to_decl_before.cc",
+    "ast/transform/utils/hoist_to_decl_before.h",
+    "ast/transform/var_for_dynamic_index.cc",
+    "ast/transform/var_for_dynamic_index.h",
+    "ast/transform/vectorize_matrix_conversions.cc",
+    "ast/transform/vectorize_matrix_conversions.h",
+    "ast/transform/vectorize_scalar_matrix_initializers.cc",
+    "ast/transform/vectorize_scalar_matrix_initializers.h",
+    "ast/transform/vertex_pulling.cc",
+    "ast/transform/vertex_pulling.h",
+    "ast/transform/while_to_loop.cc",
+    "ast/transform/while_to_loop.h",
+    "ast/transform/zero_init_workgroup_memory.cc",
+    "ast/transform/zero_init_workgroup_memory.h",
     "transform/manager.cc",
     "transform/manager.h",
-    "transform/merge_return.cc",
-    "transform/merge_return.h",
-    "transform/module_scope_var_to_entry_point_param.cc",
-    "transform/module_scope_var_to_entry_point_param.h",
-    "transform/multiplanar_external_texture.cc",
-    "transform/multiplanar_external_texture.h",
-    "transform/num_workgroups_from_uniform.cc",
-    "transform/num_workgroups_from_uniform.h",
-    "transform/packed_vec3.cc",
-    "transform/packed_vec3.h",
-    "transform/pad_structs.cc",
-    "transform/pad_structs.h",
-    "transform/preserve_padding.cc",
-    "transform/preserve_padding.h",
-    "transform/promote_initializers_to_let.cc",
-    "transform/promote_initializers_to_let.h",
-    "transform/promote_side_effects_to_decl.cc",
-    "transform/promote_side_effects_to_decl.h",
-    "transform/remove_continue_in_switch.cc",
-    "transform/remove_continue_in_switch.h",
-    "transform/remove_phonies.cc",
-    "transform/remove_phonies.h",
-    "transform/remove_unreachable_statements.cc",
-    "transform/remove_unreachable_statements.h",
-    "transform/renamer.cc",
-    "transform/renamer.h",
-    "transform/robustness.cc",
-    "transform/robustness.h",
-    "transform/simplify_pointers.cc",
-    "transform/simplify_pointers.h",
-    "transform/single_entry_point.cc",
-    "transform/single_entry_point.h",
-    "transform/spirv_atomic.cc",
-    "transform/spirv_atomic.h",
-    "transform/std140.cc",
-    "transform/std140.h",
-    "transform/substitute_override.cc",
-    "transform/substitute_override.h",
-    "transform/texture_1d_to_2d.cc",
-    "transform/texture_1d_to_2d.h",
-    "transform/transform.cc",
-    "transform/transform.h",
-    "transform/truncate_interstage_variables.cc",
-    "transform/truncate_interstage_variables.h",
-    "transform/unshadow.cc",
-    "transform/unshadow.h",
-    "transform/utils/get_insertion_point.cc",
-    "transform/utils/get_insertion_point.h",
-    "transform/utils/hoist_to_decl_before.cc",
-    "transform/utils/hoist_to_decl_before.h",
-    "transform/var_for_dynamic_index.cc",
-    "transform/var_for_dynamic_index.h",
-    "transform/vectorize_matrix_conversions.cc",
-    "transform/vectorize_matrix_conversions.h",
-    "transform/vectorize_scalar_matrix_initializers.cc",
-    "transform/vectorize_scalar_matrix_initializers.h",
-    "transform/vertex_pulling.cc",
-    "transform/vertex_pulling.h",
-    "transform/while_to_loop.cc",
-    "transform/while_to_loop.h",
-    "transform/zero_init_workgroup_memory.cc",
-    "transform/zero_init_workgroup_memory.h",
   ]
   deps = [
     ":libtint_ast_src",
@@ -1640,60 +1640,60 @@
 
   tint_unittests_source_set("tint_unittests_transform_src") {
     sources = [
-      "transform/add_block_attribute_test.cc",
-      "transform/add_empty_entry_point_test.cc",
-      "transform/array_length_from_uniform_test.cc",
-      "transform/binding_remapper_test.cc",
-      "transform/builtin_polyfill_test.cc",
-      "transform/calculate_array_length_test.cc",
-      "transform/canonicalize_entry_point_io_test.cc",
-      "transform/clamp_frag_depth_test.cc",
-      "transform/combine_samplers_test.cc",
-      "transform/decompose_memory_access_test.cc",
-      "transform/decompose_strided_array_test.cc",
-      "transform/decompose_strided_matrix_test.cc",
-      "transform/demote_to_helper_test.cc",
-      "transform/direct_variable_access_test.cc",
-      "transform/disable_uniformity_analysis_test.cc",
-      "transform/expand_compound_assignment_test.cc",
-      "transform/first_index_offset_test.cc",
-      "transform/for_loop_to_loop_test.cc",
-      "transform/localize_struct_array_assignment_test.cc",
-      "transform/merge_return_test.cc",
-      "transform/module_scope_var_to_entry_point_param_test.cc",
-      "transform/multiplanar_external_texture_test.cc",
-      "transform/num_workgroups_from_uniform_test.cc",
-      "transform/packed_vec3_test.cc",
-      "transform/pad_structs_test.cc",
-      "transform/preserve_padding_test.cc",
-      "transform/promote_initializers_to_let_test.cc",
-      "transform/promote_side_effects_to_decl_test.cc",
-      "transform/remove_continue_in_switch_test.cc",
-      "transform/remove_phonies_test.cc",
-      "transform/remove_unreachable_statements_test.cc",
-      "transform/renamer_test.cc",
-      "transform/robustness_test.cc",
-      "transform/simplify_pointers_test.cc",
-      "transform/single_entry_point_test.cc",
-      "transform/spirv_atomic_test.cc",
-      "transform/std140_exhaustive_test.cc",
-      "transform/std140_f16_test.cc",
-      "transform/std140_f32_test.cc",
-      "transform/std140_test.cc",
-      "transform/substitute_override_test.cc",
-      "transform/test_helper.h",
-      "transform/texture_1d_to_2d_test.cc",
-      "transform/transform_test.cc",
-      "transform/truncate_interstage_variables_test.cc",
-      "transform/unshadow_test.cc",
-      "transform/utils/get_insertion_point_test.cc",
-      "transform/utils/hoist_to_decl_before_test.cc",
-      "transform/var_for_dynamic_index_test.cc",
-      "transform/vectorize_matrix_conversions_test.cc",
-      "transform/vectorize_scalar_matrix_initializers_test.cc",
-      "transform/vertex_pulling_test.cc",
-      "transform/while_to_loop_test.cc",
-      "transform/zero_init_workgroup_memory_test.cc",
+      "ast/transform/add_block_attribute_test.cc",
+      "ast/transform/add_empty_entry_point_test.cc",
+      "ast/transform/array_length_from_uniform_test.cc",
+      "ast/transform/binding_remapper_test.cc",
+      "ast/transform/builtin_polyfill_test.cc",
+      "ast/transform/calculate_array_length_test.cc",
+      "ast/transform/canonicalize_entry_point_io_test.cc",
+      "ast/transform/clamp_frag_depth_test.cc",
+      "ast/transform/combine_samplers_test.cc",
+      "ast/transform/decompose_memory_access_test.cc",
+      "ast/transform/decompose_strided_array_test.cc",
+      "ast/transform/decompose_strided_matrix_test.cc",
+      "ast/transform/demote_to_helper_test.cc",
+      "ast/transform/direct_variable_access_test.cc",
+      "ast/transform/disable_uniformity_analysis_test.cc",
+      "ast/transform/expand_compound_assignment_test.cc",
+      "ast/transform/first_index_offset_test.cc",
+      "ast/transform/for_loop_to_loop_test.cc",
+      "ast/transform/localize_struct_array_assignment_test.cc",
+      "ast/transform/merge_return_test.cc",
+      "ast/transform/module_scope_var_to_entry_point_param_test.cc",
+      "ast/transform/multiplanar_external_texture_test.cc",
+      "ast/transform/num_workgroups_from_uniform_test.cc",
+      "ast/transform/packed_vec3_test.cc",
+      "ast/transform/pad_structs_test.cc",
+      "ast/transform/preserve_padding_test.cc",
+      "ast/transform/promote_initializers_to_let_test.cc",
+      "ast/transform/promote_side_effects_to_decl_test.cc",
+      "ast/transform/remove_continue_in_switch_test.cc",
+      "ast/transform/remove_phonies_test.cc",
+      "ast/transform/remove_unreachable_statements_test.cc",
+      "ast/transform/renamer_test.cc",
+      "ast/transform/robustness_test.cc",
+      "ast/transform/simplify_pointers_test.cc",
+      "ast/transform/single_entry_point_test.cc",
+      "ast/transform/spirv_atomic_test.cc",
+      "ast/transform/std140_exhaustive_test.cc",
+      "ast/transform/std140_f16_test.cc",
+      "ast/transform/std140_f32_test.cc",
+      "ast/transform/std140_test.cc",
+      "ast/transform/substitute_override_test.cc",
+      "ast/transform/test_helper.h",
+      "ast/transform/texture_1d_to_2d_test.cc",
+      "ast/transform/transform_test.cc",
+      "ast/transform/truncate_interstage_variables_test.cc",
+      "ast/transform/unshadow_test.cc",
+      "ast/transform/utils/get_insertion_point_test.cc",
+      "ast/transform/utils/hoist_to_decl_before_test.cc",
+      "ast/transform/var_for_dynamic_index_test.cc",
+      "ast/transform/vectorize_matrix_conversions_test.cc",
+      "ast/transform/vectorize_scalar_matrix_initializers_test.cc",
+      "ast/transform/vertex_pulling_test.cc",
+      "ast/transform/while_to_loop_test.cc",
+      "ast/transform/zero_init_workgroup_memory_test.cc",
     ]
 
     deps = [
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 0b06c66..41304ae 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -350,108 +350,108 @@
   symbol.cc
   symbol.h
   tint.cc
-  transform/add_empty_entry_point.cc
-  transform/add_empty_entry_point.h
-  transform/add_block_attribute.cc
-  transform/add_block_attribute.h
-  transform/array_length_from_uniform.cc
-  transform/array_length_from_uniform.h
-  transform/binding_remapper.cc
-  transform/binding_remapper.h
-  transform/builtin_polyfill.cc
-  transform/builtin_polyfill.h
-  transform/calculate_array_length.cc
-  transform/calculate_array_length.h
-  transform/clamp_frag_depth.cc
-  transform/clamp_frag_depth.h
-  transform/canonicalize_entry_point_io.cc
-  transform/canonicalize_entry_point_io.h
-  transform/combine_samplers.cc
-  transform/combine_samplers.h
-  transform/decompose_memory_access.cc
-  transform/decompose_memory_access.h
-  transform/decompose_strided_array.cc
-  transform/decompose_strided_array.h
-  transform/decompose_strided_matrix.cc
-  transform/decompose_strided_matrix.h
-  transform/demote_to_helper.cc
-  transform/demote_to_helper.h
-  transform/direct_variable_access.cc
-  transform/direct_variable_access.h
-  transform/disable_uniformity_analysis.cc
-  transform/disable_uniformity_analysis.h
-  transform/expand_compound_assignment.cc
-  transform/expand_compound_assignment.h
-  transform/first_index_offset.cc
-  transform/first_index_offset.h
-  transform/for_loop_to_loop.cc
-  transform/for_loop_to_loop.h
-  transform/localize_struct_array_assignment.cc
-  transform/localize_struct_array_assignment.h
+  ast/transform/add_empty_entry_point.cc
+  ast/transform/add_empty_entry_point.h
+  ast/transform/add_block_attribute.cc
+  ast/transform/add_block_attribute.h
+  ast/transform/array_length_from_uniform.cc
+  ast/transform/array_length_from_uniform.h
+  ast/transform/binding_remapper.cc
+  ast/transform/binding_remapper.h
+  ast/transform/builtin_polyfill.cc
+  ast/transform/builtin_polyfill.h
+  ast/transform/calculate_array_length.cc
+  ast/transform/calculate_array_length.h
+  ast/transform/clamp_frag_depth.cc
+  ast/transform/clamp_frag_depth.h
+  ast/transform/canonicalize_entry_point_io.cc
+  ast/transform/canonicalize_entry_point_io.h
+  ast/transform/combine_samplers.cc
+  ast/transform/combine_samplers.h
+  ast/transform/decompose_memory_access.cc
+  ast/transform/decompose_memory_access.h
+  ast/transform/decompose_strided_array.cc
+  ast/transform/decompose_strided_array.h
+  ast/transform/decompose_strided_matrix.cc
+  ast/transform/decompose_strided_matrix.h
+  ast/transform/demote_to_helper.cc
+  ast/transform/demote_to_helper.h
+  ast/transform/direct_variable_access.cc
+  ast/transform/direct_variable_access.h
+  ast/transform/disable_uniformity_analysis.cc
+  ast/transform/disable_uniformity_analysis.h
+  ast/transform/expand_compound_assignment.cc
+  ast/transform/expand_compound_assignment.h
+  ast/transform/first_index_offset.cc
+  ast/transform/first_index_offset.h
+  ast/transform/for_loop_to_loop.cc
+  ast/transform/for_loop_to_loop.h
+  ast/transform/localize_struct_array_assignment.cc
+  ast/transform/localize_struct_array_assignment.h
+  ast/transform/merge_return.cc
+  ast/transform/merge_return.h
+  ast/transform/module_scope_var_to_entry_point_param.cc
+  ast/transform/module_scope_var_to_entry_point_param.h
+  ast/transform/multiplanar_external_texture.cc
+  ast/transform/multiplanar_external_texture.h
+  ast/transform/num_workgroups_from_uniform.cc
+  ast/transform/num_workgroups_from_uniform.h
+  ast/transform/packed_vec3.cc
+  ast/transform/packed_vec3.h
+  ast/transform/pad_structs.cc
+  ast/transform/pad_structs.h
+  ast/transform/preserve_padding.cc
+  ast/transform/preserve_padding.h
+  ast/transform/promote_initializers_to_let.cc
+  ast/transform/promote_initializers_to_let.h
+  ast/transform/promote_side_effects_to_decl.cc
+  ast/transform/promote_side_effects_to_decl.h
+  ast/transform/remove_continue_in_switch.cc
+  ast/transform/remove_continue_in_switch.h
+  ast/transform/remove_phonies.cc
+  ast/transform/remove_phonies.h
+  ast/transform/remove_unreachable_statements.cc
+  ast/transform/remove_unreachable_statements.h
+  ast/transform/renamer.cc
+  ast/transform/renamer.h
+  ast/transform/robustness.cc
+  ast/transform/robustness.h
+  ast/transform/simplify_pointers.cc
+  ast/transform/simplify_pointers.h
+  ast/transform/single_entry_point.cc
+  ast/transform/single_entry_point.h
+  ast/transform/spirv_atomic.cc
+  ast/transform/spirv_atomic.h
+  ast/transform/std140.cc
+  ast/transform/std140.h
+  ast/transform/substitute_override.cc
+  ast/transform/substitute_override.h
+  ast/transform/texture_1d_to_2d.cc
+  ast/transform/texture_1d_to_2d.h
+  ast/transform/transform.cc
+  ast/transform/transform.h
+  ast/transform/truncate_interstage_variables.cc
+  ast/transform/truncate_interstage_variables.h
+  ast/transform/unshadow.cc
+  ast/transform/unshadow.h
+  ast/transform/utils/get_insertion_point.cc
+  ast/transform/utils/get_insertion_point.h
+  ast/transform/utils/hoist_to_decl_before.cc
+  ast/transform/utils/hoist_to_decl_before.h
+  ast/transform/var_for_dynamic_index.cc
+  ast/transform/var_for_dynamic_index.h
+  ast/transform/vectorize_matrix_conversions.cc
+  ast/transform/vectorize_matrix_conversions.h
+  ast/transform/vectorize_scalar_matrix_initializers.cc
+  ast/transform/vectorize_scalar_matrix_initializers.h
+  ast/transform/vertex_pulling.cc
+  ast/transform/vertex_pulling.h
+  ast/transform/while_to_loop.cc
+  ast/transform/while_to_loop.h
+  ast/transform/zero_init_workgroup_memory.cc
+  ast/transform/zero_init_workgroup_memory.h
   transform/manager.cc
   transform/manager.h
-  transform/merge_return.cc
-  transform/merge_return.h
-  transform/module_scope_var_to_entry_point_param.cc
-  transform/module_scope_var_to_entry_point_param.h
-  transform/multiplanar_external_texture.cc
-  transform/multiplanar_external_texture.h
-  transform/num_workgroups_from_uniform.cc
-  transform/num_workgroups_from_uniform.h
-  transform/packed_vec3.cc
-  transform/packed_vec3.h
-  transform/pad_structs.cc
-  transform/pad_structs.h
-  transform/preserve_padding.cc
-  transform/preserve_padding.h
-  transform/promote_initializers_to_let.cc
-  transform/promote_initializers_to_let.h
-  transform/promote_side_effects_to_decl.cc
-  transform/promote_side_effects_to_decl.h
-  transform/remove_continue_in_switch.cc
-  transform/remove_continue_in_switch.h
-  transform/remove_phonies.cc
-  transform/remove_phonies.h
-  transform/remove_unreachable_statements.cc
-  transform/remove_unreachable_statements.h
-  transform/renamer.cc
-  transform/renamer.h
-  transform/robustness.cc
-  transform/robustness.h
-  transform/simplify_pointers.cc
-  transform/simplify_pointers.h
-  transform/single_entry_point.cc
-  transform/single_entry_point.h
-  transform/spirv_atomic.cc
-  transform/spirv_atomic.h
-  transform/std140.cc
-  transform/std140.h
-  transform/substitute_override.cc
-  transform/substitute_override.h
-  transform/texture_1d_to_2d.cc
-  transform/texture_1d_to_2d.h
-  transform/transform.cc
-  transform/transform.h
-  transform/truncate_interstage_variables.cc
-  transform/truncate_interstage_variables.h
-  transform/unshadow.cc
-  transform/unshadow.h
-  transform/utils/get_insertion_point.cc
-  transform/utils/get_insertion_point.h
-  transform/utils/hoist_to_decl_before.cc
-  transform/utils/hoist_to_decl_before.h
-  transform/var_for_dynamic_index.cc
-  transform/var_for_dynamic_index.h
-  transform/vectorize_matrix_conversions.cc
-  transform/vectorize_matrix_conversions.h
-  transform/vectorize_scalar_matrix_initializers.cc
-  transform/vectorize_scalar_matrix_initializers.h
-  transform/vertex_pulling.cc
-  transform/vertex_pulling.h
-  transform/while_to_loop.cc
-  transform/while_to_loop.h
-  transform/zero_init_workgroup_memory.cc
-  transform/zero_init_workgroup_memory.h
   type/abstract_float.cc
   type/abstract_float.h
   type/abstract_int.cc
@@ -993,7 +993,7 @@
     symbol_table_test.cc
     symbol_test.cc
     test_main.cc
-    transform/transform_test.cc
+    ast/transform/transform_test.cc
     type/array_test.cc
     type/atomic_test.cc
     type/bool_test.cc
@@ -1278,60 +1278,60 @@
   if(${TINT_BUILD_WGSL_READER} AND ${TINT_BUILD_WGSL_WRITER})
     list(APPEND TINT_TEST_SRCS
       ast/module_clone_test.cc
-      transform/add_empty_entry_point_test.cc
-      transform/add_block_attribute_test.cc
-      transform/array_length_from_uniform_test.cc
-      transform/binding_remapper_test.cc
-      transform/builtin_polyfill_test.cc
-      transform/calculate_array_length_test.cc
-      transform/clamp_frag_depth_test.cc
-      transform/canonicalize_entry_point_io_test.cc
-      transform/combine_samplers_test.cc
-      transform/decompose_memory_access_test.cc
-      transform/decompose_strided_array_test.cc
-      transform/decompose_strided_matrix_test.cc
-      transform/demote_to_helper_test.cc
-      transform/direct_variable_access_test.cc
-      transform/disable_uniformity_analysis_test.cc
-      transform/expand_compound_assignment_test.cc
-      transform/first_index_offset_test.cc
-      transform/for_loop_to_loop_test.cc
-      transform/expand_compound_assignment_test.cc
-      transform/localize_struct_array_assignment_test.cc
-      transform/merge_return_test.cc
-      transform/module_scope_var_to_entry_point_param_test.cc
-      transform/multiplanar_external_texture_test.cc
-      transform/num_workgroups_from_uniform_test.cc
-      transform/packed_vec3_test.cc
-      transform/pad_structs_test.cc
-      transform/preserve_padding_test.cc
-      transform/promote_initializers_to_let_test.cc
-      transform/promote_side_effects_to_decl_test.cc
-      transform/remove_continue_in_switch_test.cc
-      transform/remove_phonies_test.cc
-      transform/remove_unreachable_statements_test.cc
-      transform/renamer_test.cc
-      transform/robustness_test.cc
-      transform/simplify_pointers_test.cc
-      transform/single_entry_point_test.cc
-      transform/spirv_atomic_test.cc
-      transform/std140_exhaustive_test.cc
-      transform/std140_f16_test.cc
-      transform/std140_f32_test.cc
-      transform/std140_test.cc
-      transform/substitute_override_test.cc
-      transform/test_helper.h
-      transform/texture_1d_to_2d_test.cc
-      transform/truncate_interstage_variables_test.cc
-      transform/unshadow_test.cc
-      transform/var_for_dynamic_index_test.cc
-      transform/vectorize_matrix_conversions_test.cc
-      transform/vectorize_scalar_matrix_initializers_test.cc
-      transform/vertex_pulling_test.cc
-      transform/while_to_loop_test.cc
-      transform/zero_init_workgroup_memory_test.cc
-      transform/utils/get_insertion_point_test.cc
-      transform/utils/hoist_to_decl_before_test.cc
+      ast/transform/add_empty_entry_point_test.cc
+      ast/transform/add_block_attribute_test.cc
+      ast/transform/array_length_from_uniform_test.cc
+      ast/transform/binding_remapper_test.cc
+      ast/transform/builtin_polyfill_test.cc
+      ast/transform/calculate_array_length_test.cc
+      ast/transform/clamp_frag_depth_test.cc
+      ast/transform/canonicalize_entry_point_io_test.cc
+      ast/transform/combine_samplers_test.cc
+      ast/transform/decompose_memory_access_test.cc
+      ast/transform/decompose_strided_array_test.cc
+      ast/transform/decompose_strided_matrix_test.cc
+      ast/transform/demote_to_helper_test.cc
+      ast/transform/direct_variable_access_test.cc
+      ast/transform/disable_uniformity_analysis_test.cc
+      ast/transform/expand_compound_assignment_test.cc
+      ast/transform/first_index_offset_test.cc
+      ast/transform/for_loop_to_loop_test.cc
+      ast/transform/expand_compound_assignment_test.cc
+      ast/transform/localize_struct_array_assignment_test.cc
+      ast/transform/merge_return_test.cc
+      ast/transform/module_scope_var_to_entry_point_param_test.cc
+      ast/transform/multiplanar_external_texture_test.cc
+      ast/transform/num_workgroups_from_uniform_test.cc
+      ast/transform/packed_vec3_test.cc
+      ast/transform/pad_structs_test.cc
+      ast/transform/preserve_padding_test.cc
+      ast/transform/promote_initializers_to_let_test.cc
+      ast/transform/promote_side_effects_to_decl_test.cc
+      ast/transform/remove_continue_in_switch_test.cc
+      ast/transform/remove_phonies_test.cc
+      ast/transform/remove_unreachable_statements_test.cc
+      ast/transform/renamer_test.cc
+      ast/transform/robustness_test.cc
+      ast/transform/simplify_pointers_test.cc
+      ast/transform/single_entry_point_test.cc
+      ast/transform/spirv_atomic_test.cc
+      ast/transform/std140_exhaustive_test.cc
+      ast/transform/std140_f16_test.cc
+      ast/transform/std140_f32_test.cc
+      ast/transform/std140_test.cc
+      ast/transform/substitute_override_test.cc
+      ast/transform/test_helper.h
+      ast/transform/texture_1d_to_2d_test.cc
+      ast/transform/truncate_interstage_variables_test.cc
+      ast/transform/unshadow_test.cc
+      ast/transform/var_for_dynamic_index_test.cc
+      ast/transform/vectorize_matrix_conversions_test.cc
+      ast/transform/vectorize_scalar_matrix_initializers_test.cc
+      ast/transform/vertex_pulling_test.cc
+      ast/transform/while_to_loop_test.cc
+      ast/transform/zero_init_workgroup_memory_test.cc
+      ast/transform/utils/get_insertion_point_test.cc
+      ast/transform/utils/hoist_to_decl_before_test.cc
     )
   endif()
 
diff --git a/src/tint/ast/builtin_texture_helper_test.cc b/src/tint/ast/builtin_texture_helper_test.cc
index 658b650..3231081 100644
--- a/src/tint/ast/builtin_texture_helper_test.cc
+++ b/src/tint/ast/builtin_texture_helper_test.cc
@@ -22,7 +22,7 @@
 
 using namespace tint::number_suffixes;  // NOLINT
 
-namespace tint::ast::builtin::test {
+namespace tint::ast::test {
 namespace {
 
 utils::StringStream& operator<<(utils::StringStream& out, const TextureKind& kind) {
@@ -142,11 +142,11 @@
 
 Type TextureOverloadCase::BuildResultVectorComponentType(ProgramBuilder* b) const {
     switch (texture_data_type) {
-        case builtin::test::TextureDataType::kF32:
+        case test::TextureDataType::kF32:
             return b->ty.f32();
-        case builtin::test::TextureDataType::kU32:
+        case test::TextureDataType::kU32:
             return b->ty.u32();
-        case builtin::test::TextureDataType::kI32:
+        case test::TextureDataType::kI32:
             return b->ty.i32();
     }
 
@@ -160,25 +160,25 @@
         b->Binding(0_a),
     };
     switch (texture_kind) {
-        case builtin::test::TextureKind::kRegular:
+        case test::TextureKind::kRegular:
             return b->GlobalVar(
                 kTextureName,
                 b->ty.sampled_texture(texture_dimension, BuildResultVectorComponentType(b)), attrs);
 
-        case builtin::test::TextureKind::kDepth:
+        case test::TextureKind::kDepth:
             return b->GlobalVar(kTextureName, b->ty.depth_texture(texture_dimension), attrs);
 
-        case builtin::test::TextureKind::kDepthMultisampled:
+        case test::TextureKind::kDepthMultisampled:
             return b->GlobalVar(kTextureName, b->ty.depth_multisampled_texture(texture_dimension),
                                 attrs);
 
-        case builtin::test::TextureKind::kMultisampled:
+        case test::TextureKind::kMultisampled:
             return b->GlobalVar(
                 kTextureName,
                 b->ty.multisampled_texture(texture_dimension, BuildResultVectorComponentType(b)),
                 attrs);
 
-        case builtin::test::TextureKind::kStorage: {
+        case test::TextureKind::kStorage: {
             auto st = b->ty.storage_texture(texture_dimension, texel_format, access);
             return b->GlobalVar(kTextureName, st, attrs);
         }
@@ -2554,4 +2554,4 @@
     }
 }
 
-}  // namespace tint::ast::builtin::test
+}  // namespace tint::ast::test
diff --git a/src/tint/ast/builtin_texture_helper_test.h b/src/tint/ast/builtin_texture_helper_test.h
index 2f941bb..2a448a5 100644
--- a/src/tint/ast/builtin_texture_helper_test.h
+++ b/src/tint/ast/builtin_texture_helper_test.h
@@ -23,7 +23,7 @@
 #include "src/tint/type/storage_texture.h"
 #include "src/tint/type/texture_dimension.h"
 
-namespace tint::ast::builtin::test {
+namespace tint::ast::test {
 
 /// The name of the texture global variable used by the tests.
 static constexpr const char* kTextureName = "Texture";
@@ -268,6 +268,6 @@
 
 std::ostream& operator<<(std::ostream& out, const TextureOverloadCase& data);
 
-}  // namespace tint::ast::builtin::test
+}  // namespace tint::ast::test
 
 #endif  // SRC_TINT_AST_BUILTIN_TEXTURE_HELPER_TEST_H_
diff --git a/src/tint/ast/struct_test.cc b/src/tint/ast/struct_test.cc
index 1d14716..3a638d3 100644
--- a/src/tint/ast/struct_test.cc
+++ b/src/tint/ast/struct_test.cc
@@ -16,7 +16,7 @@
 #include "gtest/gtest-spi.h"
 #include "src/tint/ast/alias.h"
 #include "src/tint/ast/test_helper.h"
-#include "src/tint/transform/add_block_attribute.h"
+#include "src/tint/ast/transform/add_block_attribute.h"
 
 namespace tint::ast {
 namespace {
diff --git a/src/tint/transform/add_block_attribute.cc b/src/tint/ast/transform/add_block_attribute.cc
similarity index 91%
rename from src/tint/transform/add_block_attribute.cc
rename to src/tint/ast/transform/add_block_attribute.cc
index a629fc4..d841d4a 100644
--- a/src/tint/transform/add_block_attribute.cc
+++ b/src/tint/ast/transform/add_block_attribute.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/add_block_attribute.h"
+#include "src/tint/ast/transform/add_block_attribute.h"
 
 #include <unordered_set>
 #include <utility>
@@ -22,10 +22,10 @@
 #include "src/tint/utils/hashmap.h"
 #include "src/tint/utils/hashset.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::AddBlockAttribute);
-TINT_INSTANTIATE_TYPEINFO(tint::transform::AddBlockAttribute::BlockAttribute);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::AddBlockAttribute);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::AddBlockAttribute::BlockAttribute);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 AddBlockAttribute::AddBlockAttribute() = default;
 
@@ -41,7 +41,7 @@
 
     // A map from a type in the source program to a block-decorated wrapper that contains it in the
     // destination program.
-    utils::Hashmap<const type::Type*, const ast::Struct*, 8> wrapper_structs;
+    utils::Hashmap<const type::Type*, const Struct*, 8> wrapper_structs;
 
     // Process global 'var' declarations that are buffers.
     bool made_changes = false;
@@ -71,7 +71,7 @@
             auto* wrapper = wrapper_structs.GetOrCreate(ty, [&] {
                 auto* block = b.ASTNodes().Create<BlockAttribute>(b.ID(), b.AllocateNodeID());
                 auto wrapper_name = global->name->symbol.Name() + "_block";
-                auto* ret = b.create<ast::Struct>(
+                auto* ret = b.create<Struct>(
                     b.Ident(b.Symbols().New(wrapper_name)),
                     utils::Vector{b.Member(kMemberName, CreateASTTypeFor(ctx, ty))},
                     utils::Vector{block});
@@ -101,7 +101,7 @@
     return Program(std::move(b));
 }
 
-AddBlockAttribute::BlockAttribute::BlockAttribute(ProgramID pid, ast::NodeID nid)
+AddBlockAttribute::BlockAttribute::BlockAttribute(ProgramID pid, NodeID nid)
     : Base(pid, nid, utils::Empty) {}
 AddBlockAttribute::BlockAttribute::~BlockAttribute() = default;
 std::string AddBlockAttribute::BlockAttribute::InternalName() const {
@@ -114,4 +114,4 @@
         ctx->dst->ID(), ctx->dst->AllocateNodeID());
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/add_block_attribute.h b/src/tint/ast/transform/add_block_attribute.h
similarity index 84%
rename from src/tint/transform/add_block_attribute.h
rename to src/tint/ast/transform/add_block_attribute.h
index 3eeb148..b23bb8f 100644
--- a/src/tint/transform/add_block_attribute.h
+++ b/src/tint/ast/transform/add_block_attribute.h
@@ -12,15 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_ADD_BLOCK_ATTRIBUTE_H_
-#define SRC_TINT_TRANSFORM_ADD_BLOCK_ATTRIBUTE_H_
+#ifndef SRC_TINT_AST_TRANSFORM_ADD_BLOCK_ATTRIBUTE_H_
+#define SRC_TINT_AST_TRANSFORM_ADD_BLOCK_ATTRIBUTE_H_
 
 #include <string>
 
 #include "src/tint/ast/internal_attribute.h"
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// AddBlockAttribute is a transform that wrap the store type of a buffer into a struct if possible,
 /// then adds an `@internal(block)` attribute to the wrapper struct.
@@ -28,12 +28,12 @@
   public:
     /// BlockAttribute is an InternalAttribute that is used to decorate a
     // structure that is used as a buffer in SPIR-V or GLSL.
-    class BlockAttribute final : public utils::Castable<BlockAttribute, ast::InternalAttribute> {
+    class BlockAttribute final : public utils::Castable<BlockAttribute, InternalAttribute> {
       public:
         /// Constructor
         /// @param program_id the identifier of the program that owns this node
         /// @param nid the unique node identifier
-        BlockAttribute(ProgramID program_id, ast::NodeID nid);
+        BlockAttribute(ProgramID program_id, NodeID nid);
         /// Destructor
         ~BlockAttribute() override;
 
@@ -59,6 +59,6 @@
                       DataMap& outputs) const override;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_ADD_BLOCK_ATTRIBUTE_H_
+#endif  // SRC_TINT_AST_TRANSFORM_ADD_BLOCK_ATTRIBUTE_H_
diff --git a/src/tint/transform/add_block_attribute_test.cc b/src/tint/ast/transform/add_block_attribute_test.cc
similarity index 98%
rename from src/tint/transform/add_block_attribute_test.cc
rename to src/tint/ast/transform/add_block_attribute_test.cc
index 4a02db9..ce1975c 100644
--- a/src/tint/transform/add_block_attribute_test.cc
+++ b/src/tint/ast/transform/add_block_attribute_test.cc
@@ -12,14 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/add_block_attribute.h"
+#include "src/tint/ast/transform/add_block_attribute.h"
 
 #include <memory>
 #include <utility>
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using AddBlockAttributeTest = TransformTest;
@@ -1022,4 +1022,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/add_empty_entry_point.cc b/src/tint/ast/transform/add_empty_entry_point.cc
similarity index 86%
rename from src/tint/transform/add_empty_entry_point.cc
rename to src/tint/ast/transform/add_empty_entry_point.cc
index f71394d..947b5f0 100644
--- a/src/tint/transform/add_empty_entry_point.cc
+++ b/src/tint/ast/transform/add_empty_entry_point.cc
@@ -12,17 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/add_empty_entry_point.h"
+#include "src/tint/ast/transform/add_empty_entry_point.h"
 
 #include <utility>
 
 #include "src/tint/program_builder.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::AddEmptyEntryPoint);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::AddEmptyEntryPoint);
 
 using namespace tint::number_suffixes;  // NOLINT
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 bool ShouldRun(const Program* program) {
@@ -52,7 +52,7 @@
 
     b.Func(b.Symbols().New("unused_entry_point"), {}, b.ty.void_(), {},
            utils::Vector{
-               b.Stage(ast::PipelineStage::kCompute),
+               b.Stage(PipelineStage::kCompute),
                b.WorkgroupSize(1_i),
            });
 
@@ -60,4 +60,4 @@
     return Program(std::move(b));
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/add_empty_entry_point.h b/src/tint/ast/transform/add_empty_entry_point.h
similarity index 78%
rename from src/tint/transform/add_empty_entry_point.h
rename to src/tint/ast/transform/add_empty_entry_point.h
index 709b574..d2939e5 100644
--- a/src/tint/transform/add_empty_entry_point.h
+++ b/src/tint/ast/transform/add_empty_entry_point.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_ADD_EMPTY_ENTRY_POINT_H_
-#define SRC_TINT_TRANSFORM_ADD_EMPTY_ENTRY_POINT_H_
+#ifndef SRC_TINT_AST_TRANSFORM_ADD_EMPTY_ENTRY_POINT_H_
+#define SRC_TINT_AST_TRANSFORM_ADD_EMPTY_ENTRY_POINT_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// Add an empty entry point to the module, if no other entry points exist.
 class AddEmptyEntryPoint final : public utils::Castable<AddEmptyEntryPoint, Transform> {
@@ -33,6 +33,6 @@
                       DataMap& outputs) const override;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_ADD_EMPTY_ENTRY_POINT_H_
+#endif  // SRC_TINT_AST_TRANSFORM_ADD_EMPTY_ENTRY_POINT_H_
diff --git a/src/tint/transform/add_empty_entry_point_test.cc b/src/tint/ast/transform/add_empty_entry_point_test.cc
similarity index 90%
rename from src/tint/transform/add_empty_entry_point_test.cc
rename to src/tint/ast/transform/add_empty_entry_point_test.cc
index 44f9005..c234df6 100644
--- a/src/tint/transform/add_empty_entry_point_test.cc
+++ b/src/tint/ast/transform/add_empty_entry_point_test.cc
@@ -12,13 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/add_empty_entry_point.h"
+#include "src/tint/ast/transform/add_empty_entry_point.h"
 
 #include <utility>
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using AddEmptyEntryPointTest = TransformTest;
@@ -83,4 +83,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/array_length_from_uniform.cc b/src/tint/ast/transform/array_length_from_uniform.cc
similarity index 85%
rename from src/tint/transform/array_length_from_uniform.cc
rename to src/tint/ast/transform/array_length_from_uniform.cc
index 1c88483..0101658 100644
--- a/src/tint/transform/array_length_from_uniform.cc
+++ b/src/tint/ast/transform/array_length_from_uniform.cc
@@ -12,24 +12,24 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/array_length_from_uniform.h"
+#include "src/tint/ast/transform/array_length_from_uniform.h"
 
 #include <memory>
 #include <string>
 #include <utility>
 
+#include "src/tint/ast/transform/simplify_pointers.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/call.h"
 #include "src/tint/sem/function.h"
 #include "src/tint/sem/statement.h"
 #include "src/tint/sem/variable.h"
-#include "src/tint/transform/simplify_pointers.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::ArrayLengthFromUniform);
-TINT_INSTANTIATE_TYPEINFO(tint::transform::ArrayLengthFromUniform::Config);
-TINT_INSTANTIATE_TYPEINFO(tint::transform::ArrayLengthFromUniform::Result);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::ArrayLengthFromUniform);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::ArrayLengthFromUniform::Config);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::ArrayLengthFromUniform::Result);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 namespace {
 
@@ -81,22 +81,22 @@
         // Determine the size of the buffer size array.
         uint32_t max_buffer_size_index = 0;
 
-        IterateArrayLengthOnStorageVar([&](const ast::CallExpression*, const sem::VariableUser*,
-                                           const sem::GlobalVariable* var) {
-            if (auto binding = var->BindingPoint()) {
-                auto idx_itr = cfg->bindpoint_to_size_index.find(*binding);
-                if (idx_itr == cfg->bindpoint_to_size_index.end()) {
-                    return;
+        IterateArrayLengthOnStorageVar(
+            [&](const CallExpression*, const sem::VariableUser*, const sem::GlobalVariable* var) {
+                if (auto binding = var->BindingPoint()) {
+                    auto idx_itr = cfg->bindpoint_to_size_index.find(*binding);
+                    if (idx_itr == cfg->bindpoint_to_size_index.end()) {
+                        return;
+                    }
+                    if (idx_itr->second > max_buffer_size_index) {
+                        max_buffer_size_index = idx_itr->second;
+                    }
                 }
-                if (idx_itr->second > max_buffer_size_index) {
-                    max_buffer_size_index = idx_itr->second;
-                }
-            }
-        });
+            });
 
         // Get (or create, on first call) the uniform buffer that will receive the
         // size of each storage buffer in the module.
-        const ast::Variable* buffer_size_ubo = nullptr;
+        const Variable* buffer_size_ubo = nullptr;
         auto get_ubo = [&]() {
             if (!buffer_size_ubo) {
                 // Emit an array<vec4<u32>, N>, where N is 1/4 number of elements.
@@ -118,7 +118,7 @@
 
         std::unordered_set<uint32_t> used_size_indices;
 
-        IterateArrayLengthOnStorageVar([&](const ast::CallExpression* call_expr,
+        IterateArrayLengthOnStorageVar([&](const CallExpression* call_expr,
                                            const sem::VariableUser* storage_buffer_sem,
                                            const sem::GlobalVariable* var) {
             auto binding = var->BindingPoint();
@@ -144,7 +144,7 @@
             //                total_storage_buffer_size - array_offset
             // array_length = ----------------------------------------
             //                             array_stride
-            const ast::Expression* total_size = total_storage_buffer_size;
+            const Expression* total_size = total_storage_buffer_size;
             auto* storage_buffer_type = storage_buffer_sem->Type()->UnwrapRef();
             const type::Array* array_type = nullptr;
             if (auto* str = storage_buffer_type->As<type::Struct>()) {
@@ -186,9 +186,9 @@
 
     /// Iterate over all arrayLength() builtins that operate on
     /// storage buffer variables.
-    /// @param functor of type void(const ast::CallExpression*, const
+    /// @param functor of type void(const CallExpression*, const
     /// sem::VariableUser, const sem::GlobalVariable*). It takes in an
-    /// ast::CallExpression of the arrayLength call expression node, a
+    /// CallExpression of the arrayLength call expression node, a
     /// sem::VariableUser of the used storage buffer variable, and the
     /// sem::GlobalVariable for the storage buffer.
     template <typename F>
@@ -197,7 +197,7 @@
 
         // Find all calls to the arrayLength() builtin.
         for (auto* node : src->ASTNodes().Objects()) {
-            auto* call_expr = node->As<ast::CallExpression>();
+            auto* call_expr = node->As<CallExpression>();
             if (!call_expr) {
                 continue;
             }
@@ -208,7 +208,7 @@
                 continue;
             }
 
-            if (auto* call_stmt = call->Stmt()->Declaration()->As<ast::CallStatement>()) {
+            if (auto* call_stmt = call->Stmt()->Declaration()->As<CallStatement>()) {
                 if (call_stmt->expr == call_expr) {
                     // arrayLength() is used as a statement.
                     // The argument expression must be side-effect free, so just drop the statement.
@@ -222,15 +222,15 @@
             // call has one of two forms:
             //   arrayLength(&struct_var.array_member)
             //   arrayLength(&array_var)
-            auto* param = call_expr->args[0]->As<ast::UnaryOpExpression>();
-            if (TINT_UNLIKELY(!param || param->op != ast::UnaryOp::kAddressOf)) {
+            auto* param = call_expr->args[0]->As<UnaryOpExpression>();
+            if (TINT_UNLIKELY(!param || param->op != UnaryOp::kAddressOf)) {
                 TINT_ICE(Transform, b.Diagnostics())
                     << "expected form of arrayLength argument to be &array_var or "
                        "&struct_var.array_member";
                 break;
             }
             auto* storage_buffer_expr = param->expr;
-            if (auto* accessor = param->expr->As<ast::MemberAccessorExpression>()) {
+            if (auto* accessor = param->expr->As<MemberAccessorExpression>()) {
                 storage_buffer_expr = accessor->object;
             }
             auto* storage_buffer_sem = sem.Get<sem::VariableUser>(storage_buffer_expr);
@@ -268,4 +268,4 @@
 ArrayLengthFromUniform::Result::Result(const Result&) = default;
 ArrayLengthFromUniform::Result::~Result() = default;
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/array_length_from_uniform.h b/src/tint/ast/transform/array_length_from_uniform.h
similarity index 88%
rename from src/tint/transform/array_length_from_uniform.h
rename to src/tint/ast/transform/array_length_from_uniform.h
index bb50dc0..5c714ea 100644
--- a/src/tint/transform/array_length_from_uniform.h
+++ b/src/tint/ast/transform/array_length_from_uniform.h
@@ -12,21 +12,21 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_ARRAY_LENGTH_FROM_UNIFORM_H_
-#define SRC_TINT_TRANSFORM_ARRAY_LENGTH_FROM_UNIFORM_H_
+#ifndef SRC_TINT_AST_TRANSFORM_ARRAY_LENGTH_FROM_UNIFORM_H_
+#define SRC_TINT_AST_TRANSFORM_ARRAY_LENGTH_FROM_UNIFORM_H_
 
 #include <unordered_map>
 #include <unordered_set>
 
+#include "src/tint/ast/transform/transform.h"
 #include "src/tint/sem/binding_point.h"
-#include "src/tint/transform/transform.h"
 
 // Forward declarations
 namespace tint {
 class CloneContext;
 }  // namespace tint
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// ArrayLengthFromUniform is a transform that implements calls to arrayLength()
 /// by calculating the length from the total size of the storage buffer, which
@@ -60,7 +60,7 @@
     ~ArrayLengthFromUniform() override;
 
     /// Configuration options for the ArrayLengthFromUniform transform.
-    struct Config final : public utils::Castable<Data, transform::Data> {
+    struct Config final : public utils::Castable<Config, Data> {
         /// Constructor
         /// @param ubo_bp the binding point to use for the generated uniform buffer.
         explicit Config(sem::BindingPoint ubo_bp);
@@ -85,7 +85,7 @@
     /// Information produced about what the transform did.
     /// If there were no calls to the arrayLength() builtin, then no Result will
     /// be emitted.
-    struct Result final : public utils::Castable<Result, transform::Data> {
+    struct Result final : public utils::Castable<Result, Data> {
         /// Constructor
         /// @param used_size_indices Indices into the UBO that are statically used.
         explicit Result(std::unordered_set<uint32_t> used_size_indices);
@@ -109,6 +109,6 @@
     struct State;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_ARRAY_LENGTH_FROM_UNIFORM_H_
+#endif  // SRC_TINT_AST_TRANSFORM_ARRAY_LENGTH_FROM_UNIFORM_H_
diff --git a/src/tint/transform/array_length_from_uniform_test.cc b/src/tint/ast/transform/array_length_from_uniform_test.cc
similarity index 96%
rename from src/tint/transform/array_length_from_uniform_test.cc
rename to src/tint/ast/transform/array_length_from_uniform_test.cc
index 4525cbc..b734630 100644
--- a/src/tint/transform/array_length_from_uniform_test.cc
+++ b/src/tint/ast/transform/array_length_from_uniform_test.cc
@@ -12,15 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/array_length_from_uniform.h"
+#include "src/tint/ast/transform/array_length_from_uniform.h"
 
 #include <utility>
 
-#include "src/tint/transform/simplify_pointers.h"
-#include "src/tint/transform/test_helper.h"
-#include "src/tint/transform/unshadow.h"
+#include "src/tint/ast/transform/simplify_pointers.h"
+#include "src/tint/ast/transform/test_helper.h"
+#include "src/tint/ast/transform/unshadow.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using ArrayLengthFromUniformTest = TransformTest;
@@ -99,9 +99,7 @@
 }
 )";
 
-    auto* expect =
-        "error: missing transform data for "
-        "tint::transform::ArrayLengthFromUniform";
+    auto* expect = "error: missing transform data for tint::ast::transform::ArrayLengthFromUniform";
 
     auto got = Run<Unshadow, SimplifyPointers, ArrayLengthFromUniform>(src);
 
@@ -515,4 +513,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/binding_remapper.cc b/src/tint/ast/transform/binding_remapper.cc
similarity index 82%
rename from src/tint/transform/binding_remapper.cc
rename to src/tint/ast/transform/binding_remapper.cc
index 6b1888d..fd646eb 100644
--- a/src/tint/transform/binding_remapper.cc
+++ b/src/tint/ast/transform/binding_remapper.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/binding_remapper.h"
+#include "src/tint/ast/transform/binding_remapper.h"
 
 #include <string>
 #include <unordered_set>
@@ -24,10 +24,10 @@
 #include "src/tint/sem/variable.h"
 #include "src/tint/utils/string.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::BindingRemapper);
-TINT_INSTANTIATE_TYPEINFO(tint::transform::BindingRemapper::Remappings);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::BindingRemapper);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::BindingRemapper::Remappings);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 BindingRemapper::Remappings::Remappings(BindingPoints bp, AccessControls ac, bool may_collide)
     : binding_points(std::move(bp)),
@@ -90,7 +90,7 @@
         }
     }
 
-    for (auto* var : src->AST().Globals<ast::Var>()) {
+    for (auto* var : src->AST().Globals<Var>()) {
         if (var->HasBindingPoint()) {
             auto* global_sem = src->Sem().Get<sem::GlobalVariable>(var);
 
@@ -109,8 +109,8 @@
                 auto* new_group = b.Group(AInt(to.group));
                 auto* new_binding = b.Binding(AInt(to.binding));
 
-                auto* old_group = ast::GetAttribute<ast::GroupAttribute>(var->attributes);
-                auto* old_binding = ast::GetAttribute<ast::BindingAttribute>(var->attributes);
+                auto* old_group = GetAttribute<GroupAttribute>(var->attributes);
+                auto* old_binding = GetAttribute<BindingAttribute>(var->attributes);
 
                 ctx.Replace(old_group, new_group);
                 ctx.Replace(old_binding, new_binding);
@@ -139,19 +139,19 @@
                 auto* ty = sem->Type()->UnwrapRef();
                 auto inner_ty = CreateASTTypeFor(ctx, ty);
                 auto* new_var =
-                    b.create<ast::Var>(ctx.Clone(var->source),                  // source
-                                       b.Ident(ctx.Clone(var->name->symbol)),   // name
-                                       inner_ty,                                // type
-                                       ctx.Clone(var->declared_address_space),  // address space
-                                       b.Expr(access),                          // access
-                                       ctx.Clone(var->initializer),             // initializer
-                                       ctx.Clone(var->attributes));             // attributes
+                    b.create<Var>(ctx.Clone(var->source),                  // source
+                                  b.Ident(ctx.Clone(var->name->symbol)),   // name
+                                  inner_ty,                                // type
+                                  ctx.Clone(var->declared_address_space),  // address space
+                                  b.Expr(access),                          // access
+                                  ctx.Clone(var->initializer),             // initializer
+                                  ctx.Clone(var->attributes));             // attributes
                 ctx.Replace(var, new_var);
             }
 
             // Add `DisableValidationAttribute`s if required
             if (add_collision_attr.count(bp)) {
-                auto* attribute = b.Disable(ast::DisabledValidation::kBindingPointCollision);
+                auto* attribute = b.Disable(DisabledValidation::kBindingPointCollision);
                 ctx.InsertBefore(var->attributes, *var->attributes.begin(), attribute);
             }
         }
@@ -161,4 +161,4 @@
     return Program(std::move(b));
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/binding_remapper.h b/src/tint/ast/transform/binding_remapper.h
similarity index 87%
rename from src/tint/transform/binding_remapper.h
rename to src/tint/ast/transform/binding_remapper.h
index 9eaedad..6a28f32 100644
--- a/src/tint/transform/binding_remapper.h
+++ b/src/tint/ast/transform/binding_remapper.h
@@ -12,16 +12,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_BINDING_REMAPPER_H_
-#define SRC_TINT_TRANSFORM_BINDING_REMAPPER_H_
+#ifndef SRC_TINT_AST_TRANSFORM_BINDING_REMAPPER_H_
+#define SRC_TINT_AST_TRANSFORM_BINDING_REMAPPER_H_
 
 #include <unordered_map>
 
+#include "src/tint/ast/transform/transform.h"
 #include "src/tint/builtin/access.h"
 #include "src/tint/sem/binding_point.h"
-#include "src/tint/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// BindingPoint is an alias to sem::BindingPoint
 using BindingPoint = sem::BindingPoint;
@@ -38,7 +38,7 @@
 
     /// Remappings is consumed by the BindingRemapper transform.
     /// Data holds information about shader usage and constant buffer offsets.
-    struct Remappings final : public utils::Castable<Data, transform::Data> {
+    struct Remappings final : public utils::Castable<Remappings, Data> {
         /// Constructor
         /// @param bp a map of new binding points
         /// @param ac a map of new access controls
@@ -73,6 +73,6 @@
                       DataMap& outputs) const override;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_BINDING_REMAPPER_H_
+#endif  // SRC_TINT_AST_TRANSFORM_BINDING_REMAPPER_H_
diff --git a/src/tint/transform/binding_remapper_test.cc b/src/tint/ast/transform/binding_remapper_test.cc
similarity index 96%
rename from src/tint/transform/binding_remapper_test.cc
rename to src/tint/ast/transform/binding_remapper_test.cc
index b4b7b29..296bd7c 100644
--- a/src/tint/transform/binding_remapper_test.cc
+++ b/src/tint/ast/transform/binding_remapper_test.cc
@@ -12,13 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/binding_remapper.h"
+#include "src/tint/ast/transform/binding_remapper.h"
 
 #include <utility>
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using BindingRemapperTest = TransformTest;
@@ -344,7 +344,7 @@
 }
 )";
 
-    auto* expect = R"(error: missing transform data for tint::transform::BindingRemapper)";
+    auto* expect = R"(error: missing transform data for tint::ast::transform::BindingRemapper)";
 
     auto got = Run<BindingRemapper>(src);
 
@@ -352,4 +352,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/builtin_polyfill.cc b/src/tint/ast/transform/builtin_polyfill.cc
similarity index 94%
rename from src/tint/transform/builtin_polyfill.cc
rename to src/tint/ast/transform/builtin_polyfill.cc
index 4014b21..3a4b01f 100644
--- a/src/tint/transform/builtin_polyfill.cc
+++ b/src/tint/ast/transform/builtin_polyfill.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/builtin_polyfill.h"
+#include "src/tint/ast/transform/builtin_polyfill.h"
 
 #include <algorithm>
 #include <tuple>
@@ -31,13 +31,13 @@
 
 using namespace tint::number_suffixes;  // NOLINT
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::BuiltinPolyfill);
-TINT_INSTANTIATE_TYPEINFO(tint::transform::BuiltinPolyfill::Config);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::BuiltinPolyfill);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::BuiltinPolyfill::Config);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// BinaryOpSignature is tuple of a binary op, LHS type and RHS type
-using BinaryOpSignature = std::tuple<ast::BinaryOp, const type::Type*, const type::Type*>;
+using BinaryOpSignature = std::tuple<BinaryOp, const type::Type*, const type::Type*>;
 
 /// PIMPL state for the transform
 struct BuiltinPolyfill::State {
@@ -60,16 +60,16 @@
         for (auto* node : src->ASTNodes().Objects()) {
             Switch(
                 node,  //
-                [&](const ast::CallExpression* expr) { Call(expr); },
-                [&](const ast::BinaryExpression* bin_op) {
+                [&](const CallExpression* expr) { Call(expr); },
+                [&](const BinaryExpression* bin_op) {
                     if (auto* s = src->Sem().Get(bin_op);
                         !s || s->Stage() == sem::EvaluationStage::kConstant ||
                         s->Stage() == sem::EvaluationStage::kNotEvaluated) {
                         return;  // Don't polyfill @const expressions
                     }
                     switch (bin_op->op) {
-                        case ast::BinaryOp::kShiftLeft:
-                        case ast::BinaryOp::kShiftRight: {
+                        case BinaryOp::kShiftLeft:
+                        case BinaryOp::kShiftRight: {
                             if (cfg.builtins.bitshift_modulo) {
                                 ctx.Replace(bin_op,
                                             [this, bin_op] { return BitshiftModulo(bin_op); });
@@ -77,7 +77,7 @@
                             }
                             break;
                         }
-                        case ast::BinaryOp::kDivide: {
+                        case BinaryOp::kDivide: {
                             if (cfg.builtins.int_div_mod) {
                                 auto* lhs_ty = src->TypeOf(bin_op->lhs)->UnwrapRef();
                                 if (lhs_ty->is_integer_scalar_or_vector()) {
@@ -88,7 +88,7 @@
                             }
                             break;
                         }
-                        case ast::BinaryOp::kModulo: {
+                        case BinaryOp::kModulo: {
                             if (cfg.builtins.int_div_mod) {
                                 auto* lhs_ty = src->TypeOf(bin_op->lhs)->UnwrapRef();
                                 if (lhs_ty->is_integer_scalar_or_vector()) {
@@ -111,7 +111,7 @@
                             break;
                     }
                 },
-                [&](const ast::Expression* expr) {
+                [&](const Expression* expr) {
                     if (cfg.builtins.bgra8unorm) {
                         if (auto* ty_expr = src->Sem().Get<sem::TypeExpression>(expr)) {
                             if (auto* tex = ty_expr->Type()->As<type::StorageTexture>()) {
@@ -170,15 +170,15 @@
         auto name = b.Symbols().New("tint_acosh");
         uint32_t width = WidthOf(ty);
 
-        auto V = [&](AFloat value) -> const ast::Expression* {
-            const ast::Expression* expr = b.Expr(value);
+        auto V = [&](AFloat value) -> const Expression* {
+            const Expression* expr = b.Expr(value);
             if (width == 1) {
                 return expr;
             }
             return b.Call(T(ty), expr);
         };
 
-        utils::Vector<const ast::Statement*, 4> body;
+        utils::Vector<const Statement*, 4> body;
         switch (cfg.builtins.acosh) {
             case Level::kFull:
                 // return log(x + sqrt(x*x - 1));
@@ -224,15 +224,15 @@
         auto name = b.Symbols().New("tint_atanh");
         uint32_t width = WidthOf(ty);
 
-        auto V = [&](AFloat value) -> const ast::Expression* {
-            const ast::Expression* expr = b.Expr(value);
+        auto V = [&](AFloat value) -> const Expression* {
+            const Expression* expr = b.Expr(value);
             if (width == 1) {
                 return expr;
             }
             return b.Call(T(ty), expr);
         };
 
-        utils::Vector<const ast::Statement*, 1> body;
+        utils::Vector<const Statement*, 1> body;
         switch (cfg.builtins.atanh) {
             case Level::kFull:
                 // return log((1+x) / (1-x)) * 0.5
@@ -290,7 +290,7 @@
             }
             return b.ty.vec<u32>(width);
         };
-        auto V = [&](uint32_t value) -> const ast::Expression* {
+        auto V = [&](uint32_t value) -> const Expression* {
             return ScalarOrVector(width, u32(value));
         };
         b.Func(
@@ -348,10 +348,10 @@
             }
             return b.ty.vec<u32>(width);
         };
-        auto V = [&](uint32_t value) -> const ast::Expression* {
+        auto V = [&](uint32_t value) -> const Expression* {
             return ScalarOrVector(width, u32(value));
         };
-        auto B = [&](const ast::Expression* value) -> const ast::Expression* {
+        auto B = [&](const Expression* value) -> const Expression* {
             if (width == 1) {
                 return b.Call<bool>(value);
             }
@@ -402,14 +402,14 @@
 
         constexpr uint32_t W = 32u;  // 32-bit
 
-        auto vecN_u32 = [&](const ast::Expression* value) -> const ast::Expression* {
+        auto vecN_u32 = [&](const Expression* value) -> const Expression* {
             if (width == 1) {
                 return value;
             }
             return b.Call(b.ty.vec<u32>(width), value);
         };
 
-        utils::Vector<const ast::Statement*, 8> body{
+        utils::Vector<const Statement*, 8> body{
             b.Decl(b.Let("s", b.Call("min", "offset", u32(W)))),
             b.Decl(b.Let("e", b.Call("min", u32(W), b.Add("s", "count")))),
         };
@@ -465,17 +465,17 @@
             }
             return b.ty.vec<u32>(width);
         };
-        auto V = [&](uint32_t value) -> const ast::Expression* {
+        auto V = [&](uint32_t value) -> const Expression* {
             return ScalarOrVector(width, u32(value));
         };
-        auto B = [&](const ast::Expression* value) -> const ast::Expression* {
+        auto B = [&](const Expression* value) -> const Expression* {
             if (width == 1) {
                 return b.Call<bool>(value);
             }
             return b.Call(b.ty.vec<bool>(width), value);
         };
 
-        const ast::Expression* x = nullptr;
+        const Expression* x = nullptr;
         if (ty->is_unsigned_integer_scalar_or_vector()) {
             x = b.Expr("v");
         } else {
@@ -537,10 +537,10 @@
             }
             return b.ty.vec<u32>(width);
         };
-        auto V = [&](uint32_t value) -> const ast::Expression* {
+        auto V = [&](uint32_t value) -> const Expression* {
             return ScalarOrVector(width, u32(value));
         };
-        auto B = [&](const ast::Expression* value) -> const ast::Expression* {
+        auto B = [&](const Expression* value) -> const Expression* {
             if (width == 1) {
                 return b.Call<bool>(value);
             }
@@ -599,8 +599,8 @@
 
         constexpr uint32_t W = 32u;  // 32-bit
 
-        auto V = [&](auto value) -> const ast::Expression* {
-            const ast::Expression* expr = b.Expr(value);
+        auto V = [&](auto value) -> const Expression* {
+            const Expression* expr = b.Expr(value);
             if (!ty->is_unsigned_integer_scalar_or_vector()) {
                 expr = b.Call<i32>(expr);
             }
@@ -609,7 +609,7 @@
             }
             return expr;
         };
-        auto U = [&](auto value) -> const ast::Expression* {
+        auto U = [&](auto value) -> const Expression* {
             if (width == 1) {
                 return b.Expr(value);
             }
@@ -638,7 +638,7 @@
         //          return ((select(T(), n << offset, offset < 32u) & mask) | (v & ~(mask)));
         //      }
 
-        utils::Vector<const ast::Statement*, 8> body;
+        utils::Vector<const Statement*, 8> body;
 
         switch (cfg.builtins.insert_bits) {
             case Level::kFull:
@@ -788,7 +788,7 @@
     /// @return the polyfill function name
     Symbol quantizeToF16(const type::Vector* vec) {
         auto name = b.Symbols().New("tint_quantizeToF16");
-        utils::Vector<const ast::Expression*, 4> args;
+        utils::Vector<const Expression*, 4> args;
         for (uint32_t i = 0; i < vec->Width(); i++) {
             args.Push(b.Call("quantizeToF16", b.IndexAccessor("v", u32(i))));
         }
@@ -880,29 +880,29 @@
     /// the RHS is modulo the bit-width of the LHS.
     /// @param bin_op the original BinaryExpression
     /// @return the polyfill value for bitshift operation
-    const ast::Expression* BitshiftModulo(const ast::BinaryExpression* bin_op) {
+    const Expression* BitshiftModulo(const BinaryExpression* bin_op) {
         auto* lhs_ty = src->TypeOf(bin_op->lhs)->UnwrapRef();
         auto* rhs_ty = src->TypeOf(bin_op->rhs)->UnwrapRef();
         auto* lhs_el_ty = type::Type::DeepestElementOf(lhs_ty);
-        const ast::Expression* mask = b.Expr(AInt(lhs_el_ty->Size() * 8 - 1));
+        const Expression* mask = b.Expr(AInt(lhs_el_ty->Size() * 8 - 1));
         if (rhs_ty->Is<type::Vector>()) {
             mask = b.Call(CreateASTTypeFor(ctx, rhs_ty), mask);
         }
         auto* lhs = ctx.Clone(bin_op->lhs);
         auto* rhs = b.And(ctx.Clone(bin_op->rhs), mask);
-        return b.create<ast::BinaryExpression>(ctx.Clone(bin_op->source), bin_op->op, lhs, rhs);
+        return b.create<BinaryExpression>(ctx.Clone(bin_op->source), bin_op->op, lhs, rhs);
     }
 
     /// Builds the polyfill inline expression for a integer divide or modulo, preventing DBZs and
     /// integer overflows.
     /// @param bin_op the original BinaryExpression
     /// @return the polyfill divide or modulo
-    const ast::Expression* IntDivMod(const ast::BinaryExpression* bin_op) {
+    const Expression* IntDivMod(const BinaryExpression* bin_op) {
         auto* lhs_ty = src->TypeOf(bin_op->lhs)->UnwrapRef();
         auto* rhs_ty = src->TypeOf(bin_op->rhs)->UnwrapRef();
         BinaryOpSignature sig{bin_op->op, lhs_ty, rhs_ty};
         auto fn = binary_op_polyfills.GetOrCreate(sig, [&] {
-            const bool is_div = bin_op->op == ast::BinaryOp::kDivide;
+            const bool is_div = bin_op->op == BinaryOp::kDivide;
 
             uint32_t lhs_width = 1;
             uint32_t rhs_width = 1;
@@ -914,7 +914,7 @@
             const char* lhs = "lhs";
             const char* rhs = "rhs";
 
-            utils::Vector<const ast::Statement*, 4> body;
+            utils::Vector<const Statement*, 4> body;
 
             if (lhs_width < width) {
                 // lhs is scalar, rhs is vector. Convert lhs to vector.
@@ -934,8 +934,8 @@
             if (lhs_ty->is_signed_integer_scalar_or_vector()) {
                 const auto bits = lhs_el_ty->Size() * 8;
                 auto min_int = AInt(AInt::kLowestValue >> (AInt::kNumBits - bits));
-                const ast::Expression* lhs_is_min = b.Equal(lhs, ScalarOrVector(width, min_int));
-                const ast::Expression* rhs_is_minus_one = b.Equal(rhs, ScalarOrVector(width, -1_a));
+                const Expression* lhs_is_min = b.Equal(lhs, ScalarOrVector(width, min_int));
+                const Expression* rhs_is_minus_one = b.Equal(rhs, ScalarOrVector(width, -1_a));
                 // use_one = rhs_is_zero | ((lhs == MIN_INT) & (rhs == -1))
                 auto* use_one = b.Or(rhs_is_zero, b.And(lhs_is_min, rhs_is_minus_one));
 
@@ -992,7 +992,7 @@
     /// Builds the polyfill inline expression for a precise float modulo, as defined in the spec.
     /// @param bin_op the original BinaryExpression
     /// @return the polyfill divide or modulo
-    const ast::Expression* PreciseFloatMod(const ast::BinaryExpression* bin_op) {
+    const Expression* PreciseFloatMod(const BinaryExpression* bin_op) {
         auto* lhs_ty = src->TypeOf(bin_op->lhs)->UnwrapRef();
         auto* rhs_ty = src->TypeOf(bin_op->rhs)->UnwrapRef();
         BinaryOpSignature sig{bin_op->op, lhs_ty, rhs_ty};
@@ -1007,7 +1007,7 @@
             const char* lhs = "lhs";
             const char* rhs = "rhs";
 
-            utils::Vector<const ast::Statement*, 4> body;
+            utils::Vector<const Statement*, 4> body;
 
             if (lhs_width < width) {
                 // lhs is scalar, rhs is vector. Convert lhs to vector.
@@ -1042,7 +1042,7 @@
     }
 
     /// @returns the AST type for the given sem type
-    ast::Type T(const type::Type* ty) { return CreateASTTypeFor(ctx, ty); }
+    Type T(const type::Type* ty) { return CreateASTTypeFor(ctx, ty); }
 
     /// @returns 1 if `ty` is not a vector, otherwise the vector width
     uint32_t WidthOf(const type::Type* ty) const {
@@ -1055,7 +1055,7 @@
     /// @returns a scalar or vector with the given width, with each element with
     /// the given value.
     template <typename T>
-    const ast::Expression* ScalarOrVector(uint32_t width, T value) {
+    const Expression* ScalarOrVector(uint32_t width, T value) {
         if (width == 1) {
             return b.Expr(value);
         }
@@ -1063,7 +1063,7 @@
     }
 
     template <typename To>
-    const ast::Expression* CastScalarOrVector(uint32_t width, const ast::Expression* e) {
+    const Expression* CastScalarOrVector(uint32_t width, const Expression* e) {
         if (width == 1) {
             return b.Call(b.ty.Of<To>(), e);
         }
@@ -1071,7 +1071,7 @@
     }
 
     /// Examines the call expression @p expr, applying any necessary polyfill transforms
-    void Call(const ast::CallExpression* expr) {
+    void Call(const CallExpression* expr) {
         auto* call = src->Sem().Get(expr)->UnwrapMaterialize()->As<sem::Call>();
         if (!call || call->Stage() == sem::EvaluationStage::kConstant ||
             call->Stage() == sem::EvaluationStage::kNotEvaluated) {
@@ -1207,7 +1207,7 @@
                                     size_t value_idx = static_cast<size_t>(
                                         sig.IndexOf(sem::ParameterUsage::kValue));
                                     ctx.Replace(expr, [this, expr, value_idx] {
-                                        utils::Vector<const ast::Expression*, 3> args;
+                                        utils::Vector<const Expression*, 3> args;
                                         for (auto* arg : expr->args) {
                                             arg = ctx.Clone(arg);
                                             if (args.Length() == value_idx) {  // value
@@ -1288,4 +1288,4 @@
 BuiltinPolyfill::Config::Config(const Config&) = default;
 BuiltinPolyfill::Config::~Config() = default;
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/builtin_polyfill.h b/src/tint/ast/transform/builtin_polyfill.h
similarity index 92%
rename from src/tint/transform/builtin_polyfill.h
rename to src/tint/ast/transform/builtin_polyfill.h
index e42ba8f..1973d9e 100644
--- a/src/tint/transform/builtin_polyfill.h
+++ b/src/tint/ast/transform/builtin_polyfill.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_BUILTIN_POLYFILL_H_
-#define SRC_TINT_TRANSFORM_BUILTIN_POLYFILL_H_
+#ifndef SRC_TINT_AST_TRANSFORM_BUILTIN_POLYFILL_H_
+#define SRC_TINT_AST_TRANSFORM_BUILTIN_POLYFILL_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// Implements builtins for backends that do not have a native implementation.
 class BuiltinPolyfill final : public utils::Castable<BuiltinPolyfill, Transform> {
@@ -89,7 +89,7 @@
 
     /// Config is consumed by the BuiltinPolyfill transform.
     /// Config specifies the builtins that should be polyfilled.
-    struct Config final : public utils::Castable<Data, transform::Data> {
+    struct Config final : public utils::Castable<Config, Data> {
         /// Constructor
         /// @param b the list of builtins to polyfill
         explicit Config(const Builtins& b);
@@ -113,6 +113,6 @@
     struct State;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_BUILTIN_POLYFILL_H_
+#endif  // SRC_TINT_AST_TRANSFORM_BUILTIN_POLYFILL_H_
diff --git a/src/tint/transform/builtin_polyfill_test.cc b/src/tint/ast/transform/builtin_polyfill_test.cc
similarity index 99%
rename from src/tint/transform/builtin_polyfill_test.cc
rename to src/tint/ast/transform/builtin_polyfill_test.cc
index ad47af6..e48ab70 100644
--- a/src/tint/transform/builtin_polyfill_test.cc
+++ b/src/tint/ast/transform/builtin_polyfill_test.cc
@@ -12,14 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/builtin_polyfill.h"
+#include "src/tint/ast/transform/builtin_polyfill.h"
 
 #include <utility>
 
-#include "src/tint/transform/direct_variable_access.h"
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/direct_variable_access.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using Level = BuiltinPolyfill::Level;
@@ -4030,4 +4030,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/calculate_array_length.cc b/src/tint/ast/transform/calculate_array_length.cc
similarity index 92%
rename from src/tint/transform/calculate_array_length.cc
rename to src/tint/ast/transform/calculate_array_length.cc
index 4a3598d..59f684a 100644
--- a/src/tint/transform/calculate_array_length.cc
+++ b/src/tint/ast/transform/calculate_array_length.cc
@@ -12,13 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/calculate_array_length.h"
+#include "src/tint/ast/transform/calculate_array_length.h"
 
 #include <unordered_map>
 #include <utility>
 
 #include "src/tint/ast/call_statement.h"
 #include "src/tint/ast/disable_validation_attribute.h"
+#include "src/tint/ast/transform/simplify_pointers.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/block_statement.h"
 #include "src/tint/sem/call.h"
@@ -27,17 +28,16 @@
 #include "src/tint/sem/struct.h"
 #include "src/tint/sem/variable.h"
 #include "src/tint/switch.h"
-#include "src/tint/transform/simplify_pointers.h"
 #include "src/tint/type/reference.h"
 #include "src/tint/utils/hash.h"
 #include "src/tint/utils/map.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::CalculateArrayLength);
-TINT_INSTANTIATE_TYPEINFO(tint::transform::CalculateArrayLength::BufferSizeIntrinsic);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::CalculateArrayLength);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::CalculateArrayLength::BufferSizeIntrinsic);
 
 using namespace tint::number_suffixes;  // NOLINT
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 namespace {
 
@@ -57,7 +57,7 @@
 /// ArrayUsage describes a runtime array usage.
 /// It is used as a key by the array_length_by_usage map.
 struct ArrayUsage {
-    ast::BlockStatement const* const block;
+    BlockStatement const* const block;
     sem::Variable const* const buffer;
     bool operator==(const ArrayUsage& rhs) const {
         return block == rhs.block && buffer == rhs.buffer;
@@ -71,7 +71,7 @@
 
 }  // namespace
 
-CalculateArrayLength::BufferSizeIntrinsic::BufferSizeIntrinsic(ProgramID pid, ast::NodeID nid)
+CalculateArrayLength::BufferSizeIntrinsic::BufferSizeIntrinsic(ProgramID pid, NodeID nid)
     : Base(pid, nid, utils::Empty) {}
 CalculateArrayLength::BufferSizeIntrinsic::~BufferSizeIntrinsic() = default;
 std::string CalculateArrayLength::BufferSizeIntrinsic::InternalName() const {
@@ -106,7 +106,7 @@
         return utils::GetOrCreate(buffer_size_intrinsics, buffer_type, [&] {
             auto name = b.Sym();
             auto type = CreateASTTypeFor(ctx, buffer_type);
-            auto* disable_validation = b.Disable(ast::DisabledValidation::kFunctionParameter);
+            auto* disable_validation = b.Disable(DisabledValidation::kFunctionParameter);
             b.Func(
                 name,
                 utils::Vector{
@@ -128,13 +128,13 @@
 
     // Find all the arrayLength() calls...
     for (auto* node : src->ASTNodes().Objects()) {
-        if (auto* call_expr = node->As<ast::CallExpression>()) {
+        if (auto* call_expr = node->As<CallExpression>()) {
             auto* call = sem.Get(call_expr)->UnwrapMaterialize()->As<sem::Call>();
             if (auto* builtin = call->Target()->As<sem::Builtin>()) {
                 if (builtin->Type() == builtin::Function::kArrayLength) {
                     // We're dealing with an arrayLength() call
 
-                    if (auto* call_stmt = call->Stmt()->Declaration()->As<ast::CallStatement>()) {
+                    if (auto* call_stmt = call->Stmt()->Declaration()->As<CallStatement>()) {
                         if (call_stmt->expr == call_expr) {
                             // arrayLength() is used as a statement.
                             // The argument expression must be side-effect free, so just drop the
@@ -151,13 +151,13 @@
                     //   arrayLength(&struct_var.array_member)
                     //   arrayLength(&array_var)
                     auto* arg = call_expr->args[0];
-                    auto* address_of = arg->As<ast::UnaryOpExpression>();
-                    if (TINT_UNLIKELY(!address_of || address_of->op != ast::UnaryOp::kAddressOf)) {
+                    auto* address_of = arg->As<UnaryOpExpression>();
+                    if (TINT_UNLIKELY(!address_of || address_of->op != UnaryOp::kAddressOf)) {
                         TINT_ICE(Transform, b.Diagnostics())
                             << "arrayLength() expected address-of, got " << arg->TypeInfo().name;
                     }
                     auto* storage_buffer_expr = address_of->expr;
-                    if (auto* accessor = storage_buffer_expr->As<ast::MemberAccessorExpression>()) {
+                    if (auto* accessor = storage_buffer_expr->As<MemberAccessorExpression>()) {
                         storage_buffer_expr = accessor->object;
                     }
                     auto* storage_buffer_sem = sem.Get<sem::VariableUser>(storage_buffer_expr);
@@ -199,8 +199,7 @@
                             // array_length = ----------------------------------------
                             //                             array_stride
                             auto name = b.Sym();
-                            const ast::Expression* total_size =
-                                b.Expr(buffer_size_result->variable);
+                            const Expression* total_size = b.Expr(buffer_size_result->variable);
 
                             const type::Array* array_type = Switch(
                                 storage_buffer_type->StoreType(),
@@ -245,4 +244,4 @@
     return Program(std::move(b));
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/calculate_array_length.h b/src/tint/ast/transform/calculate_array_length.h
similarity index 83%
rename from src/tint/transform/calculate_array_length.h
rename to src/tint/ast/transform/calculate_array_length.h
index 6ebb65c..cab9c24 100644
--- a/src/tint/transform/calculate_array_length.h
+++ b/src/tint/ast/transform/calculate_array_length.h
@@ -12,20 +12,20 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_CALCULATE_ARRAY_LENGTH_H_
-#define SRC_TINT_TRANSFORM_CALCULATE_ARRAY_LENGTH_H_
+#ifndef SRC_TINT_AST_TRANSFORM_CALCULATE_ARRAY_LENGTH_H_
+#define SRC_TINT_AST_TRANSFORM_CALCULATE_ARRAY_LENGTH_H_
 
 #include <string>
 
 #include "src/tint/ast/internal_attribute.h"
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
 // Forward declarations
 namespace tint {
 class CloneContext;
 }  // namespace tint
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// CalculateArrayLength is a transform used to replace calls to arrayLength()
 /// with a value calculated from the size of the storage buffer.
@@ -37,12 +37,12 @@
     /// BufferSizeIntrinsic is an InternalAttribute that's applied to intrinsic
     /// functions used to obtain the runtime size of a storage buffer.
     class BufferSizeIntrinsic final
-        : public utils::Castable<BufferSizeIntrinsic, ast::InternalAttribute> {
+        : public utils::Castable<BufferSizeIntrinsic, InternalAttribute> {
       public:
         /// Constructor
         /// @param program_id the identifier of the program that owns this node
         /// @param nid the unique node identifier
-        BufferSizeIntrinsic(ProgramID program_id, ast::NodeID nid);
+        BufferSizeIntrinsic(ProgramID program_id, NodeID nid);
         /// Destructor
         ~BufferSizeIntrinsic() override;
 
@@ -66,6 +66,6 @@
                       DataMap& outputs) const override;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_CALCULATE_ARRAY_LENGTH_H_
+#endif  // SRC_TINT_AST_TRANSFORM_CALCULATE_ARRAY_LENGTH_H_
diff --git a/src/tint/transform/calculate_array_length_test.cc b/src/tint/ast/transform/calculate_array_length_test.cc
similarity index 97%
rename from src/tint/transform/calculate_array_length_test.cc
rename to src/tint/ast/transform/calculate_array_length_test.cc
index 98f2ed7..5930540 100644
--- a/src/tint/transform/calculate_array_length_test.cc
+++ b/src/tint/ast/transform/calculate_array_length_test.cc
@@ -12,13 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/calculate_array_length.h"
+#include "src/tint/ast/transform/calculate_array_length.h"
 
-#include "src/tint/transform/simplify_pointers.h"
-#include "src/tint/transform/test_helper.h"
-#include "src/tint/transform/unshadow.h"
+#include "src/tint/ast/transform/simplify_pointers.h"
+#include "src/tint/ast/transform/test_helper.h"
+#include "src/tint/ast/transform/unshadow.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using CalculateArrayLengthTest = TransformTest;
@@ -548,4 +548,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/canonicalize_entry_point_io.cc b/src/tint/ast/transform/canonicalize_entry_point_io.cc
similarity index 84%
rename from src/tint/transform/canonicalize_entry_point_io.cc
rename to src/tint/ast/transform/canonicalize_entry_point_io.cc
index 9e9368a..08999e2 100644
--- a/src/tint/transform/canonicalize_entry_point_io.cc
+++ b/src/tint/ast/transform/canonicalize_entry_point_io.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/canonicalize_entry_point_io.h"
+#include "src/tint/ast/transform/canonicalize_entry_point_io.h"
 
 #include <algorithm>
 #include <string>
@@ -21,17 +21,17 @@
 #include <vector>
 
 #include "src/tint/ast/disable_validation_attribute.h"
+#include "src/tint/ast/transform/unshadow.h"
 #include "src/tint/builtin/builtin_value.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/function.h"
-#include "src/tint/transform/unshadow.h"
 
 using namespace tint::number_suffixes;  // NOLINT
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::CanonicalizeEntryPointIO);
-TINT_INSTANTIATE_TYPEINFO(tint::transform::CanonicalizeEntryPointIO::Config);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::CanonicalizeEntryPointIO);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::CanonicalizeEntryPointIO::Config);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 CanonicalizeEntryPointIO::CanonicalizeEntryPointIO() = default;
 CanonicalizeEntryPointIO::~CanonicalizeEntryPointIO() = default;
@@ -41,7 +41,7 @@
 /// Info for a struct member
 struct MemberInfo {
     /// The struct member item
-    const ast::StructMember* member;
+    const StructMember* member;
     /// The struct member location if provided
     std::optional<uint32_t> location;
 };
@@ -83,9 +83,9 @@
 }
 
 // Returns true if `attr` is a shader IO attribute.
-bool IsShaderIOAttribute(const ast::Attribute* attr) {
-    return attr->IsAnyOf<ast::BuiltinAttribute, ast::InterpolateAttribute, ast::InvariantAttribute,
-                         ast::LocationAttribute>();
+bool IsShaderIOAttribute(const Attribute* attr) {
+    return attr
+        ->IsAnyOf<BuiltinAttribute, InterpolateAttribute, InvariantAttribute, LocationAttribute>();
 }
 
 }  // namespace
@@ -97,11 +97,11 @@
         /// The name of the output value.
         std::string name;
         /// The type of the output value.
-        ast::Type type;
+        Type type;
         /// The shader IO attributes.
-        utils::Vector<const ast::Attribute*, 8> attributes;
+        utils::Vector<const Attribute*, 8> attributes;
         /// The value itself.
-        const ast::Expression* value;
+        const Expression* value;
         /// The output location.
         std::optional<uint32_t> location;
     };
@@ -111,29 +111,29 @@
     /// The transform config.
     CanonicalizeEntryPointIO::Config const cfg;
     /// The entry point function (AST).
-    const ast::Function* func_ast;
+    const Function* func_ast;
     /// The entry point function (SEM).
     const sem::Function* func_sem;
 
     /// The new entry point wrapper function's parameters.
-    utils::Vector<const ast::Parameter*, 8> wrapper_ep_parameters;
+    utils::Vector<const Parameter*, 8> wrapper_ep_parameters;
 
     /// The members of the wrapper function's struct parameter.
     utils::Vector<MemberInfo, 8> wrapper_struct_param_members;
     /// The name of the wrapper function's struct parameter.
     Symbol wrapper_struct_param_name;
     /// The parameters that will be passed to the original function.
-    utils::Vector<const ast::Expression*, 8> inner_call_parameters;
+    utils::Vector<const Expression*, 8> inner_call_parameters;
     /// The members of the wrapper function's struct return type.
     utils::Vector<MemberInfo, 8> wrapper_struct_output_members;
     /// The wrapper function output values.
     utils::Vector<OutputValue, 8> wrapper_output_values;
     /// The body of the wrapper function.
-    utils::Vector<const ast::Statement*, 8> wrapper_body;
+    utils::Vector<const Statement*, 8> wrapper_body;
     /// Input names used by the entrypoint
     std::unordered_set<std::string> input_names;
     /// A map of cloned attribute to builtin value
-    utils::Hashmap<const ast::BuiltinAttribute*, builtin::BuiltinValue, 16> builtin_attrs;
+    utils::Hashmap<const BuiltinAttribute*, builtin::BuiltinValue, 16> builtin_attrs;
 
     /// Constructor
     /// @param context the clone context
@@ -141,7 +141,7 @@
     /// @param function the entry point function
     State(CloneContext& context,
           const CanonicalizeEntryPointIO::Config& config,
-          const ast::Function* function)
+          const Function* function)
         : ctx(context), cfg(config), func_ast(function), func_sem(ctx.src->Sem().Get(function)) {}
 
     /// Clones the attributes from @p in and adds it to @p out. If @p in is a builtin attribute,
@@ -149,12 +149,11 @@
     /// @param in the attribute to clone
     /// @param out the output Attributes
     template <size_t N>
-    void CloneAttribute(const ast::Attribute* in, utils::Vector<const ast::Attribute*, N>& out) {
+    void CloneAttribute(const Attribute* in, utils::Vector<const Attribute*, N>& out) {
         auto* cloned = ctx.Clone(in);
         out.Push(cloned);
-        if (auto* builtin = in->As<ast::BuiltinAttribute>()) {
-            builtin_attrs.Add(cloned->As<ast::BuiltinAttribute>(),
-                              ctx.src->Sem().Get(builtin)->Value());
+        if (auto* builtin = in->As<BuiltinAttribute>()) {
+            builtin_attrs.Add(cloned->As<BuiltinAttribute>(), ctx.src->Sem().Get(builtin)->Value());
         }
     }
 
@@ -163,12 +162,11 @@
     /// @param do_interpolate whether to clone InterpolateAttribute
     /// @return the cloned attributes
     template <size_t N>
-    auto CloneShaderIOAttributes(const utils::Vector<const ast::Attribute*, N> in,
-                                 bool do_interpolate) {
-        utils::Vector<const ast::Attribute*, N> out;
+    auto CloneShaderIOAttributes(const utils::Vector<const Attribute*, N> in, bool do_interpolate) {
+        utils::Vector<const Attribute*, N> out;
         for (auto* attr : in) {
             if (IsShaderIOAttribute(attr) &&
-                (do_interpolate || !attr->template Is<ast::InterpolateAttribute>())) {
+                (do_interpolate || !attr->template Is<InterpolateAttribute>())) {
                 CloneAttribute(attr, out);
             }
         }
@@ -177,7 +175,7 @@
 
     /// @param attr the input attribute
     /// @returns the builtin value of the attribute
-    builtin::BuiltinValue BuiltinOf(const ast::BuiltinAttribute* attr) {
+    builtin::BuiltinValue BuiltinOf(const BuiltinAttribute* attr) {
         if (attr->program_id == ctx.dst->ID()) {
             // attr belongs to the target program.
             // Obtain the builtin value from #builtin_attrs.
@@ -197,8 +195,8 @@
     /// @param attrs the input attribute list
     /// @returns the builtin value if any of the attributes in @p attrs is a builtin attribute,
     /// otherwise builtin::BuiltinValue::kUndefined
-    builtin::BuiltinValue BuiltinOf(utils::VectorRef<const ast::Attribute*> attrs) {
-        if (auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(attrs)) {
+    builtin::BuiltinValue BuiltinOf(utils::VectorRef<const Attribute*> attrs) {
+        if (auto* builtin = GetAttribute<BuiltinAttribute>(attrs)) {
             return BuiltinOf(builtin);
         }
         return builtin::BuiltinValue::kUndefined;
@@ -219,10 +217,10 @@
     /// @param location the location if provided
     /// @param attrs the attributes to apply to the shader input
     /// @returns an expression which evaluates to the value of the shader input
-    const ast::Expression* AddInput(std::string name,
-                                    const type::Type* type,
-                                    std::optional<uint32_t> location,
-                                    utils::Vector<const ast::Attribute*, 8> attrs) {
+    const Expression* AddInput(std::string name,
+                               const type::Type* type,
+                               std::optional<uint32_t> location,
+                               utils::Vector<const Attribute*, 8> attrs) {
         auto ast_type = CreateASTTypeFor(ctx, type);
 
         auto builtin_attr = BuiltinOf(attrs);
@@ -233,17 +231,16 @@
             // https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/StandaloneSpirv.html#VUID-StandaloneSpirv-Flat-04744
             // TODO(crbug.com/tint/1224): Remove this once a flat interpolation attribute is
             // required for integers.
-            if (func_ast->PipelineStage() == ast::PipelineStage::kFragment &&
-                type->is_integer_scalar_or_vector() &&
-                !ast::HasAttribute<ast::InterpolateAttribute>(attrs) &&
-                (ast::HasAttribute<ast::LocationAttribute>(attrs) ||
+            if (func_ast->PipelineStage() == PipelineStage::kFragment &&
+                type->is_integer_scalar_or_vector() && !HasAttribute<InterpolateAttribute>(attrs) &&
+                (HasAttribute<LocationAttribute>(attrs) ||
                  cfg.shader_style == ShaderStyle::kSpirv)) {
                 attrs.Push(ctx.dst->Interpolate(builtin::InterpolationType::kFlat,
                                                 builtin::InterpolationSampling::kUndefined));
             }
 
             // Disable validation for use of the `input` address space.
-            attrs.Push(ctx.dst->Disable(ast::DisabledValidation::kIgnoreAddressSpace));
+            attrs.Push(ctx.dst->Disable(DisabledValidation::kIgnoreAddressSpace));
 
             // In GLSL, if it's a builtin, override the name with the
             // corresponding gl_ builtin name
@@ -255,7 +252,7 @@
             auto symbol = ctx.dst->Symbols().New(name);
 
             // Create the global variable and use its value for the shader input.
-            const ast::Expression* value = ctx.dst->Expr(symbol);
+            const Expression* value = ctx.dst->Expr(symbol);
 
             if (builtin_attr != builtin::BuiltinValue::kUndefined) {
                 if (cfg.shader_style == ShaderStyle::kGlsl) {
@@ -296,18 +293,17 @@
     void AddOutput(std::string name,
                    const type::Type* type,
                    std::optional<uint32_t> location,
-                   utils::Vector<const ast::Attribute*, 8> attrs,
-                   const ast::Expression* value) {
+                   utils::Vector<const Attribute*, 8> attrs,
+                   const Expression* value) {
         auto builtin_attr = BuiltinOf(attrs);
         // Vulkan requires that integer user-defined vertex outputs are always decorated with
         // `Flat`.
         // TODO(crbug.com/tint/1224): Remove this once a flat interpolation attribute is required
         // for integers.
         if (cfg.shader_style == ShaderStyle::kSpirv &&
-            func_ast->PipelineStage() == ast::PipelineStage::kVertex &&
-            type->is_integer_scalar_or_vector() &&
-            ast::HasAttribute<ast::LocationAttribute>(attrs) &&
-            !ast::HasAttribute<ast::InterpolateAttribute>(attrs)) {
+            func_ast->PipelineStage() == PipelineStage::kVertex &&
+            type->is_integer_scalar_or_vector() && HasAttribute<LocationAttribute>(attrs) &&
+            !HasAttribute<InterpolateAttribute>(attrs)) {
             attrs.Push(ctx.dst->Interpolate(builtin::InterpolationType::kFlat,
                                             builtin::InterpolationSampling::kUndefined));
         }
@@ -338,14 +334,14 @@
     /// @param param the original function parameter
     void ProcessNonStructParameter(const sem::Parameter* param) {
         // Do not add interpolation attributes on vertex input
-        bool do_interpolate = func_ast->PipelineStage() != ast::PipelineStage::kVertex;
+        bool do_interpolate = func_ast->PipelineStage() != PipelineStage::kVertex;
         // Remove the shader IO attributes from the inner function parameter, and attach them to the
         // new object instead.
-        utils::Vector<const ast::Attribute*, 8> attributes;
+        utils::Vector<const Attribute*, 8> attributes;
         for (auto* attr : param->Declaration()->attributes) {
             if (IsShaderIOAttribute(attr)) {
                 ctx.Remove(param->Declaration()->attributes, attr);
-                if ((do_interpolate || !attr->Is<ast::InterpolateAttribute>())) {
+                if ((do_interpolate || !attr->Is<InterpolateAttribute>())) {
                     CloneAttribute(attr, attributes);
                 }
             }
@@ -363,13 +359,13 @@
     /// @param param the original function parameter
     void ProcessStructParameter(const sem::Parameter* param) {
         // Do not add interpolation attributes on vertex input
-        bool do_interpolate = func_ast->PipelineStage() != ast::PipelineStage::kVertex;
+        bool do_interpolate = func_ast->PipelineStage() != PipelineStage::kVertex;
 
         auto* str = param->Type()->As<sem::Struct>();
 
         // Recreate struct members in the outer entry point and build an initializer
         // list to pass them through to the inner function.
-        utils::Vector<const ast::Expression*, 8> inner_struct_values;
+        utils::Vector<const Expression*, 8> inner_struct_values;
         for (auto* member : str->Members()) {
             if (TINT_UNLIKELY(member->Type()->Is<type::Struct>())) {
                 TINT_ICE(Transform, ctx.dst->Diagnostics()) << "nested IO struct";
@@ -397,7 +393,7 @@
     /// @param original_result the result object produced by the original function
     void ProcessReturnType(const type::Type* inner_ret_type, Symbol original_result) {
         // Do not add interpolation attributes on fragment output
-        bool do_interpolate = func_ast->PipelineStage() != ast::PipelineStage::kFragment;
+        bool do_interpolate = func_ast->PipelineStage() != PipelineStage::kFragment;
         if (auto* str = inner_ret_type->As<sem::Struct>()) {
             for (auto* member : str->Members()) {
                 if (TINT_UNLIKELY(member->Type()->Is<type::Struct>())) {
@@ -456,7 +452,7 @@
     /// Create an expression for gl_Position.[component]
     /// @param component the component of gl_Position to access
     /// @returns the new expression
-    const ast::Expression* GLPosition(const char* component) {
+    const Expression* GLPosition(const char* component) {
         Symbol pos = ctx.dst->Symbols().Register("gl_Position");
         Symbol c = ctx.dst->Symbols().Register(component);
         return ctx.dst->MemberAccessor(ctx.dst->Expr(pos), c);
@@ -469,10 +465,10 @@
     /// @param b another struct member
     /// @returns true if a comes before b
     bool StructMemberComparator(const MemberInfo& a, const MemberInfo& b) {
-        auto* a_loc = ast::GetAttribute<ast::LocationAttribute>(a.member->attributes);
-        auto* b_loc = ast::GetAttribute<ast::LocationAttribute>(b.member->attributes);
-        auto* a_blt = ast::GetAttribute<ast::BuiltinAttribute>(a.member->attributes);
-        auto* b_blt = ast::GetAttribute<ast::BuiltinAttribute>(b.member->attributes);
+        auto* a_loc = GetAttribute<LocationAttribute>(a.member->attributes);
+        auto* b_loc = GetAttribute<LocationAttribute>(b.member->attributes);
+        auto* a_blt = GetAttribute<BuiltinAttribute>(a.member->attributes);
+        auto* b_blt = GetAttribute<BuiltinAttribute>(b.member->attributes);
         if (a_loc) {
             if (!b_loc) {
                 // `a` has location attribute and `b` does not: `a` goes first.
@@ -497,15 +493,15 @@
         std::sort(wrapper_struct_param_members.begin(), wrapper_struct_param_members.end(),
                   [&](auto& a, auto& b) { return StructMemberComparator(a, b); });
 
-        utils::Vector<const ast::StructMember*, 8> members;
+        utils::Vector<const StructMember*, 8> members;
         for (auto& mem : wrapper_struct_param_members) {
             members.Push(mem.member);
         }
 
         // Create the new struct type.
         auto struct_name = ctx.dst->Sym();
-        auto* in_struct = ctx.dst->create<ast::Struct>(ctx.dst->Ident(struct_name),
-                                                       std::move(members), utils::Empty);
+        auto* in_struct =
+            ctx.dst->create<Struct>(ctx.dst->Ident(struct_name), std::move(members), utils::Empty);
         ctx.InsertBefore(ctx.src->AST().GlobalDeclarations(), func_ast, in_struct);
 
         // Create a new function parameter using this struct type.
@@ -515,8 +511,8 @@
 
     /// Create and return the wrapper function's struct result object.
     /// @returns the struct type
-    ast::Struct* CreateOutputStruct() {
-        utils::Vector<const ast::Statement*, 8> assignments;
+    Struct* CreateOutputStruct() {
+        utils::Vector<const Statement*, 8> assignments;
 
         auto wrapper_result = ctx.dst->Symbols().New("wrapper_result");
 
@@ -544,14 +540,14 @@
         std::sort(wrapper_struct_output_members.begin(), wrapper_struct_output_members.end(),
                   [&](auto& a, auto& b) { return StructMemberComparator(a, b); });
 
-        utils::Vector<const ast::StructMember*, 8> members;
+        utils::Vector<const StructMember*, 8> members;
         for (auto& mem : wrapper_struct_output_members) {
             members.Push(mem.member);
         }
 
         // Create the new struct type.
-        auto* out_struct = ctx.dst->create<ast::Struct>(ctx.dst->Ident(ctx.dst->Sym()),
-                                                        std::move(members), utils::Empty);
+        auto* out_struct = ctx.dst->create<Struct>(ctx.dst->Ident(ctx.dst->Sym()),
+                                                   std::move(members), utils::Empty);
         ctx.InsertBefore(ctx.src->AST().GlobalDeclarations(), func_ast, out_struct);
 
         // Create the output struct object, assign its members, and return it.
@@ -570,12 +566,12 @@
         for (auto& outval : wrapper_output_values) {
             // Disable validation for use of the `output` address space.
             auto attributes = std::move(outval.attributes);
-            attributes.Push(ctx.dst->Disable(ast::DisabledValidation::kIgnoreAddressSpace));
+            attributes.Push(ctx.dst->Disable(DisabledValidation::kIgnoreAddressSpace));
 
             // Create the global variable and assign it the output value.
             auto name = ctx.dst->Symbols().New(outval.name);
-            ast::Type type = outval.type;
-            const ast::Expression* lhs = ctx.dst->Expr(name);
+            Type type = outval.type;
+            const Expression* lhs = ctx.dst->Expr(name);
             if (BuiltinOf(attributes) == builtin::BuiltinValue::kSampleMask) {
                 // Vulkan requires the type of a SampleMask builtin to be an array.
                 // Declare it as array<u32, 1> and then store to the first element.
@@ -589,7 +585,7 @@
 
     // Recreate the original function without entry point attributes and call it.
     /// @returns the inner function call expression
-    const ast::CallExpression* CallInnerFunction() {
+    const CallExpression* CallInnerFunction() {
         Symbol inner_name;
         if (cfg.shader_style == ShaderStyle::kGlsl) {
             // In GLSL, clone the original entry point name, as the wrapper will be
@@ -606,9 +602,9 @@
         // The parameter attributes will have already been stripped during
         // processing.
         auto* inner_function =
-            ctx.dst->create<ast::Function>(ctx.dst->Ident(inner_name), ctx.Clone(func_ast->params),
-                                           ctx.Clone(func_ast->return_type),
-                                           ctx.Clone(func_ast->body), utils::Empty, utils::Empty);
+            ctx.dst->create<Function>(ctx.dst->Ident(inner_name), ctx.Clone(func_ast->params),
+                                      ctx.Clone(func_ast->return_type), ctx.Clone(func_ast->body),
+                                      utils::Empty, utils::Empty);
         ctx.Replace(func_ast, inner_function);
 
         // Call the function.
@@ -619,12 +615,11 @@
     void Process() {
         bool needs_fixed_sample_mask = false;
         bool needs_vertex_point_size = false;
-        if (func_ast->PipelineStage() == ast::PipelineStage::kFragment &&
+        if (func_ast->PipelineStage() == PipelineStage::kFragment &&
             cfg.fixed_sample_mask != 0xFFFFFFFF) {
             needs_fixed_sample_mask = true;
         }
-        if (func_ast->PipelineStage() == ast::PipelineStage::kVertex &&
-            cfg.emit_vertex_point_size) {
+        if (func_ast->PipelineStage() == PipelineStage::kVertex && cfg.emit_vertex_point_size) {
             needs_vertex_point_size = true;
         }
 
@@ -656,7 +651,7 @@
         auto* call_inner = CallInnerFunction();
 
         // Process the return type, and start building the wrapper function body.
-        std::function<ast::Type()> wrapper_ret_type = [&] { return ctx.dst->ty.void_(); };
+        std::function<Type()> wrapper_ret_type = [&] { return ctx.dst->ty.void_(); };
         if (func_sem->ReturnType()->Is<type::Void>()) {
             // The function call is just a statement with no result.
             wrapper_body.Push(ctx.dst->CallStmt(call_inner));
@@ -693,10 +688,10 @@
         }
 
         if (cfg.shader_style == ShaderStyle::kGlsl &&
-            func_ast->PipelineStage() == ast::PipelineStage::kVertex) {
+            func_ast->PipelineStage() == PipelineStage::kVertex) {
             auto* pos_y = GLPosition("y");
             auto* negate_pos_y =
-                ctx.dst->create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, GLPosition("y"));
+                ctx.dst->create<UnaryOpExpression>(UnaryOp::kNegation, GLPosition("y"));
             wrapper_body.Push(ctx.dst->Assign(pos_y, negate_pos_y));
 
             auto* two_z = ctx.dst->Mul(ctx.dst->Expr(2_f), GLPosition("z"));
@@ -714,7 +709,7 @@
             name = ctx.Clone(func_ast->name->symbol);
         }
 
-        auto* wrapper_func = ctx.dst->create<ast::Function>(
+        auto* wrapper_func = ctx.dst->create<Function>(
             ctx.dst->Ident(name), wrapper_ep_parameters, ctx.dst->ty(wrapper_ret_type()),
             ctx.dst->Block(wrapper_body), ctx.Clone(func_ast->attributes), utils::Empty);
         ctx.InsertAfter(ctx.src->AST().GlobalDeclarations(), func_ast, wrapper_func);
@@ -726,14 +721,14 @@
     /// @param address_space the address space (input or output)
     /// @returns the gl_ string corresponding to that builtin
     const char* GLSLBuiltinToString(builtin::BuiltinValue builtin,
-                                    ast::PipelineStage stage,
+                                    PipelineStage stage,
                                     builtin::AddressSpace address_space) {
         switch (builtin) {
             case builtin::BuiltinValue::kPosition:
                 switch (stage) {
-                    case ast::PipelineStage::kVertex:
+                    case PipelineStage::kVertex:
                         return "gl_Position";
-                    case ast::PipelineStage::kFragment:
+                    case PipelineStage::kFragment:
                         return "gl_FragCoord";
                     default:
                         return "";
@@ -775,9 +770,9 @@
     /// @param ast_type (inout) the incoming WGSL and outgoing GLSL types
     /// @returns an expression representing the GLSL builtin converted to what
     /// WGSL expects
-    const ast::Expression* FromGLSLBuiltin(builtin::BuiltinValue builtin,
-                                           const ast::Expression* value,
-                                           ast::Type& ast_type) {
+    const Expression* FromGLSLBuiltin(builtin::BuiltinValue builtin,
+                                      const Expression* value,
+                                      Type& ast_type) {
         switch (builtin) {
             case builtin::BuiltinValue::kVertexIndex:
             case builtin::BuiltinValue::kInstanceIndex:
@@ -805,9 +800,9 @@
     /// @param value the value to convert
     /// @param type (out) the type to which the value was converted
     /// @returns the converted value which can be assigned to the GLSL builtin
-    const ast::Expression* ToGLSLBuiltin(builtin::BuiltinValue builtin,
-                                         const ast::Expression* value,
-                                         const type::Type*& type) {
+    const Expression* ToGLSLBuiltin(builtin::BuiltinValue builtin,
+                                    const Expression* value,
+                                    const type::Type*& type) {
         switch (builtin) {
             case builtin::BuiltinValue::kVertexIndex:
             case builtin::BuiltinValue::kInstanceIndex:
@@ -839,7 +834,7 @@
     // Remove entry point IO attributes from struct declarations.
     // New structures will be created for each entry point, as necessary.
     for (auto* ty : src->AST().TypeDecls()) {
-        if (auto* struct_ty = ty->As<ast::Struct>()) {
+        if (auto* struct_ty = ty->As<Struct>()) {
             for (auto* member : struct_ty->members) {
                 for (auto* attr : member->attributes) {
                     if (IsShaderIOAttribute(attr)) {
@@ -873,4 +868,4 @@
 CanonicalizeEntryPointIO::Config::Config(const Config&) = default;
 CanonicalizeEntryPointIO::Config::~Config() = default;
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/canonicalize_entry_point_io.h b/src/tint/ast/transform/canonicalize_entry_point_io.h
similarity index 93%
rename from src/tint/transform/canonicalize_entry_point_io.h
rename to src/tint/ast/transform/canonicalize_entry_point_io.h
index 85e9b22..3ee9ea6 100644
--- a/src/tint/transform/canonicalize_entry_point_io.h
+++ b/src/tint/ast/transform/canonicalize_entry_point_io.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_CANONICALIZE_ENTRY_POINT_IO_H_
-#define SRC_TINT_TRANSFORM_CANONICALIZE_ENTRY_POINT_IO_H_
+#ifndef SRC_TINT_AST_TRANSFORM_CANONICALIZE_ENTRY_POINT_IO_H_
+#define SRC_TINT_AST_TRANSFORM_CANONICALIZE_ENTRY_POINT_IO_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// CanonicalizeEntryPointIO is a transform used to rewrite shader entry point
 /// interfaces into a form that the generators can handle. Each entry point
@@ -136,6 +136,6 @@
     struct State;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_CANONICALIZE_ENTRY_POINT_IO_H_
+#endif  // SRC_TINT_AST_TRANSFORM_CANONICALIZE_ENTRY_POINT_IO_H_
diff --git a/src/tint/transform/canonicalize_entry_point_io_test.cc b/src/tint/ast/transform/canonicalize_entry_point_io_test.cc
similarity index 99%
rename from src/tint/transform/canonicalize_entry_point_io_test.cc
rename to src/tint/ast/transform/canonicalize_entry_point_io_test.cc
index 08b8430..98af3a7 100644
--- a/src/tint/transform/canonicalize_entry_point_io_test.cc
+++ b/src/tint/ast/transform/canonicalize_entry_point_io_test.cc
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/canonicalize_entry_point_io.h"
+#include "src/tint/ast/transform/canonicalize_entry_point_io.h"
 
-#include "src/tint/transform/test_helper.h"
-#include "src/tint/transform/unshadow.h"
+#include "src/tint/ast/transform/test_helper.h"
+#include "src/tint/ast/transform/unshadow.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using CanonicalizeEntryPointIOTest = TransformTest;
@@ -26,8 +26,7 @@
     auto* src = "";
 
     auto* expect =
-        "error: missing transform data for "
-        "tint::transform::CanonicalizeEntryPointIO";
+        "error: missing transform data for tint::ast::transform::CanonicalizeEntryPointIO";
 
     auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src);
 
@@ -3965,4 +3964,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/clamp_frag_depth.cc b/src/tint/ast/transform/clamp_frag_depth.cc
similarity index 89%
rename from src/tint/transform/clamp_frag_depth.cc
rename to src/tint/ast/transform/clamp_frag_depth.cc
index 4948ec5..1e12b1d 100644
--- a/src/tint/transform/clamp_frag_depth.cc
+++ b/src/tint/ast/transform/clamp_frag_depth.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/clamp_frag_depth.h"
+#include "src/tint/ast/transform/clamp_frag_depth.h"
 
 #include <utility>
 
@@ -29,9 +29,9 @@
 #include "src/tint/utils/scoped_assignment.h"
 #include "src/tint/utils/vector.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::ClampFragDepth);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::ClampFragDepth);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// PIMPL state for the transform
 struct ClampFragDepth::State {
@@ -51,7 +51,7 @@
     Transform::ApplyResult Run() {
         // Abort on any use of push constants in the module.
         for (auto* global : src->AST().GlobalVariables()) {
-            if (auto* var = global->As<ast::Var>()) {
+            if (auto* var = global->As<Var>()) {
                 auto* v = src->Sem().Get(var);
                 if (TINT_UNLIKELY(v->AddressSpace() == builtin::AddressSpace::kPushConstant)) {
                     TINT_ICE(Transform, b.Diagnostics())
@@ -101,14 +101,14 @@
 
         // Map of io struct to helper function to return the structure with the depth clamping
         // applied.
-        utils::Hashmap<const ast::Struct*, Symbol, 4u> io_structs_clamp_helpers;
+        utils::Hashmap<const Struct*, Symbol, 4u> io_structs_clamp_helpers;
 
         // Register a callback that will be called for each visted AST function.
         // This call wraps the cloning of the function's statements, and will assign to
         // `returns_frag_depth_as_value` or `returns_frag_depth_as_struct_helper` if the function's
         // return value requires depth clamping.
-        ctx.ReplaceAll([&](const ast::Function* fn) {
-            if (fn->PipelineStage() != ast::PipelineStage::kFragment) {
+        ctx.ReplaceAll([&](const Function* fn) {
+            if (fn->PipelineStage() != PipelineStage::kFragment) {
                 return ctx.CloneWithoutTransform(fn);
             }
 
@@ -129,9 +129,9 @@
                     auto fn_sym =
                         b.Symbols().New("clamp_frag_depth_" + struct_ty->name->symbol.Name());
 
-                    utils::Vector<const ast::Expression*, 8u> initializer_args;
+                    utils::Vector<const Expression*, 8u> initializer_args;
                     for (auto* member : struct_ty->members) {
-                        const ast::Expression* arg =
+                        const Expression* arg =
                             b.MemberAccessor("s", ctx.Clone(member->name->symbol));
                         if (ContainsFragDepth(member->attributes)) {
                             arg = b.Call(base_fn_sym, arg);
@@ -154,7 +154,7 @@
         });
 
         // Replace the return statements `return expr` with `return clamp_frag_depth(expr)`.
-        ctx.ReplaceAll([&](const ast::ReturnStatement* stmt) -> const ast::ReturnStatement* {
+        ctx.ReplaceAll([&](const ReturnStatement* stmt) -> const ReturnStatement* {
             if (returns_frag_depth_as_value) {
                 return b.Return(stmt->source, b.Call(base_fn_sym, ctx.Clone(stmt->value)));
             }
@@ -173,7 +173,7 @@
     /// @returns true if the transform should run
     bool ShouldRun() {
         for (auto* fn : src->AST().Functions()) {
-            if (fn->PipelineStage() == ast::PipelineStage::kFragment &&
+            if (fn->PipelineStage() == PipelineStage::kFragment &&
                 (ReturnsFragDepthAsValue(fn) || ReturnsFragDepthInStruct(fn))) {
                 return true;
             }
@@ -183,9 +183,9 @@
     }
     /// @param attrs the attributes to examine
     /// @returns true if @p attrs contains a `@builtin(frag_depth)` attribute
-    bool ContainsFragDepth(utils::VectorRef<const ast::Attribute*> attrs) {
+    bool ContainsFragDepth(utils::VectorRef<const Attribute*> attrs) {
         for (auto* attribute : attrs) {
-            if (auto* builtin_attr = attribute->As<ast::BuiltinAttribute>()) {
+            if (auto* builtin_attr = attribute->As<BuiltinAttribute>()) {
                 auto builtin = sem.Get(builtin_attr)->Value();
                 if (builtin == builtin::BuiltinValue::kFragDepth) {
                     return true;
@@ -198,14 +198,14 @@
 
     /// @param fn the function to examine
     /// @returns true if @p fn has a return type with a `@builtin(frag_depth)` attribute
-    bool ReturnsFragDepthAsValue(const ast::Function* fn) {
+    bool ReturnsFragDepthAsValue(const Function* fn) {
         return ContainsFragDepth(fn->return_type_attributes);
     }
 
     /// @param fn the function to examine
     /// @returns true if @p fn has a return structure with a `@builtin(frag_depth)` attribute on one
     /// of the members
-    bool ReturnsFragDepthInStruct(const ast::Function* fn) {
+    bool ReturnsFragDepthInStruct(const Function* fn) {
         if (auto* struct_ty = sem.Get(fn)->ReturnType()->As<sem::Struct>()) {
             for (auto* member : struct_ty->Members()) {
                 if (ContainsFragDepth(member->Declaration()->attributes)) {
@@ -225,4 +225,4 @@
     return State{src}.Run();
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/clamp_frag_depth.h b/src/tint/ast/transform/clamp_frag_depth.h
similarity index 87%
rename from src/tint/transform/clamp_frag_depth.h
rename to src/tint/ast/transform/clamp_frag_depth.h
index 88a7ee1..3ba8b2f 100644
--- a/src/tint/transform/clamp_frag_depth.h
+++ b/src/tint/ast/transform/clamp_frag_depth.h
@@ -12,17 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_CLAMP_FRAG_DEPTH_H_
-#define SRC_TINT_TRANSFORM_CLAMP_FRAG_DEPTH_H_
+#ifndef SRC_TINT_AST_TRANSFORM_CLAMP_FRAG_DEPTH_H_
+#define SRC_TINT_AST_TRANSFORM_CLAMP_FRAG_DEPTH_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
 // Forward declarations
 namespace tint {
 class CloneContext;
 }  // namespace tint
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// Add clamping of the `@builtin(frag_depth)` output of fragment shaders using two push constants
 /// provided by the outside environment. For example the following code:
@@ -70,6 +70,6 @@
     struct State;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_CLAMP_FRAG_DEPTH_H_
+#endif  // SRC_TINT_AST_TRANSFORM_CLAMP_FRAG_DEPTH_H_
diff --git a/src/tint/transform/clamp_frag_depth_test.cc b/src/tint/ast/transform/clamp_frag_depth_test.cc
similarity index 97%
rename from src/tint/transform/clamp_frag_depth_test.cc
rename to src/tint/ast/transform/clamp_frag_depth_test.cc
index 7c7019a..7a0ac9f 100644
--- a/src/tint/transform/clamp_frag_depth_test.cc
+++ b/src/tint/ast/transform/clamp_frag_depth_test.cc
@@ -12,11 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/clamp_frag_depth.h"
+#include "src/tint/ast/transform/clamp_frag_depth.h"
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using ClampFragDepthTest = TransformTest;
@@ -378,4 +378,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/combine_samplers.cc b/src/tint/ast/transform/combine_samplers.cc
similarity index 86%
rename from src/tint/transform/combine_samplers.cc
rename to src/tint/ast/transform/combine_samplers.cc
index ebf8126..e3a3d82 100644
--- a/src/tint/transform/combine_samplers.cc
+++ b/src/tint/ast/transform/combine_samplers.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/combine_samplers.h"
+#include "src/tint/ast/transform/combine_samplers.h"
 
 #include <string>
 #include <unordered_map>
@@ -25,8 +25,8 @@
 
 #include "src/tint/utils/map.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::CombineSamplers);
-TINT_INSTANTIATE_TYPEINFO(tint::transform::CombineSamplers::BindingInfo);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::CombineSamplers);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::CombineSamplers::BindingInfo);
 
 namespace {
 
@@ -37,7 +37,7 @@
 
 }  // namespace
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 using namespace tint::number_suffixes;  // NOLINT
 
@@ -61,7 +61,7 @@
 
     /// Map from a texture/sampler pair to the corresponding combined sampler
     /// variable
-    using CombinedTextureSamplerMap = std::unordered_map<sem::VariablePair, const ast::Variable*>;
+    using CombinedTextureSamplerMap = std::unordered_map<sem::VariablePair, const Variable*>;
 
     /// Use sem::BindingPoint without scope.
     using BindingPoint = sem::BindingPoint;
@@ -79,15 +79,14 @@
     /// references (one comparison sampler, one regular). These are also used as
     /// temporary sampler parameters to the texture builtins to satisfy the WGSL
     /// resolver, but are then ignored and removed by the GLSL writer.
-    const ast::Variable* placeholder_samplers_[2] = {};
+    const Variable* placeholder_samplers_[2] = {};
 
     /// Group and binding attributes used by all combined sampler globals.
     /// Group 0 and binding 0 are used, with collisions disabled.
     /// @returns the newly-created attribute list
     auto Attributes() const {
-        utils::Vector<const ast::Attribute*, 3> attributes{ctx.dst->Group(0_a),
-                                                           ctx.dst->Binding(0_a)};
-        attributes.Push(ctx.dst->Disable(ast::DisabledValidation::kBindingPointCollision));
+        utils::Vector<const Attribute*, 3> attributes{ctx.dst->Group(0_a), ctx.dst->Binding(0_a)};
+        attributes.Push(ctx.dst->Disable(DisabledValidation::kBindingPointCollision));
         return attributes;
     }
 
@@ -103,9 +102,9 @@
     /// @param sampler_var the sampler (global) variable
     /// @param name the default name to use (may be overridden by map lookup)
     /// @returns the newly-created global variable
-    const ast::Variable* CreateCombinedGlobal(const sem::Variable* texture_var,
-                                              const sem::Variable* sampler_var,
-                                              std::string name) {
+    const Variable* CreateCombinedGlobal(const sem::Variable* texture_var,
+                                         const sem::Variable* sampler_var,
+                                         std::string name) {
         SamplerTexturePair bp_pair;
         bp_pair.texture_binding_point = *texture_var->As<sem::GlobalVariable>()->BindingPoint();
         bp_pair.sampler_binding_point =
@@ -115,7 +114,7 @@
         if (it != binding_info->binding_map.end()) {
             name = it->second;
         }
-        ast::Type type = CreateCombinedASTTypeFor(texture_var, sampler_var);
+        Type type = CreateCombinedASTTypeFor(texture_var, sampler_var);
         Symbol symbol = ctx.dst->Symbols().New(name);
         return ctx.dst->GlobalVar(symbol, type, Attributes());
     }
@@ -123,8 +122,8 @@
     /// Creates placeholder global sampler variables.
     /// @param kind the sampler kind to create for
     /// @returns the newly-created global variable
-    const ast::Variable* CreatePlaceholder(type::SamplerKind kind) {
-        ast::Type type = ctx.dst->ty.sampler(kind);
+    const Variable* CreatePlaceholder(type::SamplerKind kind) {
+        Type type = ctx.dst->ty.sampler(kind);
         const char* name = kind == type::SamplerKind::kComparisonSampler
                                ? "placeholder_comparison_sampler"
                                : "placeholder_sampler";
@@ -132,13 +131,13 @@
         return ctx.dst->GlobalVar(symbol, type, Attributes());
     }
 
-    /// Creates ast::Identifier for a given texture and sampler variable pair.
+    /// Creates Identifier for a given texture and sampler variable pair.
     /// Depth textures with no samplers are turned into the corresponding
     /// f32 texture (e.g., texture_depth_2d -> texture_2d<f32>).
     /// @param texture the texture variable of interest
     /// @param sampler the texture variable of interest
     /// @returns the newly-created type
-    ast::Type CreateCombinedASTTypeFor(const sem::Variable* texture, const sem::Variable* sampler) {
+    Type CreateCombinedASTTypeFor(const sem::Variable* texture, const sem::Variable* sampler) {
         const type::Type* texture_type = texture->Type()->UnwrapRef();
         const type::DepthTexture* depth = texture_type->As<type::DepthTexture>();
         if (depth && !sampler) {
@@ -163,8 +162,7 @@
                 ctx.Remove(ctx.src->AST().GlobalDeclarations(), global);
             } else if (auto binding_point = global_sem->BindingPoint()) {
                 if (binding_point->group == 0 && binding_point->binding == 0) {
-                    auto* attribute =
-                        ctx.dst->Disable(ast::DisabledValidation::kBindingPointCollision);
+                    auto* attribute = ctx.dst->Disable(DisabledValidation::kBindingPointCollision);
                     ctx.InsertFront(global->attributes, attribute);
                 }
             }
@@ -172,13 +170,13 @@
 
         // Rewrite all function signatures to use combined samplers, and remove
         // separate textures & samplers. Create new combined globals where found.
-        ctx.ReplaceAll([&](const ast::Function* ast_fn) -> const ast::Function* {
+        ctx.ReplaceAll([&](const Function* ast_fn) -> const Function* {
             if (auto* fn = sem.Get(ast_fn)) {
                 auto pairs = fn->TextureSamplerPairs();
                 if (pairs.IsEmpty()) {
                     return nullptr;
                 }
-                utils::Vector<const ast::Parameter*, 8> params;
+                utils::Vector<const Parameter*, 8> params;
                 for (auto pair : fn->TextureSamplerPairs()) {
                     const sem::Variable* texture_var = pair.first;
                     const sem::Variable* sampler_var = pair.second;
@@ -195,7 +193,7 @@
                     } else {
                         // Either texture or sampler (or both) is a function parameter;
                         // add a new function parameter to represent the combined sampler.
-                        ast::Type type = CreateCombinedASTTypeFor(texture_var, sampler_var);
+                        Type type = CreateCombinedASTTypeFor(texture_var, sampler_var);
                         auto* var = ctx.dst->Param(ctx.dst->Symbols().New(name), type);
                         params.Push(var);
                         function_combined_texture_samplers_[fn][pair] = var;
@@ -215,9 +213,9 @@
                 auto* body = ctx.Clone(ast_fn->body);
                 auto attributes = ctx.Clone(ast_fn->attributes);
                 auto return_type_attributes = ctx.Clone(ast_fn->return_type_attributes);
-                return ctx.dst->create<ast::Function>(name, params, return_type, body,
-                                                      std::move(attributes),
-                                                      std::move(return_type_attributes));
+                return ctx.dst->create<Function>(name, params, return_type, body,
+                                                 std::move(attributes),
+                                                 std::move(return_type_attributes));
             }
             return nullptr;
         });
@@ -225,9 +223,9 @@
         // Replace all function call expressions containing texture or
         // sampler parameters to use the current function's combined samplers or
         // the combined global samplers, as appropriate.
-        ctx.ReplaceAll([&](const ast::CallExpression* expr) -> const ast::Expression* {
+        ctx.ReplaceAll([&](const CallExpression* expr) -> const Expression* {
             if (auto* call = sem.Get(expr)->UnwrapMaterialize()->As<sem::Call>()) {
-                utils::Vector<const ast::Expression*, 8> args;
+                utils::Vector<const Expression*, 8> args;
                 // Replace all texture builtin calls.
                 if (auto* builtin = call->Target()->As<sem::Builtin>()) {
                     const auto& signature = builtin->Signature();
@@ -254,7 +252,7 @@
                     for (auto* arg : expr->args) {
                         auto* type = ctx.src->TypeOf(arg)->UnwrapRef();
                         if (type->Is<type::Texture>()) {
-                            const ast::Variable* var =
+                            const Variable* var =
                                 IsGlobal(new_pair)
                                     ? global_combined_texture_samplers_[new_pair]
                                     : function_combined_texture_samplers_[call->Stmt()->Function()]
@@ -263,7 +261,7 @@
                         } else if (auto* sampler_type = type->As<type::Sampler>()) {
                             type::SamplerKind kind = sampler_type->kind();
                             int index = (kind == type::SamplerKind::kSampler) ? 0 : 1;
-                            const ast::Variable*& p = placeholder_samplers_[index];
+                            const Variable*& p = placeholder_samplers_[index];
                             if (!p) {
                                 p = CreatePlaceholder(kind);
                             }
@@ -272,10 +270,10 @@
                             args.Push(ctx.Clone(arg));
                         }
                     }
-                    const ast::Expression* value = ctx.dst->Call(ctx.Clone(expr->target), args);
+                    const Expression* value = ctx.dst->Call(ctx.Clone(expr->target), args);
                     if (builtin->Type() == builtin::Function::kTextureLoad &&
                         texture_var->Type()->UnwrapRef()->Is<type::DepthTexture>() &&
-                        !call->Stmt()->Declaration()->Is<ast::CallStatement>()) {
+                        !call->Stmt()->Declaration()->Is<CallStatement>()) {
                         value = ctx.dst->MemberAccessor(value, "x");
                     }
                     return value;
@@ -307,7 +305,7 @@
                         // If both texture and sampler are (now) global, pass that
                         // global variable to the callee. Otherwise use the caller's
                         // function parameter for this pair.
-                        const ast::Variable* var =
+                        const Variable* var =
                             IsGlobal(new_pair)
                                 ? global_combined_texture_samplers_[new_pair]
                                 : function_combined_texture_samplers_[call->Stmt()->Function()]
@@ -353,4 +351,4 @@
     return State(src, binding_info).Run();
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/combine_samplers.h b/src/tint/ast/transform/combine_samplers.h
similarity index 91%
rename from src/tint/transform/combine_samplers.h
rename to src/tint/ast/transform/combine_samplers.h
index b521a55..f9de2e7 100644
--- a/src/tint/transform/combine_samplers.h
+++ b/src/tint/ast/transform/combine_samplers.h
@@ -12,16 +12,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_COMBINE_SAMPLERS_H_
-#define SRC_TINT_TRANSFORM_COMBINE_SAMPLERS_H_
+#ifndef SRC_TINT_AST_TRANSFORM_COMBINE_SAMPLERS_H_
+#define SRC_TINT_AST_TRANSFORM_COMBINE_SAMPLERS_H_
 
 #include <string>
 #include <unordered_map>
 
+#include "src/tint/ast/transform/transform.h"
 #include "src/tint/sem/sampler_texture_pair.h"
-#include "src/tint/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// This transform converts all separate texture/sampler refences in a
 /// program into combined texture/samplers. This is required for GLSL,
@@ -62,7 +62,7 @@
 
     /// The client-provided mapping from separate texture and sampler binding
     /// points to combined sampler binding point.
-    struct BindingInfo final : public utils::Castable<Data, transform::Data> {
+    struct BindingInfo final : public utils::Castable<BindingInfo, Data> {
         /// Constructor
         /// @param map the map of all (texture, sampler) -> (combined) pairs
         /// @param placeholder the binding point to use for placeholder samplers.
@@ -97,6 +97,6 @@
     struct State;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_COMBINE_SAMPLERS_H_
+#endif  // SRC_TINT_AST_TRANSFORM_COMBINE_SAMPLERS_H_
diff --git a/src/tint/transform/combine_samplers_test.cc b/src/tint/ast/transform/combine_samplers_test.cc
similarity index 99%
rename from src/tint/transform/combine_samplers_test.cc
rename to src/tint/ast/transform/combine_samplers_test.cc
index cfabded..f658493 100644
--- a/src/tint/transform/combine_samplers_test.cc
+++ b/src/tint/ast/transform/combine_samplers_test.cc
@@ -12,14 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/combine_samplers.h"
+#include "src/tint/ast/transform/combine_samplers.h"
 
 #include <memory>
 #include <utility>
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using CombineSamplersTest = TransformTest;
@@ -985,4 +985,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/decompose_memory_access.cc b/src/tint/ast/transform/decompose_memory_access.cc
similarity index 92%
rename from src/tint/transform/decompose_memory_access.cc
rename to src/tint/ast/transform/decompose_memory_access.cc
index 181518d..f80fd56 100644
--- a/src/tint/transform/decompose_memory_access.cc
+++ b/src/tint/ast/transform/decompose_memory_access.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/decompose_memory_access.h"
+#include "src/tint/ast/transform/decompose_memory_access.h"
 
 #include <memory>
 #include <string>
@@ -41,10 +41,10 @@
 
 using namespace tint::number_suffixes;  // NOLINT
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::DecomposeMemoryAccess);
-TINT_INSTANTIATE_TYPEINFO(tint::transform::DecomposeMemoryAccess::Intrinsic);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::DecomposeMemoryAccess);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::DecomposeMemoryAccess::Intrinsic);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 namespace {
 
@@ -60,21 +60,21 @@
     return false;
 }
 
-/// Offset is a simple ast::Expression builder interface, used to build byte
+/// Offset is a simple Expression builder interface, used to build byte
 /// offsets for storage and uniform buffer accesses.
 struct Offset : utils::Castable<Offset> {
-    /// @returns builds and returns the ast::Expression in `ctx.dst`
-    virtual const ast::Expression* Build(CloneContext& ctx) const = 0;
+    /// @returns builds and returns the Expression in `ctx.dst`
+    virtual const Expression* Build(CloneContext& ctx) const = 0;
 };
 
 /// OffsetExpr is an implementation of Offset that clones and casts the given
 /// expression to `u32`.
 struct OffsetExpr : Offset {
-    const ast::Expression* const expr = nullptr;
+    const Expression* const expr = nullptr;
 
-    explicit OffsetExpr(const ast::Expression* e) : expr(e) {}
+    explicit OffsetExpr(const Expression* e) : expr(e) {}
 
-    const ast::Expression* Build(CloneContext& ctx) const override {
+    const Expression* Build(CloneContext& ctx) const override {
         auto* type = ctx.src->Sem().GetVal(expr)->Type()->UnwrapRef();
         auto* res = ctx.Clone(expr);
         if (!type->Is<type::U32>()) {
@@ -91,7 +91,7 @@
 
     explicit OffsetLiteral(uint32_t lit) : literal(lit) {}
 
-    const ast::Expression* Build(CloneContext& ctx) const override {
+    const Expression* Build(CloneContext& ctx) const override {
         return ctx.dst->Expr(u32(literal));
     }
 };
@@ -99,12 +99,12 @@
 /// OffsetBinOp is an implementation of Offset that constructs a binary-op of
 /// two Offsets.
 struct OffsetBinOp : Offset {
-    ast::BinaryOp op;
+    BinaryOp op;
     Offset const* lhs = nullptr;
     Offset const* rhs = nullptr;
 
-    const ast::Expression* Build(CloneContext& ctx) const override {
-        return ctx.dst->create<ast::BinaryExpression>(op, lhs->Build(ctx), rhs->Build(ctx));
+    const Expression* Build(CloneContext& ctx) const override {
+        return ctx.dst->create<BinaryExpression>(op, lhs->Build(ctx), rhs->Build(ctx));
     }
 };
 
@@ -313,7 +313,7 @@
 
 /// Store describes a single storage or uniform buffer write
 struct Store {
-    const ast::AssignmentStatement* assignment;  // The AST assignment statement
+    const AssignmentStatement* assignment;       // The AST assignment statement
     BufferAccess target;                         // The target for the write
 };
 
@@ -330,9 +330,9 @@
     /// expressions chain the access.
     /// Subset of #expression_order, as expressions are not removed from
     /// #expression_order.
-    std::unordered_map<const ast::Expression*, BufferAccess> accesses;
+    std::unordered_map<const Expression*, BufferAccess> accesses;
     /// The visited order of AST expressions (superset of #accesses)
-    std::vector<const ast::Expression*> expression_order;
+    std::vector<const Expression*> expression_order;
     /// [buffer-type, element-type] -> load function name
     std::unordered_map<LoadStoreKey, Symbol, LoadStoreKey::Hasher> load_funcs;
     /// [buffer-type, element-type] -> store function name
@@ -353,9 +353,9 @@
     const Offset* ToOffset(uint32_t offset) { return offsets_.Create<OffsetLiteral>(offset); }
 
     /// @param expr the expression to convert to an Offset
-    /// @returns an Offset for the given ast::Expression
-    const Offset* ToOffset(const ast::Expression* expr) {
-        if (auto* lit = expr->As<ast::IntLiteralExpression>()) {
+    /// @returns an Offset for the given Expression
+    const Offset* ToOffset(const Expression* expr) {
+        if (auto* lit = expr->As<IntLiteralExpression>()) {
             if (lit->value >= 0) {
                 return offsets_.Create<OffsetLiteral>(static_cast<uint32_t>(lit->value));
             }
@@ -390,7 +390,7 @@
             }
         }
         auto* out = offsets_.Create<OffsetBinOp>();
-        out->op = ast::BinaryOp::kAdd;
+        out->op = BinaryOp::kAdd;
         out->lhs = lhs;
         out->rhs = rhs;
         return out;
@@ -422,7 +422,7 @@
             return offsets_.Create<OffsetLiteral>(lhs_lit->literal * rhs_lit->literal);
         }
         auto* out = offsets_.Create<OffsetBinOp>();
-        out->op = ast::BinaryOp::kMultiply;
+        out->op = BinaryOp::kMultiply;
         out->lhs = lhs;
         out->rhs = rhs;
         return out;
@@ -432,7 +432,7 @@
     /// to #expression_order.
     /// @param expr the expression that performs the access
     /// @param access the access
-    void AddAccess(const ast::Expression* expr, const BufferAccess& access) {
+    void AddAccess(const Expression* expr, const BufferAccess& access) {
         TINT_ASSERT(Transform, access.type);
         accesses.emplace(expr, access);
         expression_order.emplace_back(expr);
@@ -443,7 +443,7 @@
     /// `node`, an invalid BufferAccess is returned.
     /// @param node the expression that performed an access
     /// @return the BufferAccess for the given expression
-    BufferAccess TakeAccess(const ast::Expression* node) {
+    BufferAccess TakeAccess(const Expression* node) {
         auto lhs_it = accesses.find(node);
         if (lhs_it == accesses.end()) {
             return {};
@@ -475,7 +475,7 @@
                 b.Func(name, params, el_ast_ty, nullptr,
                        utils::Vector{
                            intrinsic,
-                           b.Disable(ast::DisabledValidation::kFunctionHasNoBody),
+                           b.Disable(DisabledValidation::kFunctionHasNoBody),
                        });
             } else if (auto* arr_ty = el_ty->As<type::Array>()) {
                 // fn load_func(buffer : buf_ty, offset : u32) -> array<T, N> {
@@ -498,8 +498,8 @@
                     TINT_ICE(Transform, b.Diagnostics()) << "unexpected non-constant array count";
                     arr_cnt = 1;
                 }
-                auto* for_cond = b.create<ast::BinaryExpression>(
-                    ast::BinaryOp::kLessThan, b.Expr(i), b.Expr(u32(arr_cnt.value())));
+                auto* for_cond = b.create<BinaryExpression>(BinaryOp::kLessThan, b.Expr(i),
+                                                            b.Expr(u32(arr_cnt.value())));
                 auto* for_cont = b.Assign(i, b.Add(i, 1_u));
                 auto* arr_el = b.IndexAccessor(arr, i);
                 auto* el_offset = b.Add(b.Expr("offset"), b.Mul(i, u32(arr_ty->Stride())));
@@ -514,7 +514,7 @@
                            b.Return(arr),
                        });
             } else {
-                utils::Vector<const ast::Expression*, 8> values;
+                utils::Vector<const Expression*, 8> values;
                 if (auto* mat_ty = el_ty->As<type::Matrix>()) {
                     auto* vec_ty = mat_ty->ColumnType();
                     Symbol load = LoadFunc(vec_ty, address_space, buffer);
@@ -557,10 +557,10 @@
                 b.Func(name, params, b.ty.void_(), nullptr,
                        utils::Vector{
                            intrinsic,
-                           b.Disable(ast::DisabledValidation::kFunctionHasNoBody),
+                           b.Disable(DisabledValidation::kFunctionHasNoBody),
                        });
             } else {
-                auto body = Switch<utils::Vector<const ast::Statement*, 8>>(
+                auto body = Switch<utils::Vector<const Statement*, 8>>(
                     el_ty,  //
                     [&](const type::Array* arr_ty) {
                         // fn store_func(buffer : buf_ty, offset : u32, value : el_ty) {
@@ -585,8 +585,8 @@
                                 << "unexpected non-constant array count";
                             arr_cnt = 1;
                         }
-                        auto* for_cond = b.create<ast::BinaryExpression>(
-                            ast::BinaryOp::kLessThan, b.Expr(i), b.Expr(u32(arr_cnt.value())));
+                        auto* for_cond = b.create<BinaryExpression>(BinaryOp::kLessThan, b.Expr(i),
+                                                                    b.Expr(u32(arr_cnt.value())));
                         auto* for_cont = b.Assign(i, b.Add(i, 1_u));
                         auto* arr_el = b.IndexAccessor(array, i);
                         auto* el_offset = b.Add(b.Expr("offset"), b.Mul(i, u32(arr_ty->Stride())));
@@ -598,7 +598,7 @@
                     [&](const type::Matrix* mat_ty) {
                         auto* vec_ty = mat_ty->ColumnType();
                         Symbol store = StoreFunc(vec_ty, buffer);
-                        utils::Vector<const ast::Statement*, 4> stmts;
+                        utils::Vector<const Statement*, 4> stmts;
                         for (uint32_t i = 0; i < mat_ty->columns(); i++) {
                             auto* offset = b.Add("offset", u32(i * mat_ty->ColumnStride()));
                             auto* element = b.IndexAccessor("value", u32(i));
@@ -608,7 +608,7 @@
                         return stmts;
                     },
                     [&](const type::Struct* str) {
-                        utils::Vector<const ast::Statement*, 8> stmts;
+                        utils::Vector<const Statement*, 8> stmts;
                         for (auto* member : str->Members()) {
                             auto* offset = b.Add("offset", u32(member->Offset()));
                             auto* element = b.MemberAccessor("value", ctx.Clone(member->Name()));
@@ -656,14 +656,14 @@
                     << el_ty->TypeInfo().name;
             }
 
-            ast::Type ret_ty;
+            Type ret_ty;
 
             // For intrinsics that return a struct, there is no AST node for it, so create one now.
             if (intrinsic->Type() == builtin::Function::kAtomicCompareExchangeWeak) {
                 auto* str = intrinsic->ReturnType()->As<type::Struct>();
                 TINT_ASSERT(Transform, str);
 
-                utils::Vector<const ast::StructMember*, 8> ast_members;
+                utils::Vector<const StructMember*, 8> ast_members;
                 ast_members.Reserve(str->Members().Length());
                 for (auto& m : str->Members()) {
                     ast_members.Push(
@@ -681,7 +681,7 @@
             b.Func(name, std::move(params), ret_ty, nullptr,
                    utils::Vector{
                        atomic,
-                       b.Disable(ast::DisabledValidation::kFunctionHasNoBody),
+                       b.Disable(DisabledValidation::kFunctionHasNoBody),
                    });
             return name;
         });
@@ -689,11 +689,11 @@
 };
 
 DecomposeMemoryAccess::Intrinsic::Intrinsic(ProgramID pid,
-                                            ast::NodeID nid,
+                                            NodeID nid,
                                             Op o,
                                             DataType ty,
                                             builtin::AddressSpace as,
-                                            const ast::IdentifierExpression* buf)
+                                            const IdentifierExpression* buf)
     : Base(pid, nid, utils::Vector{buf}), op(o), type(ty), address_space(as) {}
 DecomposeMemoryAccess::Intrinsic::~Intrinsic() = default;
 std::string DecomposeMemoryAccess::Intrinsic::InternalName() const {
@@ -804,7 +804,7 @@
     return op != Op::kLoad && op != Op::kStore;
 }
 
-const ast::IdentifierExpression* DecomposeMemoryAccess::Intrinsic::Buffer() const {
+const IdentifierExpression* DecomposeMemoryAccess::Intrinsic::Buffer() const {
     return dependencies[0];
 }
 
@@ -832,7 +832,7 @@
     // nodes are fully immutable and require their children to be constructed
     // first so their pointer can be passed to the parent's initializer.
     for (auto* node : src->ASTNodes().Objects()) {
-        if (auto* ident = node->As<ast::IdentifierExpression>()) {
+        if (auto* ident = node->As<IdentifierExpression>()) {
             // X
             if (auto* sem_ident = sem.GetVal(ident)) {
                 if (auto* user = sem_ident->UnwrapLoad()->As<sem::VariableUser>()) {
@@ -852,7 +852,7 @@
             continue;
         }
 
-        if (auto* accessor = node->As<ast::MemberAccessorExpression>()) {
+        if (auto* accessor = node->As<MemberAccessorExpression>()) {
             // X.Y
             auto* accessor_sem = sem.Get(accessor)->UnwrapLoad();
             if (auto* swizzle = accessor_sem->As<sem::Swizzle>()) {
@@ -882,7 +882,7 @@
             continue;
         }
 
-        if (auto* accessor = node->As<ast::IndexAccessorExpression>()) {
+        if (auto* accessor = node->As<IndexAccessorExpression>()) {
             if (auto access = state.TakeAccess(accessor->object)) {
                 // X[Y]
                 if (auto* arr = access.type->As<type::Array>()) {
@@ -915,8 +915,8 @@
             }
         }
 
-        if (auto* op = node->As<ast::UnaryOpExpression>()) {
-            if (op->op == ast::UnaryOp::kAddressOf) {
+        if (auto* op = node->As<UnaryOpExpression>()) {
+            if (op->op == UnaryOp::kAddressOf) {
                 // &X
                 if (auto access = state.TakeAccess(op->expr)) {
                     // HLSL does not support pointers, so just take the access from the
@@ -927,7 +927,7 @@
             }
         }
 
-        if (auto* assign = node->As<ast::AssignmentStatement>()) {
+        if (auto* assign = node->As<AssignmentStatement>()) {
             // X = Y
             // Move the LHS access to a store.
             if (auto lhs = state.TakeAccess(assign->lhs)) {
@@ -935,7 +935,7 @@
             }
         }
 
-        if (auto* call_expr = node->As<ast::CallExpression>()) {
+        if (auto* call_expr = node->As<CallExpression>()) {
             auto* call = sem.Get(call_expr)->UnwrapMaterialize()->As<sem::Call>();
             if (auto* builtin = call->Target()->As<sem::Builtin>()) {
                 if (builtin->Type() == builtin::Function::kArrayLength) {
@@ -953,7 +953,7 @@
                             auto buffer = ctx.Clone(access.var->Declaration()->name->symbol);
                             Symbol func = state.AtomicFunc(el_ty, builtin, buffer);
 
-                            utils::Vector<const ast::Expression*, 8> args{offset};
+                            utils::Vector<const Expression*, 8> args{offset};
                             for (size_t i = 1; i < call_expr->args.Length(); i++) {
                                 auto* arg = call_expr->args[i];
                                 args.Push(ctx.Clone(arg));
@@ -1001,7 +1001,7 @@
     return Program(std::move(b));
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::Offset);
-TINT_INSTANTIATE_TYPEINFO(tint::transform::OffsetLiteral);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::Offset);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::OffsetLiteral);
diff --git a/src/tint/transform/decompose_memory_access.h b/src/tint/ast/transform/decompose_memory_access.h
similarity index 87%
rename from src/tint/transform/decompose_memory_access.h
rename to src/tint/ast/transform/decompose_memory_access.h
index 8f06726..21d7cb7 100644
--- a/src/tint/transform/decompose_memory_access.h
+++ b/src/tint/ast/transform/decompose_memory_access.h
@@ -12,20 +12,20 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_DECOMPOSE_MEMORY_ACCESS_H_
-#define SRC_TINT_TRANSFORM_DECOMPOSE_MEMORY_ACCESS_H_
+#ifndef SRC_TINT_AST_TRANSFORM_DECOMPOSE_MEMORY_ACCESS_H_
+#define SRC_TINT_AST_TRANSFORM_DECOMPOSE_MEMORY_ACCESS_H_
 
 #include <string>
 
 #include "src/tint/ast/internal_attribute.h"
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
 // Forward declarations
 namespace tint {
 class CloneContext;
 }  // namespace tint
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// DecomposeMemoryAccess is a transform used to replace storage and uniform buffer accesses with a
 /// combination of load, store or atomic functions on primitive types.
@@ -35,7 +35,7 @@
     /// transforms this into calls to
     /// `[RW]ByteAddressBuffer.Load[N]()` or `[RW]ByteAddressBuffer.Store[N]()`,
     /// with a possible cast.
-    class Intrinsic final : public utils::Castable<Intrinsic, ast::InternalAttribute> {
+    class Intrinsic final : public utils::Castable<Intrinsic, InternalAttribute> {
       public:
         /// Intrinsic op
         enum class Op {
@@ -82,11 +82,11 @@
         /// @param address_space the address space of the buffer
         /// @param buffer the storage or uniform buffer identifier
         Intrinsic(ProgramID pid,
-                  ast::NodeID nid,
+                  NodeID nid,
                   Op o,
                   DataType type,
                   builtin::AddressSpace address_space,
-                  const ast::IdentifierExpression* buffer);
+                  const IdentifierExpression* buffer);
         /// Destructor
         ~Intrinsic() override;
 
@@ -103,7 +103,7 @@
         bool IsAtomic() const;
 
         /// @return the buffer that this intrinsic operates on
-        const ast::IdentifierExpression* Buffer() const;
+        const IdentifierExpression* Buffer() const;
 
         /// The op of the intrinsic
         const Op op;
@@ -129,6 +129,6 @@
     struct State;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_DECOMPOSE_MEMORY_ACCESS_H_
+#endif  // SRC_TINT_AST_TRANSFORM_DECOMPOSE_MEMORY_ACCESS_H_
diff --git a/src/tint/transform/decompose_memory_access_test.cc b/src/tint/ast/transform/decompose_memory_access_test.cc
similarity index 99%
rename from src/tint/transform/decompose_memory_access_test.cc
rename to src/tint/ast/transform/decompose_memory_access_test.cc
index 95ec9de..52f2ff2 100644
--- a/src/tint/transform/decompose_memory_access_test.cc
+++ b/src/tint/ast/transform/decompose_memory_access_test.cc
@@ -12,11 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/decompose_memory_access.h"
+#include "src/tint/ast/transform/decompose_memory_access.h"
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using DecomposeMemoryAccessTest = TransformTest;
@@ -3962,4 +3962,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/decompose_strided_array.cc b/src/tint/ast/transform/decompose_strided_array.cc
similarity index 83%
rename from src/tint/transform/decompose_strided_array.cc
rename to src/tint/ast/transform/decompose_strided_array.cc
index 838948e..130c528 100644
--- a/src/tint/transform/decompose_strided_array.cc
+++ b/src/tint/ast/transform/decompose_strided_array.cc
@@ -12,33 +12,33 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/decompose_strided_array.h"
+#include "src/tint/ast/transform/decompose_strided_array.h"
 
 #include <unordered_map>
 #include <utility>
 #include <vector>
 
+#include "src/tint/ast/transform/simplify_pointers.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/call.h"
 #include "src/tint/sem/member_accessor_expression.h"
 #include "src/tint/sem/type_expression.h"
 #include "src/tint/sem/value_constructor.h"
 #include "src/tint/sem/value_expression.h"
-#include "src/tint/transform/simplify_pointers.h"
 #include "src/tint/utils/hash.h"
 #include "src/tint/utils/map.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::DecomposeStridedArray);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::DecomposeStridedArray);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using DecomposedArrays = std::unordered_map<const type::Array*, Symbol>;
 
 bool ShouldRun(const Program* program) {
     for (auto* node : program->ASTNodes().Objects()) {
-        if (auto* ident = node->As<ast::TemplatedIdentifier>()) {
-            if (ast::GetAttribute<ast::StrideAttribute>(ident->attributes)) {
+        if (auto* ident = node->As<TemplatedIdentifier>()) {
+            if (GetAttribute<StrideAttribute>(ident->attributes)) {
                 return true;
             }
         }
@@ -74,8 +74,8 @@
     // stride for the array element type, then replace the array element type with
     // a structure, holding a single field with a @size attribute equal to the
     // array stride.
-    ctx.ReplaceAll([&](const ast::IdentifierExpression* expr) -> const ast::IdentifierExpression* {
-        auto* ident = expr->identifier->As<ast::TemplatedIdentifier>();
+    ctx.ReplaceAll([&](const IdentifierExpression* expr) -> const IdentifierExpression* {
+        auto* ident = expr->identifier->As<TemplatedIdentifier>();
         if (!ident) {
             return nullptr;
         }
@@ -90,8 +90,8 @@
         if (!arr->IsStrideImplicit()) {
             auto el_ty = utils::GetOrCreate(decomposed, arr, [&] {
                 auto name = b.Symbols().New("strided_arr");
-                auto* member_ty = ctx.Clone(ident->arguments[0]->As<ast::IdentifierExpression>());
-                auto* member = b.Member(kMemberName, ast::Type{member_ty},
+                auto* member_ty = ctx.Clone(ident->arguments[0]->As<IdentifierExpression>());
+                auto* member = b.Member(kMemberName, Type{member_ty},
                                         utils::Vector{
                                             b.MemberSize(AInt(arr->Stride())),
                                         });
@@ -105,14 +105,14 @@
                 return b.Expr(b.ty.array(b.ty(el_ty)));
             }
         }
-        if (ast::GetAttribute<ast::StrideAttribute>(ident->attributes)) {
+        if (GetAttribute<StrideAttribute>(ident->attributes)) {
             // Strip the @stride attribute
-            auto* ty = ctx.Clone(ident->arguments[0]->As<ast::IdentifierExpression>());
+            auto* ty = ctx.Clone(ident->arguments[0]->As<IdentifierExpression>());
             if (ident->arguments.Length() > 1) {
                 auto* count = ctx.Clone(ident->arguments[1]);
-                return b.Expr(b.ty.array(ast::Type{ty}, count));
+                return b.Expr(b.ty.array(Type{ty}, count));
             } else {
-                return b.Expr(b.ty.array(ast::Type{ty}));
+                return b.Expr(b.ty.array(Type{ty}));
             }
         }
         return nullptr;
@@ -122,7 +122,7 @@
     // element changed to a single field structure. These expressions are adjusted
     // to insert an additional member accessor for the single structure field.
     // Example: `arr[i]` -> `arr[i].el`
-    ctx.ReplaceAll([&](const ast::IndexAccessorExpression* idx) -> const ast::Expression* {
+    ctx.ReplaceAll([&](const IndexAccessorExpression* idx) -> const Expression* {
         if (auto* ty = src->TypeOf(idx->object)) {
             if (auto* arr = ty->UnwrapRef()->As<type::Array>()) {
                 if (!arr->IsStrideImplicit()) {
@@ -140,7 +140,7 @@
     //   `@stride(32) array<i32, 3>(1, 2, 3)`
     // ->
     //   `array<strided_arr, 3>(strided_arr(1), strided_arr(2), strided_arr(3))`
-    ctx.ReplaceAll([&](const ast::CallExpression* expr) -> const ast::Expression* {
+    ctx.ReplaceAll([&](const CallExpression* expr) -> const Expression* {
         if (!expr->args.IsEmpty()) {
             if (auto* call = sem.Get(expr)->UnwrapMaterialize()->As<sem::Call>()) {
                 if (auto* ctor = call->Target()->As<sem::ValueConstructor>()) {
@@ -153,7 +153,7 @@
 
                         auto* target = ctx.Clone(expr->target);
 
-                        utils::Vector<const ast::Expression*, 8> args;
+                        utils::Vector<const Expression*, 8> args;
                         if (auto it = decomposed.find(arr); it != decomposed.end()) {
                             args.Reserve(expr->args.Length());
                             for (auto* arg : expr->args) {
@@ -175,4 +175,4 @@
     return Program(std::move(b));
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/decompose_strided_array.h b/src/tint/ast/transform/decompose_strided_array.h
similarity index 82%
rename from src/tint/transform/decompose_strided_array.h
rename to src/tint/ast/transform/decompose_strided_array.h
index aee75b0..a9d10cc 100644
--- a/src/tint/transform/decompose_strided_array.h
+++ b/src/tint/ast/transform/decompose_strided_array.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_DECOMPOSE_STRIDED_ARRAY_H_
-#define SRC_TINT_TRANSFORM_DECOMPOSE_STRIDED_ARRAY_H_
+#ifndef SRC_TINT_AST_TRANSFORM_DECOMPOSE_STRIDED_ARRAY_H_
+#define SRC_TINT_AST_TRANSFORM_DECOMPOSE_STRIDED_ARRAY_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// DecomposeStridedArray transforms replaces arrays with a non-default
 /// `@stride` attribute with an array of structure elements, where the
@@ -41,6 +41,6 @@
                       DataMap& outputs) const override;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_DECOMPOSE_STRIDED_ARRAY_H_
+#endif  // SRC_TINT_AST_TRANSFORM_DECOMPOSE_STRIDED_ARRAY_H_
diff --git a/src/tint/transform/decompose_strided_array_test.cc b/src/tint/ast/transform/decompose_strided_array_test.cc
similarity index 96%
rename from src/tint/transform/decompose_strided_array_test.cc
rename to src/tint/ast/transform/decompose_strided_array_test.cc
index 54c00b7..28ac32a 100644
--- a/src/tint/transform/decompose_strided_array_test.cc
+++ b/src/tint/ast/transform/decompose_strided_array_test.cc
@@ -12,20 +12,20 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/decompose_strided_array.h"
+#include "src/tint/ast/transform/decompose_strided_array.h"
 
 #include <memory>
 #include <utility>
 #include <vector>
 
+#include "src/tint/ast/transform/simplify_pointers.h"
+#include "src/tint/ast/transform/test_helper.h"
+#include "src/tint/ast/transform/unshadow.h"
 #include "src/tint/program_builder.h"
-#include "src/tint/transform/simplify_pointers.h"
-#include "src/tint/transform/test_helper.h"
-#include "src/tint/transform/unshadow.h"
 
 using namespace tint::number_suffixes;  // NOLINT
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using DecomposeStridedArrayTest = TransformTest;
@@ -101,7 +101,7 @@
                b.Decl(b.Let("b", b.ty.f32(), b.IndexAccessor("arr", 1_i))),
            },
            utils::Vector{
-               b.Stage(ast::PipelineStage::kCompute),
+               b.Stage(PipelineStage::kCompute),
                b.WorkgroupSize(1_i),
            });
 
@@ -145,7 +145,7 @@
                b.Decl(b.Let("b", b.ty.f32(), b.IndexAccessor("arr", 1_i))),
            },
            utils::Vector{
-               b.Stage(ast::PipelineStage::kCompute),
+               b.Stage(PipelineStage::kCompute),
                b.WorkgroupSize(1_i),
            });
 
@@ -195,7 +195,7 @@
                b.Decl(b.Let("b", b.ty.f32(), b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i))),
            },
            utils::Vector{
-               b.Stage(ast::PipelineStage::kCompute),
+               b.Stage(PipelineStage::kCompute),
                b.WorkgroupSize(1_i),
            });
 
@@ -253,7 +253,7 @@
                          b.IndexAccessor(b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i), 2_i))),
         },
         utils::Vector{
-            b.Stage(ast::PipelineStage::kCompute),
+            b.Stage(PipelineStage::kCompute),
             b.WorkgroupSize(1_i),
         });
 
@@ -303,7 +303,7 @@
                b.Decl(b.Let("b", b.ty.f32(), b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i))),
            },
            utils::Vector{
-               b.Stage(ast::PipelineStage::kCompute),
+               b.Stage(PipelineStage::kCompute),
                b.WorkgroupSize(1_i),
            });
 
@@ -357,7 +357,7 @@
                b.Decl(b.Let("b", b.ty.f32(), b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i))),
            },
            utils::Vector{
-               b.Stage(ast::PipelineStage::kCompute),
+               b.Stage(PipelineStage::kCompute),
                b.WorkgroupSize(1_i),
            });
 
@@ -410,7 +410,7 @@
                b.Assign(b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i), 5_f),
            },
            utils::Vector{
-               b.Stage(ast::PipelineStage::kCompute),
+               b.Stage(PipelineStage::kCompute),
                b.WorkgroupSize(1_i),
            });
 
@@ -472,7 +472,7 @@
                b.Assign(b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i), 5_f),
            },
            utils::Vector{
-               b.Stage(ast::PipelineStage::kCompute),
+               b.Stage(PipelineStage::kCompute),
                b.WorkgroupSize(1_i),
            });
 
@@ -531,7 +531,7 @@
                b.Assign(b.IndexAccessor(b.Deref("b"), 1_i), 5_f),
            },
            utils::Vector{
-               b.Stage(ast::PipelineStage::kCompute),
+               b.Stage(PipelineStage::kCompute),
                b.WorkgroupSize(1_i),
            });
 
@@ -593,7 +593,7 @@
                b.Assign(b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i), 5_f),
            },
            utils::Vector{
-               b.Stage(ast::PipelineStage::kCompute),
+               b.Stage(PipelineStage::kCompute),
                b.WorkgroupSize(1_i),
            });
 
@@ -696,7 +696,7 @@
                         5_f),
            },
            utils::Vector{
-               b.Stage(ast::PipelineStage::kCompute),
+               b.Stage(PipelineStage::kCompute),
                b.WorkgroupSize(1_i),
            });
 
@@ -738,4 +738,4 @@
     EXPECT_EQ(expect, str(got));
 }
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/decompose_strided_matrix.cc b/src/tint/ast/transform/decompose_strided_matrix.cc
similarity index 85%
rename from src/tint/transform/decompose_strided_matrix.cc
rename to src/tint/ast/transform/decompose_strided_matrix.cc
index 6443095..0eb04cb 100644
--- a/src/tint/transform/decompose_strided_matrix.cc
+++ b/src/tint/ast/transform/decompose_strided_matrix.cc
@@ -12,22 +12,22 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/decompose_strided_matrix.h"
+#include "src/tint/ast/transform/decompose_strided_matrix.h"
 
 #include <unordered_map>
 #include <utility>
 #include <vector>
 
+#include "src/tint/ast/transform/simplify_pointers.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/member_accessor_expression.h"
 #include "src/tint/sem/value_expression.h"
-#include "src/tint/transform/simplify_pointers.h"
 #include "src/tint/utils/hash.h"
 #include "src/tint/utils/map.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::DecomposeStridedMatrix);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::DecomposeStridedMatrix);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 /// MatrixInfo describes a matrix member with a custom stride
@@ -38,7 +38,7 @@
     const type::Matrix* matrix = nullptr;
 
     /// @returns the identifier of an array that holds an vector column for each row of the matrix.
-    ast::Type array(ProgramBuilder* b) const {
+    Type array(ProgramBuilder* b) const {
         return b->ty.array(b->ty.vec<f32>(matrix->rows()), u32(matrix->columns()),
                            utils::Vector{
                                b->Stride(stride),
@@ -72,7 +72,7 @@
     // and populate the `decomposed` map with the members that have been replaced.
     utils::Hashmap<const type::StructMember*, MatrixInfo, 8> decomposed;
     for (auto* node : src->ASTNodes().Objects()) {
-        if (auto* str = node->As<ast::Struct>()) {
+        if (auto* str = node->As<Struct>()) {
             auto* str_ty = src->Sem().Get(str);
             if (!str_ty->UsedAs(builtin::AddressSpace::kUniform) &&
                 !str_ty->UsedAs(builtin::AddressSpace::kStorage)) {
@@ -83,8 +83,7 @@
                 if (!matrix) {
                     continue;
                 }
-                auto* attr =
-                    ast::GetAttribute<ast::StrideAttribute>(member->Declaration()->attributes);
+                auto* attr = GetAttribute<StrideAttribute>(member->Declaration()->attributes);
                 if (!attr) {
                     continue;
                 }
@@ -111,17 +110,16 @@
     // preserve these without calling conversion functions.
     // Example:
     //   ssbo.mat[2] -> ssbo.mat[2]
-    ctx.ReplaceAll(
-        [&](const ast::IndexAccessorExpression* expr) -> const ast::IndexAccessorExpression* {
-            if (auto* access = src->Sem().Get<sem::StructMemberAccess>(expr->object)) {
-                if (decomposed.Contains(access->Member())) {
-                    auto* obj = ctx.CloneWithoutTransform(expr->object);
-                    auto* idx = ctx.Clone(expr->index);
-                    return b.IndexAccessor(obj, idx);
-                }
+    ctx.ReplaceAll([&](const IndexAccessorExpression* expr) -> const IndexAccessorExpression* {
+        if (auto* access = src->Sem().Get<sem::StructMemberAccess>(expr->object)) {
+            if (decomposed.Contains(access->Member())) {
+                auto* obj = ctx.CloneWithoutTransform(expr->object);
+                auto* idx = ctx.Clone(expr->index);
+                return b.IndexAccessor(obj, idx);
             }
-            return nullptr;
-        });
+        }
+        return nullptr;
+    });
 
     // For all struct member accesses to the matrix on the LHS of an assignment,
     // we need to convert the matrix to the array before assigning to the
@@ -129,7 +127,7 @@
     // Example:
     //   ssbo.mat = mat_to_arr(m)
     std::unordered_map<MatrixInfo, Symbol, MatrixInfo::Hasher> mat_to_arr;
-    ctx.ReplaceAll([&](const ast::AssignmentStatement* stmt) -> const ast::Statement* {
+    ctx.ReplaceAll([&](const AssignmentStatement* stmt) -> const Statement* {
         if (auto* access = src->Sem().Get<sem::StructMemberAccess>(stmt->lhs)) {
             if (auto info = decomposed.Find(access->Member())) {
                 auto fn = utils::GetOrCreate(mat_to_arr, *info, [&] {
@@ -142,7 +140,7 @@
                     auto array = [&] { return info->array(ctx.dst); };
 
                     auto mat = b.Sym("m");
-                    utils::Vector<const ast::Expression*, 4> columns;
+                    utils::Vector<const Expression*, 4> columns;
                     for (uint32_t i = 0; i < static_cast<uint32_t>(info->matrix->columns()); i++) {
                         columns.Push(b.IndexAccessor(mat, u32(i)));
                     }
@@ -168,7 +166,7 @@
     // matrix type. Example:
     //   m = arr_to_mat(ssbo.mat)
     std::unordered_map<MatrixInfo, Symbol, MatrixInfo::Hasher> arr_to_mat;
-    ctx.ReplaceAll([&](const ast::MemberAccessorExpression* expr) -> const ast::Expression* {
+    ctx.ReplaceAll([&](const MemberAccessorExpression* expr) -> const Expression* {
         if (auto* access = src->Sem().Get(expr)->UnwrapLoad()->As<sem::StructMemberAccess>()) {
             if (auto info = decomposed.Find(access->Member())) {
                 auto fn = utils::GetOrCreate(arr_to_mat, *info, [&] {
@@ -181,7 +179,7 @@
                     auto array = [&] { return info->array(ctx.dst); };
 
                     auto arr = b.Sym("arr");
-                    utils::Vector<const ast::Expression*, 4> columns;
+                    utils::Vector<const Expression*, 4> columns;
                     for (uint32_t i = 0; i < static_cast<uint32_t>(info->matrix->columns()); i++) {
                         columns.Push(b.IndexAccessor(arr, u32(i)));
                     }
@@ -205,4 +203,4 @@
     return Program(std::move(b));
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/decompose_strided_matrix.h b/src/tint/ast/transform/decompose_strided_matrix.h
similarity index 82%
rename from src/tint/transform/decompose_strided_matrix.h
rename to src/tint/ast/transform/decompose_strided_matrix.h
index 8fa0feb..2fa6324 100644
--- a/src/tint/transform/decompose_strided_matrix.h
+++ b/src/tint/ast/transform/decompose_strided_matrix.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_DECOMPOSE_STRIDED_MATRIX_H_
-#define SRC_TINT_TRANSFORM_DECOMPOSE_STRIDED_MATRIX_H_
+#ifndef SRC_TINT_AST_TRANSFORM_DECOMPOSE_STRIDED_MATRIX_H_
+#define SRC_TINT_AST_TRANSFORM_DECOMPOSE_STRIDED_MATRIX_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// DecomposeStridedMatrix transforms replaces matrix members of storage or
 /// uniform buffer structures, that have a stride attribute, into an array
@@ -41,6 +41,6 @@
                       DataMap& outputs) const override;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_DECOMPOSE_STRIDED_MATRIX_H_
+#endif  // SRC_TINT_AST_TRANSFORM_DECOMPOSE_STRIDED_MATRIX_H_
diff --git a/src/tint/transform/decompose_strided_matrix_test.cc b/src/tint/ast/transform/decompose_strided_matrix_test.cc
similarity index 72%
rename from src/tint/transform/decompose_strided_matrix_test.cc
rename to src/tint/ast/transform/decompose_strided_matrix_test.cc
index 12ca02e..4fa8017 100644
--- a/src/tint/transform/decompose_strided_matrix_test.cc
+++ b/src/tint/ast/transform/decompose_strided_matrix_test.cc
@@ -12,21 +12,21 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/decompose_strided_matrix.h"
+#include "src/tint/ast/transform/decompose_strided_matrix.h"
 
 #include <memory>
 #include <utility>
 #include <vector>
 
 #include "src/tint/ast/disable_validation_attribute.h"
+#include "src/tint/ast/transform/simplify_pointers.h"
+#include "src/tint/ast/transform/test_helper.h"
+#include "src/tint/ast/transform/unshadow.h"
 #include "src/tint/program_builder.h"
-#include "src/tint/transform/simplify_pointers.h"
-#include "src/tint/transform/test_helper.h"
-#include "src/tint/transform/unshadow.h"
 
 using namespace tint::number_suffixes;  // NOLINT
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using DecomposeStridedMatrixTest = TransformTest;
@@ -67,22 +67,22 @@
     //   let x : mat2x2<f32> = s.m;
     // }
     ProgramBuilder b;
-    auto* S = b.Structure(
-        "S", utils::Vector{
-                 b.Member("m", b.ty.mat2x2<f32>(),
-                          utils::Vector{
-                              b.MemberOffset(16_u),
-                              b.create<ast::StrideAttribute>(32u),
-                              b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
-                          }),
-             });
+    auto* S =
+        b.Structure("S", utils::Vector{
+                             b.Member("m", b.ty.mat2x2<f32>(),
+                                      utils::Vector{
+                                          b.MemberOffset(16_u),
+                                          b.create<StrideAttribute>(32u),
+                                          b.Disable(DisabledValidation::kIgnoreStrideAttribute),
+                                      }),
+                         });
     b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kUniform, b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
                b.Decl(b.Let("x", b.ty.mat2x2<f32>(), b.MemberAccessor("s", "m"))),
            },
            utils::Vector{
-               b.Stage(ast::PipelineStage::kCompute),
+               b.Stage(PipelineStage::kCompute),
                b.WorkgroupSize(1_i),
            });
 
@@ -124,15 +124,15 @@
     //   let x : vec2<f32> = s.m[1];
     // }
     ProgramBuilder b;
-    auto* S = b.Structure(
-        "S", utils::Vector{
-                 b.Member("m", b.ty.mat2x2<f32>(),
-                          utils::Vector{
-                              b.MemberOffset(16_u),
-                              b.create<ast::StrideAttribute>(32u),
-                              b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
-                          }),
-             });
+    auto* S =
+        b.Structure("S", utils::Vector{
+                             b.Member("m", b.ty.mat2x2<f32>(),
+                                      utils::Vector{
+                                          b.MemberOffset(16_u),
+                                          b.create<StrideAttribute>(32u),
+                                          b.Disable(DisabledValidation::kIgnoreStrideAttribute),
+                                      }),
+                         });
     b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kUniform, b.Group(0_a), b.Binding(0_a));
     b.Func(
         "f", utils::Empty, b.ty.void_(),
@@ -140,7 +140,7 @@
             b.Decl(b.Let("x", b.ty.vec2<f32>(), b.IndexAccessor(b.MemberAccessor("s", "m"), 1_i))),
         },
         utils::Vector{
-            b.Stage(ast::PipelineStage::kCompute),
+            b.Stage(PipelineStage::kCompute),
             b.WorkgroupSize(1_i),
         });
 
@@ -178,22 +178,22 @@
     //   let x : mat2x2<f32> = s.m;
     // }
     ProgramBuilder b;
-    auto* S = b.Structure(
-        "S", utils::Vector{
-                 b.Member("m", b.ty.mat2x2<f32>(),
-                          utils::Vector{
-                              b.MemberOffset(16_u),
-                              b.create<ast::StrideAttribute>(8u),
-                              b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
-                          }),
-             });
+    auto* S =
+        b.Structure("S", utils::Vector{
+                             b.Member("m", b.ty.mat2x2<f32>(),
+                                      utils::Vector{
+                                          b.MemberOffset(16_u),
+                                          b.create<StrideAttribute>(8u),
+                                          b.Disable(DisabledValidation::kIgnoreStrideAttribute),
+                                      }),
+                         });
     b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kUniform, b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
                b.Decl(b.Let("x", b.ty.mat2x2<f32>(), b.MemberAccessor("s", "m"))),
            },
            utils::Vector{
-               b.Stage(ast::PipelineStage::kCompute),
+               b.Stage(PipelineStage::kCompute),
                b.WorkgroupSize(1_i),
            });
 
@@ -232,15 +232,15 @@
     //   let x : mat2x2<f32> = s.m;
     // }
     ProgramBuilder b;
-    auto* S = b.Structure(
-        "S", utils::Vector{
-                 b.Member("m", b.ty.mat2x2<f32>(),
-                          utils::Vector{
-                              b.MemberOffset(8_u),
-                              b.create<ast::StrideAttribute>(32u),
-                              b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
-                          }),
-             });
+    auto* S =
+        b.Structure("S", utils::Vector{
+                             b.Member("m", b.ty.mat2x2<f32>(),
+                                      utils::Vector{
+                                          b.MemberOffset(8_u),
+                                          b.create<StrideAttribute>(32u),
+                                          b.Disable(DisabledValidation::kIgnoreStrideAttribute),
+                                      }),
+                         });
     b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
                 b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
@@ -248,7 +248,7 @@
                b.Decl(b.Let("x", b.ty.mat2x2<f32>(), b.MemberAccessor("s", "m"))),
            },
            utils::Vector{
-               b.Stage(ast::PipelineStage::kCompute),
+               b.Stage(PipelineStage::kCompute),
                b.WorkgroupSize(1_i),
            });
 
@@ -290,15 +290,15 @@
     //   let x : vec2<f32> = s.m[1];
     // }
     ProgramBuilder b;
-    auto* S = b.Structure(
-        "S", utils::Vector{
-                 b.Member("m", b.ty.mat2x2<f32>(),
-                          utils::Vector{
-                              b.MemberOffset(16_u),
-                              b.create<ast::StrideAttribute>(32u),
-                              b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
-                          }),
-             });
+    auto* S =
+        b.Structure("S", utils::Vector{
+                             b.Member("m", b.ty.mat2x2<f32>(),
+                                      utils::Vector{
+                                          b.MemberOffset(16_u),
+                                          b.create<StrideAttribute>(32u),
+                                          b.Disable(DisabledValidation::kIgnoreStrideAttribute),
+                                      }),
+                         });
     b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
                 b.Group(0_a), b.Binding(0_a));
     b.Func(
@@ -307,7 +307,7 @@
             b.Decl(b.Let("x", b.ty.vec2<f32>(), b.IndexAccessor(b.MemberAccessor("s", "m"), 1_i))),
         },
         utils::Vector{
-            b.Stage(ast::PipelineStage::kCompute),
+            b.Stage(PipelineStage::kCompute),
             b.WorkgroupSize(1_i),
         });
 
@@ -345,15 +345,15 @@
     //   s.m = mat2x2<f32>(vec2<f32>(1.0, 2.0), vec2<f32>(3.0, 4.0));
     // }
     ProgramBuilder b;
-    auto* S = b.Structure(
-        "S", utils::Vector{
-                 b.Member("m", b.ty.mat2x2<f32>(),
-                          utils::Vector{
-                              b.MemberOffset(8_u),
-                              b.create<ast::StrideAttribute>(32u),
-                              b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
-                          }),
-             });
+    auto* S =
+        b.Structure("S", utils::Vector{
+                             b.Member("m", b.ty.mat2x2<f32>(),
+                                      utils::Vector{
+                                          b.MemberOffset(8_u),
+                                          b.create<StrideAttribute>(32u),
+                                          b.Disable(DisabledValidation::kIgnoreStrideAttribute),
+                                      }),
+                         });
     b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
                 b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
@@ -362,7 +362,7 @@
                         b.mat2x2<f32>(b.vec2<f32>(1_f, 2_f), b.vec2<f32>(3_f, 4_f))),
            },
            utils::Vector{
-               b.Stage(ast::PipelineStage::kCompute),
+               b.Stage(PipelineStage::kCompute),
                b.WorkgroupSize(1_i),
            });
 
@@ -404,15 +404,15 @@
     //   s.m[1] = vec2<f32>(1.0, 2.0);
     // }
     ProgramBuilder b;
-    auto* S = b.Structure(
-        "S", utils::Vector{
-                 b.Member("m", b.ty.mat2x2<f32>(),
-                          utils::Vector{
-                              b.MemberOffset(8_u),
-                              b.create<ast::StrideAttribute>(32u),
-                              b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
-                          }),
-             });
+    auto* S =
+        b.Structure("S", utils::Vector{
+                             b.Member("m", b.ty.mat2x2<f32>(),
+                                      utils::Vector{
+                                          b.MemberOffset(8_u),
+                                          b.create<StrideAttribute>(32u),
+                                          b.Disable(DisabledValidation::kIgnoreStrideAttribute),
+                                      }),
+                         });
     b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
                 b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
@@ -420,7 +420,7 @@
                b.Assign(b.IndexAccessor(b.MemberAccessor("s", "m"), 1_i), b.vec2<f32>(1_f, 2_f)),
            },
            utils::Vector{
-               b.Stage(ast::PipelineStage::kCompute),
+               b.Stage(PipelineStage::kCompute),
                b.WorkgroupSize(1_i),
            });
 
@@ -464,15 +464,15 @@
     //   (*b)[1] = vec2<f32>(5.0, 6.0);
     // }
     ProgramBuilder b;
-    auto* S = b.Structure(
-        "S", utils::Vector{
-                 b.Member("m", b.ty.mat2x2<f32>(),
-                          utils::Vector{
-                              b.MemberOffset(8_u),
-                              b.create<ast::StrideAttribute>(32u),
-                              b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
-                          }),
-             });
+    auto* S =
+        b.Structure("S", utils::Vector{
+                             b.Member("m", b.ty.mat2x2<f32>(),
+                                      utils::Vector{
+                                          b.MemberOffset(8_u),
+                                          b.create<StrideAttribute>(32u),
+                                          b.Disable(DisabledValidation::kIgnoreStrideAttribute),
+                                      }),
+                         });
     b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kStorage, builtin::Access::kReadWrite,
                 b.Group(0_a), b.Binding(0_a));
     b.Func("f", utils::Empty, b.ty.void_(),
@@ -486,7 +486,7 @@
                b.Assign(b.IndexAccessor(b.Deref("b"), 1_i), b.vec2<f32>(5_f, 6_f)),
            },
            utils::Vector{
-               b.Stage(ast::PipelineStage::kCompute),
+               b.Stage(PipelineStage::kCompute),
                b.WorkgroupSize(1_i),
            });
 
@@ -536,22 +536,22 @@
     //   let x : mat2x2<f32> = s.m;
     // }
     ProgramBuilder b;
-    auto* S = b.Structure(
-        "S", utils::Vector{
-                 b.Member("m", b.ty.mat2x2<f32>(),
-                          utils::Vector{
-                              b.MemberOffset(8_u),
-                              b.create<ast::StrideAttribute>(32u),
-                              b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
-                          }),
-             });
+    auto* S =
+        b.Structure("S", utils::Vector{
+                             b.Member("m", b.ty.mat2x2<f32>(),
+                                      utils::Vector{
+                                          b.MemberOffset(8_u),
+                                          b.create<StrideAttribute>(32u),
+                                          b.Disable(DisabledValidation::kIgnoreStrideAttribute),
+                                      }),
+                         });
     b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kPrivate);
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
                b.Decl(b.Let("x", b.ty.mat2x2<f32>(), b.MemberAccessor("s", "m"))),
            },
            utils::Vector{
-               b.Stage(ast::PipelineStage::kCompute),
+               b.Stage(PipelineStage::kCompute),
                b.WorkgroupSize(1_i),
            });
 
@@ -590,15 +590,15 @@
     //   s.m = mat2x2<f32>(vec2<f32>(1.0, 2.0), vec2<f32>(3.0, 4.0));
     // }
     ProgramBuilder b;
-    auto* S = b.Structure(
-        "S", utils::Vector{
-                 b.Member("m", b.ty.mat2x2<f32>(),
-                          utils::Vector{
-                              b.MemberOffset(8_u),
-                              b.create<ast::StrideAttribute>(32u),
-                              b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
-                          }),
-             });
+    auto* S =
+        b.Structure("S", utils::Vector{
+                             b.Member("m", b.ty.mat2x2<f32>(),
+                                      utils::Vector{
+                                          b.MemberOffset(8_u),
+                                          b.create<StrideAttribute>(32u),
+                                          b.Disable(DisabledValidation::kIgnoreStrideAttribute),
+                                      }),
+                         });
     b.GlobalVar("s", b.ty.Of(S), builtin::AddressSpace::kPrivate);
     b.Func("f", utils::Empty, b.ty.void_(),
            utils::Vector{
@@ -606,7 +606,7 @@
                         b.mat2x2<f32>(b.vec2<f32>(1_f, 2_f), b.vec2<f32>(3_f, 4_f))),
            },
            utils::Vector{
-               b.Stage(ast::PipelineStage::kCompute),
+               b.Stage(PipelineStage::kCompute),
                b.WorkgroupSize(1_i),
            });
 
@@ -633,4 +633,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/demote_to_helper.cc b/src/tint/ast/transform/demote_to_helper.cc
similarity index 93%
rename from src/tint/transform/demote_to_helper.cc
rename to src/tint/ast/transform/demote_to_helper.cc
index 46e9203..8e67ddb 100644
--- a/src/tint/transform/demote_to_helper.cc
+++ b/src/tint/ast/transform/demote_to_helper.cc
@@ -12,27 +12,27 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/demote_to_helper.h"
+#include "src/tint/ast/transform/demote_to_helper.h"
 
 #include <unordered_map>
 #include <unordered_set>
 #include <utility>
 
+#include "src/tint/ast/transform/utils/hoist_to_decl_before.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/block_statement.h"
 #include "src/tint/sem/call.h"
 #include "src/tint/sem/function.h"
 #include "src/tint/sem/statement.h"
 #include "src/tint/switch.h"
-#include "src/tint/transform/utils/hoist_to_decl_before.h"
 #include "src/tint/type/reference.h"
 #include "src/tint/utils/map.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::DemoteToHelper);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::DemoteToHelper);
 
 using namespace tint::number_suffixes;  // NOLINT
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 DemoteToHelper::DemoteToHelper() = default;
 
@@ -85,9 +85,8 @@
     b.GlobalVar(flag, builtin::AddressSpace::kPrivate, b.Expr(false));
 
     // Replace all discard statements with a statement that marks the invocation as discarded.
-    ctx.ReplaceAll([&](const ast::DiscardStatement*) -> const ast::Statement* {
-        return b.Assign(flag, b.Expr(true));
-    });
+    ctx.ReplaceAll(
+        [&](const DiscardStatement*) -> const Statement* { return b.Assign(flag, b.Expr(true)); });
 
     // Insert a conditional discard at the end of each entry point that does not end with a return.
     for (auto* func : functions_to_process) {
@@ -111,7 +110,7 @@
             node,
 
             // Mask assignments to storage buffer variables.
-            [&](const ast::AssignmentStatement* assign) {
+            [&](const AssignmentStatement* assign) {
                 // Skip writes in functions that are not called from shaders that discard.
                 auto* func = sem.Get(assign)->Function();
                 if (functions_to_process.count(func) == 0) {
@@ -119,7 +118,7 @@
                 }
 
                 // Skip phony assignments.
-                if (assign->lhs->Is<ast::PhonyExpression>()) {
+                if (assign->lhs->Is<PhonyExpression>()) {
                     return;
                 }
 
@@ -144,7 +143,7 @@
             },
 
             // Mask builtins that write to host-visible memory.
-            [&](const ast::CallExpression* call) {
+            [&](const CallExpression* call) {
                 auto* sem_call = sem.Get<sem::Call>(call);
                 auto* stmt = sem_call ? sem_call->Stmt() : nullptr;
                 auto* func = stmt ? stmt->Function() : nullptr;
@@ -161,7 +160,7 @@
                 } else if (builtin->IsAtomic() &&
                            builtin->Type() != builtin::Function::kAtomicLoad) {
                     // A call to an atomic builtin can be a statement or an expression.
-                    if (auto* call_stmt = stmt->Declaration()->As<ast::CallStatement>();
+                    if (auto* call_stmt = stmt->Declaration()->As<CallStatement>();
                         call_stmt && call_stmt->expr == call) {
                         // This call is a statement.
                         // Wrap it inside a conditional block.
@@ -178,8 +177,8 @@
                         //   }
                         //   let y = x + tmp;
                         auto result = b.Sym();
-                        ast::Type result_ty;
-                        const ast::Statement* masked_call = nullptr;
+                        Type result_ty;
+                        const Statement* masked_call = nullptr;
                         if (builtin->Type() == builtin::Function::kAtomicCompareExchangeWeak) {
                             // Special case for atomicCompareExchangeWeak as we cannot name its
                             // result type. We have to declare an equivalent struct and copy the
@@ -232,7 +231,7 @@
             },
 
             // Insert a conditional discard before all return statements in entry points.
-            [&](const ast::ReturnStatement* ret) {
+            [&](const ReturnStatement* ret) {
                 auto* func = sem.Get(ret)->Function();
                 if (func->Declaration()->IsEntryPoint() && functions_to_process.count(func)) {
                     auto* discard = b.If(flag, b.Block(b.Discard()));
@@ -246,4 +245,4 @@
     return Program(std::move(b));
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/demote_to_helper.h b/src/tint/ast/transform/demote_to_helper.h
similarity index 84%
rename from src/tint/transform/demote_to_helper.h
rename to src/tint/ast/transform/demote_to_helper.h
index 75909d2..a3529ec 100644
--- a/src/tint/transform/demote_to_helper.h
+++ b/src/tint/ast/transform/demote_to_helper.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_DEMOTE_TO_HELPER_H_
-#define SRC_TINT_TRANSFORM_DEMOTE_TO_HELPER_H_
+#ifndef SRC_TINT_AST_TRANSFORM_DEMOTE_TO_HELPER_H_
+#define SRC_TINT_AST_TRANSFORM_DEMOTE_TO_HELPER_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// Implement demote-to-helper semantics for discard statements.
 ///
@@ -42,6 +42,6 @@
                       DataMap& outputs) const override;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_DEMOTE_TO_HELPER_H_
+#endif  // SRC_TINT_AST_TRANSFORM_DEMOTE_TO_HELPER_H_
diff --git a/src/tint/transform/demote_to_helper_test.cc b/src/tint/ast/transform/demote_to_helper_test.cc
similarity index 99%
rename from src/tint/transform/demote_to_helper_test.cc
rename to src/tint/ast/transform/demote_to_helper_test.cc
index 3753360..6d9e698 100644
--- a/src/tint/transform/demote_to_helper_test.cc
+++ b/src/tint/ast/transform/demote_to_helper_test.cc
@@ -12,13 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/demote_to_helper.h"
+#include "src/tint/ast/transform/demote_to_helper.h"
 
 #include <utility>
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using DemoteToHelperTest = TransformTest;
@@ -1202,4 +1202,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/direct_variable_access.cc b/src/tint/ast/transform/direct_variable_access.cc
similarity index 96%
rename from src/tint/transform/direct_variable_access.cc
rename to src/tint/ast/transform/direct_variable_access.cc
index 8c06afc..f4160d4 100644
--- a/src/tint/transform/direct_variable_access.cc
+++ b/src/tint/ast/transform/direct_variable_access.cc
@@ -12,12 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/direct_variable_access.h"
+#include "src/tint/ast/transform/direct_variable_access.h"
 
 #include <algorithm>
 #include <string>
 #include <utility>
 
+#include "src/tint/ast/transform/utils/hoist_to_decl_before.h"
 #include "src/tint/ast/traverse_expressions.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/call.h"
@@ -28,14 +29,13 @@
 #include "src/tint/sem/statement.h"
 #include "src/tint/sem/struct.h"
 #include "src/tint/sem/variable.h"
-#include "src/tint/transform/utils/hoist_to_decl_before.h"
 #include "src/tint/type/abstract_int.h"
 #include "src/tint/utils/reverse.h"
 #include "src/tint/utils/scoped_assignment.h"
 #include "src/tint/utils/string_stream.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::DirectVariableAccess);
-TINT_INSTANTIATE_TYPEINFO(tint::transform::DirectVariableAccess::Config);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::DirectVariableAccess);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::DirectVariableAccess::Config);
 
 using namespace tint::number_suffixes;  // NOLINT
 
@@ -190,7 +190,7 @@
 
 }  // namespace tint::utils
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// The PIMPL state for the DirectVariableAccess transform
 struct DirectVariableAccess::State {
@@ -450,19 +450,19 @@
 
                 Switch(
                     variable->Declaration(),
-                    [&](const ast::Var*) {
+                    [&](const Var*) {
                         if (variable->AddressSpace() != builtin::AddressSpace::kHandle) {
                             // Start a new access chain for the non-handle 'var' access
                             create_new_chain();
                         }
                     },
-                    [&](const ast::Parameter*) {
+                    [&](const Parameter*) {
                         if (variable->Type()->Is<type::Pointer>()) {
                             // Start a new access chain for the pointer parameter access
                             create_new_chain();
                         }
                     },
-                    [&](const ast::Let*) {
+                    [&](const Let*) {
                         if (variable->Type()->Is<type::Pointer>()) {
                             // variable is a pointer-let.
                             auto* init = sem.GetVal(variable->Declaration()->initializer);
@@ -494,11 +494,10 @@
                 }
             },
             [&](const sem::ValueExpression* e) {
-                if (auto* unary = e->Declaration()->As<ast::UnaryOpExpression>()) {
+                if (auto* unary = e->Declaration()->As<UnaryOpExpression>()) {
                     // Unary op.
                     // If this is a '&' or '*', simply move the chain to the unary op expression.
-                    if (unary->op == ast::UnaryOp::kAddressOf ||
-                        unary->op == ast::UnaryOp::kIndirection) {
+                    if (unary->op == UnaryOp::kAddressOf || unary->op == UnaryOp::kIndirection) {
                         take_chain(sem.GetVal(unary->expr));
                     }
                 }
@@ -529,7 +528,7 @@
 
             if (auto* idx_variable_user = idx->UnwrapMaterialize()->As<sem::VariableUser>()) {
                 auto* idx_variable = idx_variable_user->Variable();
-                if (idx_variable->Declaration()->IsAnyOf<ast::Let, ast::Parameter>()) {
+                if (idx_variable->Declaration()->IsAnyOf<Let, Parameter>()) {
                     // Dynamic index is an immutable variable
                     continue;  // Hoisting not required.
                 }
@@ -557,7 +556,7 @@
     /// * Casts the resulting expression to a u32 if @p cast_to_u32 is true, and the expression type
     ///   isn't implicitly usable as a u32. This is to help feed the expression into a
     ///   `array<u32, N>` argument passed to a callee variant function.
-    const ast::Expression* BuildDynamicIndex(const sem::ValueExpression* idx, bool cast_to_u32) {
+    const Expression* BuildDynamicIndex(const sem::ValueExpression* idx, bool cast_to_u32) {
         if (auto* val = idx->ConstantValue()) {
             // Expression evaluated to a constant value. Just emit that constant.
             return b.Expr(val->ValueAs<AInt>());
@@ -808,7 +807,7 @@
             // many variant functions, keep a record of the last created variant, and explicitly add
             // this to the module if it isn't the last. We'll return the last created variant,
             // taking the place of the original function.
-            const ast::Function* pending_variant = nullptr;
+            const Function* pending_variant = nullptr;
 
             // For each variant of fn...
             for (auto variant_it : fn_info->SortedVariants()) {
@@ -827,7 +826,7 @@
                 // Pointer parameters in the 'uniform', 'storage' or 'workgroup' address space are
                 // either replaced with an array of dynamic indices, or are dropped (if there are no
                 // dynamic indices).
-                utils::Vector<const ast::Parameter*, 8> params;
+                utils::Vector<const Parameter*, 8> params;
                 for (auto* param : fn->Parameters()) {
                     if (auto incoming_shape = variant_sig.Find(param)) {
                         auto& symbols = *variant.ptr_param_symbols.Find(param);
@@ -856,8 +855,8 @@
                 auto attrs = ctx.Clone(fn->Declaration()->attributes);
                 auto ret_attrs = ctx.Clone(fn->Declaration()->return_type_attributes);
                 pending_variant =
-                    b.create<ast::Function>(b.Ident(variant.name), std::move(params), ret_ty, body,
-                                            std::move(attrs), std::move(ret_attrs));
+                    b.create<Function>(b.Ident(variant.name), std::move(params), ret_ty, body,
+                                       std::move(attrs), std::move(ret_attrs));
             }
 
             return pending_variant;
@@ -877,7 +876,7 @@
             }
 
             // Build the new call expressions's arguments.
-            utils::Vector<const ast::Expression*, 8> new_args;
+            utils::Vector<const Expression*, 8> new_args;
             for (size_t arg_idx = 0; arg_idx < call->Arguments().Length(); arg_idx++) {
                 auto* arg = call->Arguments()[arg_idx];
                 auto* param = call->Target()->Parameters()[arg_idx];
@@ -915,7 +914,7 @@
                 // Get or create the dynamic indices array.
                 if (auto dyn_idx_arr_ty = DynamicIndexArrayType(full_indices)) {
                     // Build an array of dynamic indices to pass as the replacement for the pointer.
-                    utils::Vector<const ast::Expression*, 8> dyn_idx_args;
+                    utils::Vector<const Expression*, 8> dyn_idx_args;
                     if (auto* root_param = chain->root.variable->As<sem::Parameter>()) {
                         // Access chain originates from a pointer parameter.
                         if (auto incoming_chain =
@@ -985,7 +984,7 @@
     ///   let.
     void TransformAccessChainExpressions() {
         // Register a custom handler for all non-function call expressions
-        ctx.ReplaceAll([this](const ast::Expression* ast_expr) -> const ast::Expression* {
+        ctx.ReplaceAll([this](const Expression* ast_expr) -> const Expression* {
             if (!clone_state->current_variant) {
                 // Expression does not belong to a function variant.
                 return nullptr;  // Just clone the expression.
@@ -1065,7 +1064,7 @@
 
     /// @returns the type alias used to hold the dynamic indices for @p shape, declaring a new alias
     /// if this is the first call for the given shape.
-    ast::Type DynamicIndexArrayType(const AccessShape& shape) {
+    Type DynamicIndexArrayType(const AccessShape& shape) {
         auto name = dynamic_index_array_aliases.GetOrCreate(shape, [&] {
             // Count the number of dynamic indices
             uint32_t num_dyn_indices = shape.NumDynamicIndices();
@@ -1076,7 +1075,7 @@
             b.Alias(symbol, b.ty.array(b.ty.u32(), u32(num_dyn_indices)));
             return symbol;
         });
-        return name.IsValid() ? b.ty(name) : ast::Type{};
+        return name.IsValid() ? b.ty(name) : Type{};
     }
 
     /// @returns a name describing the given shape
@@ -1113,7 +1112,7 @@
     /// Builds an expresion to the root of an access, returning the new expression.
     /// @param root the AccessRoot
     /// @param deref if true, the returned expression will always be a reference type.
-    const ast::Expression* BuildAccessRootExpr(const AccessRoot& root, bool deref) {
+    const Expression* BuildAccessRootExpr(const AccessRoot& root, bool deref) {
         if (auto* param = root.variable->As<sem::Parameter>()) {
             if (auto symbols = clone_state->current_variant->ptr_param_symbols.Find(param)) {
                 if (deref) {
@@ -1123,7 +1122,7 @@
             }
         }
 
-        const ast::Expression* expr = b.Expr(ctx.Clone(root.variable->Declaration()->name->symbol));
+        const Expression* expr = b.Expr(ctx.Clone(root.variable->Declaration()->name->symbol));
         if (deref) {
             if (root.variable->Type()->Is<type::Pointer>()) {
                 expr = b.Deref(expr);
@@ -1137,10 +1136,9 @@
     /// @param expr the input expression
     /// @param access the access to perform on the current expression
     /// @param dynamic_index a function that obtains the i'th dynamic index
-    const ast::Expression* BuildAccessExpr(
-        const ast::Expression* expr,
-        const AccessOp& access,
-        std::function<const ast::Expression*(size_t)> dynamic_index) {
+    const Expression* BuildAccessExpr(const Expression* expr,
+                                      const AccessOp& access,
+                                      std::function<const Expression*(size_t)> dynamic_index) {
         if (auto* dyn_idx = std::get_if<DynamicIndex>(&access)) {
             /// The access uses a dynamic (runtime-expression) index.
             auto* idx = dynamic_index(dyn_idx->slot);
@@ -1217,4 +1215,4 @@
     return State(program, options).Run();
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/direct_variable_access.h b/src/tint/ast/transform/direct_variable_access.h
similarity index 86%
rename from src/tint/transform/direct_variable_access.h
rename to src/tint/ast/transform/direct_variable_access.h
index 74aafa7..adf8d94 100644
--- a/src/tint/transform/direct_variable_access.h
+++ b/src/tint/ast/transform/direct_variable_access.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_DIRECT_VARIABLE_ACCESS_H_
-#define SRC_TINT_TRANSFORM_DIRECT_VARIABLE_ACCESS_H_
+#ifndef SRC_TINT_AST_TRANSFORM_DIRECT_VARIABLE_ACCESS_H_
+#define SRC_TINT_AST_TRANSFORM_DIRECT_VARIABLE_ACCESS_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// DirectVariableAccess is a transform that allows usage of pointer parameters in the 'storage',
 /// 'uniform' and 'workgroup' address space, and passing of pointers to sub-objects. These pointers
@@ -29,7 +29,7 @@
 /// unique variable. Calls to specialized functions are transformed so that the pointer arguments
 /// are replaced with an array of access-chain indicies, and if the pointer is in the 'function' or
 /// 'private' address space, also with a pointer to the root object. For more information, see the
-/// comments in src/tint/transform/direct_variable_access.cc.
+/// comments in src/tint/ast/transform/direct_variable_access.cc.
 ///
 /// @note DirectVariableAccess requires the transform::Unshadow transform to have been run first.
 class DirectVariableAccess final : public utils::Castable<DirectVariableAccess, Transform> {
@@ -49,7 +49,7 @@
 
     /// Config is consumed by the DirectVariableAccess transform.
     /// Config specifies the behavior of the transform.
-    struct Config final : public utils::Castable<Data, transform::Data> {
+    struct Config final : public utils::Castable<Config, Data> {
         /// Constructor
         /// @param options behavior of the transform
         explicit Config(const Options& options);
@@ -69,6 +69,6 @@
     struct State;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_DIRECT_VARIABLE_ACCESS_H_
+#endif  // SRC_TINT_AST_TRANSFORM_DIRECT_VARIABLE_ACCESS_H_
diff --git a/src/tint/transform/direct_variable_access_test.cc b/src/tint/ast/transform/direct_variable_access_test.cc
similarity index 99%
rename from src/tint/transform/direct_variable_access_test.cc
rename to src/tint/ast/transform/direct_variable_access_test.cc
index cc77748..b735991 100644
--- a/src/tint/transform/direct_variable_access_test.cc
+++ b/src/tint/ast/transform/direct_variable_access_test.cc
@@ -12,15 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/direct_variable_access.h"
+#include "src/tint/ast/transform/direct_variable_access.h"
 
 #include <memory>
 #include <utility>
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 #include "src/tint/utils/string.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 /// @returns a DataMap with DirectVariableAccess::Config::transform_private enabled.
@@ -2710,4 +2710,4 @@
 }  // namespace complex_tests
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/disable_uniformity_analysis.cc b/src/tint/ast/transform/disable_uniformity_analysis.cc
similarity index 86%
rename from src/tint/transform/disable_uniformity_analysis.cc
rename to src/tint/ast/transform/disable_uniformity_analysis.cc
index 7c26fb8..8e3a780 100644
--- a/src/tint/transform/disable_uniformity_analysis.cc
+++ b/src/tint/ast/transform/disable_uniformity_analysis.cc
@@ -12,16 +12,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/disable_uniformity_analysis.h"
+#include "src/tint/ast/transform/disable_uniformity_analysis.h"
 
 #include <utility>
 
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/module.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::DisableUniformityAnalysis);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::DisableUniformityAnalysis);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 DisableUniformityAnalysis::DisableUniformityAnalysis() = default;
 
@@ -43,4 +43,4 @@
     return Program(std::move(b));
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/disable_uniformity_analysis.h b/src/tint/ast/transform/disable_uniformity_analysis.h
similarity index 77%
rename from src/tint/transform/disable_uniformity_analysis.h
rename to src/tint/ast/transform/disable_uniformity_analysis.h
index a2827c5..5e53303 100644
--- a/src/tint/transform/disable_uniformity_analysis.h
+++ b/src/tint/ast/transform/disable_uniformity_analysis.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_DISABLE_UNIFORMITY_ANALYSIS_H_
-#define SRC_TINT_TRANSFORM_DISABLE_UNIFORMITY_ANALYSIS_H_
+#ifndef SRC_TINT_AST_TRANSFORM_DISABLE_UNIFORMITY_ANALYSIS_H_
+#define SRC_TINT_AST_TRANSFORM_DISABLE_UNIFORMITY_ANALYSIS_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// Disable uniformity analysis for the program.
 class DisableUniformityAnalysis final
@@ -34,6 +34,6 @@
                       DataMap& outputs) const override;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_DISABLE_UNIFORMITY_ANALYSIS_H_
+#endif  // SRC_TINT_AST_TRANSFORM_DISABLE_UNIFORMITY_ANALYSIS_H_
diff --git a/src/tint/transform/disable_uniformity_analysis_test.cc b/src/tint/ast/transform/disable_uniformity_analysis_test.cc
similarity index 90%
rename from src/tint/transform/disable_uniformity_analysis_test.cc
rename to src/tint/ast/transform/disable_uniformity_analysis_test.cc
index 3bcac0e..4c6f4bf 100644
--- a/src/tint/transform/disable_uniformity_analysis_test.cc
+++ b/src/tint/ast/transform/disable_uniformity_analysis_test.cc
@@ -12,14 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/disable_uniformity_analysis.h"
+#include "src/tint/ast/transform/disable_uniformity_analysis.h"
 
 #include <string>
 #include <utility>
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using DisableUniformityAnalysisTest = TransformTest;
@@ -70,4 +70,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/expand_compound_assignment.cc b/src/tint/ast/transform/expand_compound_assignment.cc
similarity index 82%
rename from src/tint/transform/expand_compound_assignment.cc
rename to src/tint/ast/transform/expand_compound_assignment.cc
index f8b4111..3862d2b 100644
--- a/src/tint/transform/expand_compound_assignment.cc
+++ b/src/tint/ast/transform/expand_compound_assignment.cc
@@ -12,30 +12,30 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/expand_compound_assignment.h"
+#include "src/tint/ast/transform/expand_compound_assignment.h"
 
 #include <utility>
 
 #include "src/tint/ast/compound_assignment_statement.h"
 #include "src/tint/ast/increment_decrement_statement.h"
+#include "src/tint/ast/transform/utils/hoist_to_decl_before.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/block_statement.h"
 #include "src/tint/sem/for_loop_statement.h"
 #include "src/tint/sem/statement.h"
 #include "src/tint/sem/value_expression.h"
-#include "src/tint/transform/utils/hoist_to_decl_before.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::ExpandCompoundAssignment);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::ExpandCompoundAssignment);
 
 using namespace tint::number_suffixes;  // NOLINT
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 namespace {
 
 bool ShouldRun(const Program* program) {
     for (auto* node : program->ASTNodes().Objects()) {
-        if (node->IsAnyOf<ast::CompoundAssignmentStatement, ast::IncrementDecrementStatement>()) {
+        if (node->IsAnyOf<CompoundAssignmentStatement, IncrementDecrementStatement>()) {
             return true;
         }
     }
@@ -58,17 +58,14 @@
     /// @param lhs the lhs expression from the source statement
     /// @param rhs the rhs expression in the destination module
     /// @param op the binary operator
-    void Expand(const ast::Statement* stmt,
-                const ast::Expression* lhs,
-                const ast::Expression* rhs,
-                ast::BinaryOp op) {
+    void Expand(const Statement* stmt, const Expression* lhs, const Expression* rhs, BinaryOp op) {
         // Helper function to create the new LHS expression. This will be called
         // twice when building the non-compound assignment statement, so must
         // not produce expressions that cause side effects.
-        std::function<const ast::Expression*()> new_lhs;
+        std::function<const Expression*()> new_lhs;
 
         // Helper function to create a variable that is a pointer to `expr`.
-        auto hoist_pointer_to = [&](const ast::Expression* expr) {
+        auto hoist_pointer_to = [&](const Expression* expr) {
             auto name = b.Sym();
             auto* ptr = b.AddressOf(ctx.Clone(expr));
             auto* decl = b.Decl(b.Let(name, ptr));
@@ -77,7 +74,7 @@
         };
 
         // Helper function to hoist `expr` to a let declaration.
-        auto hoist_expr_to_let = [&](const ast::Expression* expr) {
+        auto hoist_expr_to_let = [&](const Expression* expr) {
             auto name = b.Sym();
             auto* decl = b.Decl(b.Let(name, ctx.Clone(expr)));
             hoist_to_decl_before.InsertBefore(ctx.src->Sem().Get(stmt), decl);
@@ -85,7 +82,7 @@
         };
 
         // Helper function that returns `true` if the type of `expr` is a vector.
-        auto is_vec = [&](const ast::Expression* expr) {
+        auto is_vec = [&](const Expression* expr) {
             if (auto* val_expr = ctx.src->Sem().GetVal(expr)) {
                 return val_expr->Type()->UnwrapRef()->Is<type::Vector>();
             }
@@ -96,10 +93,10 @@
         // LHS that we can evaluate twice.
         // We need to special case compound assignments to vector components since
         // we cannot take the address of a vector component.
-        auto* index_accessor = lhs->As<ast::IndexAccessorExpression>();
-        auto* member_accessor = lhs->As<ast::MemberAccessorExpression>();
-        if (lhs->Is<ast::IdentifierExpression>() ||
-            (member_accessor && member_accessor->object->Is<ast::IdentifierExpression>())) {
+        auto* index_accessor = lhs->As<IndexAccessorExpression>();
+        auto* member_accessor = lhs->As<MemberAccessorExpression>();
+        if (lhs->Is<IdentifierExpression>() ||
+            (member_accessor && member_accessor->object->Is<IdentifierExpression>())) {
             // This is the simple case with no side effects, so we can just use the
             // original LHS expression directly.
             // Before:
@@ -144,7 +141,7 @@
         }
 
         // Replace the statement with a regular assignment statement.
-        auto* value = b.create<ast::BinaryExpression>(op, new_lhs(), rhs);
+        auto* value = b.create<BinaryExpression>(op, new_lhs(), rhs);
         ctx.Replace(stmt, b.Assign(new_lhs(), value));
     }
 
@@ -174,11 +171,11 @@
     CloneContext ctx{&b, src, /* auto_clone_symbols */ true};
     State state(ctx);
     for (auto* node : src->ASTNodes().Objects()) {
-        if (auto* assign = node->As<ast::CompoundAssignmentStatement>()) {
+        if (auto* assign = node->As<CompoundAssignmentStatement>()) {
             state.Expand(assign, assign->lhs, ctx.Clone(assign->rhs), assign->op);
-        } else if (auto* inc_dec = node->As<ast::IncrementDecrementStatement>()) {
+        } else if (auto* inc_dec = node->As<IncrementDecrementStatement>()) {
             // For increment/decrement statements, `i++` becomes `i = i + 1`.
-            auto op = inc_dec->increment ? ast::BinaryOp::kAdd : ast::BinaryOp::kSubtract;
+            auto op = inc_dec->increment ? BinaryOp::kAdd : BinaryOp::kSubtract;
             state.Expand(inc_dec, inc_dec->lhs, ctx.dst->Expr(1_a), op);
         }
     }
@@ -187,4 +184,4 @@
     return Program(std::move(b));
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/expand_compound_assignment.h b/src/tint/ast/transform/expand_compound_assignment.h
similarity index 83%
rename from src/tint/transform/expand_compound_assignment.h
rename to src/tint/ast/transform/expand_compound_assignment.h
index ce5a36c..8da91b5 100644
--- a/src/tint/transform/expand_compound_assignment.h
+++ b/src/tint/ast/transform/expand_compound_assignment.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_EXPAND_COMPOUND_ASSIGNMENT_H_
-#define SRC_TINT_TRANSFORM_EXPAND_COMPOUND_ASSIGNMENT_H_
+#ifndef SRC_TINT_AST_TRANSFORM_EXPAND_COMPOUND_ASSIGNMENT_H_
+#define SRC_TINT_AST_TRANSFORM_EXPAND_COMPOUND_ASSIGNMENT_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// Converts compound assignment statements to regular assignment statements,
 /// hoisting the LHS expression if necessary.
@@ -54,6 +54,6 @@
     struct State;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_EXPAND_COMPOUND_ASSIGNMENT_H_
+#endif  // SRC_TINT_AST_TRANSFORM_EXPAND_COMPOUND_ASSIGNMENT_H_
diff --git a/src/tint/transform/expand_compound_assignment_test.cc b/src/tint/ast/transform/expand_compound_assignment_test.cc
similarity index 98%
rename from src/tint/transform/expand_compound_assignment_test.cc
rename to src/tint/ast/transform/expand_compound_assignment_test.cc
index c227398..179a6f8 100644
--- a/src/tint/transform/expand_compound_assignment_test.cc
+++ b/src/tint/ast/transform/expand_compound_assignment_test.cc
@@ -12,13 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/expand_compound_assignment.h"
+#include "src/tint/ast/transform/expand_compound_assignment.h"
 
 #include <utility>
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using ExpandCompoundAssignmentTest = TransformTest;
@@ -744,4 +744,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/first_index_offset.cc b/src/tint/ast/transform/first_index_offset.cc
similarity index 88%
rename from src/tint/transform/first_index_offset.cc
rename to src/tint/ast/transform/first_index_offset.cc
index c8d4a26..4c77efb 100644
--- a/src/tint/transform/first_index_offset.cc
+++ b/src/tint/ast/transform/first_index_offset.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/first_index_offset.h"
+#include "src/tint/ast/transform/first_index_offset.h"
 
 #include <memory>
 #include <unordered_map>
@@ -25,11 +25,11 @@
 #include "src/tint/sem/struct.h"
 #include "src/tint/sem/variable.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::FirstIndexOffset);
-TINT_INSTANTIATE_TYPEINFO(tint::transform::FirstIndexOffset::BindingPoint);
-TINT_INSTANTIATE_TYPEINFO(tint::transform::FirstIndexOffset::Data);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::FirstIndexOffset);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::FirstIndexOffset::BindingPoint);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::FirstIndexOffset::Data);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 // Uniform buffer member names
@@ -38,7 +38,7 @@
 
 bool ShouldRun(const Program* program) {
     for (auto* fn : program->AST().Functions()) {
-        if (fn->PipelineStage() == ast::PipelineStage::kVertex) {
+        if (fn->PipelineStage() == PipelineStage::kVertex) {
             return true;
         }
     }
@@ -86,9 +86,9 @@
     // Traverse the AST scanning for builtin accesses via variables (includes
     // parameters) or structure member accesses.
     for (auto* node : ctx.src->ASTNodes().Objects()) {
-        if (auto* var = node->As<ast::Variable>()) {
+        if (auto* var = node->As<Variable>()) {
             for (auto* attr : var->attributes) {
-                if (auto* builtin_attr = attr->As<ast::BuiltinAttribute>()) {
+                if (auto* builtin_attr = attr->As<BuiltinAttribute>()) {
                     builtin::BuiltinValue builtin = src->Sem().Get(builtin_attr)->Value();
                     if (builtin == builtin::BuiltinValue::kVertexIndex) {
                         auto* sem_var = ctx.src->Sem().Get(var);
@@ -103,9 +103,9 @@
                 }
             }
         }
-        if (auto* member = node->As<ast::StructMember>()) {
+        if (auto* member = node->As<StructMember>()) {
             for (auto* attr : member->attributes) {
-                if (auto* builtin_attr = attr->As<ast::BuiltinAttribute>()) {
+                if (auto* builtin_attr = attr->As<BuiltinAttribute>()) {
                     builtin::BuiltinValue builtin = src->Sem().Get(builtin_attr)->Value();
                     if (builtin == builtin::BuiltinValue::kVertexIndex) {
                         auto* sem_mem = ctx.src->Sem().Get(member);
@@ -124,7 +124,7 @@
 
     if (has_vertex_or_instance_index) {
         // Add uniform buffer members and calculate byte offsets
-        utils::Vector<const ast::StructMember*, 8> members;
+        utils::Vector<const StructMember*, 8> members;
         members.Push(b.Member(kFirstVertexName, b.ty.u32()));
         members.Push(b.Member(kFirstInstanceName, b.ty.u32()));
         auto* struct_ = b.Structure(b.Sym(), std::move(members));
@@ -138,7 +138,7 @@
                     });
 
         // Fix up all references to the builtins with the offsets
-        ctx.ReplaceAll([=, &ctx](const ast::Expression* expr) -> const ast::Expression* {
+        ctx.ReplaceAll([=, &ctx](const Expression* expr) -> const Expression* {
             if (auto* sem = ctx.src->Sem().GetVal(expr)) {
                 if (auto* user = sem->UnwrapLoad()->As<sem::VariableUser>()) {
                     auto it = builtin_vars.find(user->Variable());
@@ -166,4 +166,4 @@
     return Program(std::move(b));
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/first_index_offset.h b/src/tint/ast/transform/first_index_offset.h
similarity index 92%
rename from src/tint/transform/first_index_offset.h
rename to src/tint/ast/transform/first_index_offset.h
index dbf47ae..cb5e3f3 100644
--- a/src/tint/transform/first_index_offset.h
+++ b/src/tint/ast/transform/first_index_offset.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_FIRST_INDEX_OFFSET_H_
-#define SRC_TINT_TRANSFORM_FIRST_INDEX_OFFSET_H_
+#ifndef SRC_TINT_AST_TRANSFORM_FIRST_INDEX_OFFSET_H_
+#define SRC_TINT_AST_TRANSFORM_FIRST_INDEX_OFFSET_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// Adds firstVertex/Instance (injected via root constants) to
 /// vertex/instance index builtins.
@@ -113,6 +113,6 @@
     uint32_t group_ = 0;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_FIRST_INDEX_OFFSET_H_
+#endif  // SRC_TINT_AST_TRANSFORM_FIRST_INDEX_OFFSET_H_
diff --git a/src/tint/transform/first_index_offset_test.cc b/src/tint/ast/transform/first_index_offset_test.cc
similarity index 98%
rename from src/tint/transform/first_index_offset_test.cc
rename to src/tint/ast/transform/first_index_offset_test.cc
index c159261..1be6474 100644
--- a/src/tint/transform/first_index_offset_test.cc
+++ b/src/tint/ast/transform/first_index_offset_test.cc
@@ -12,15 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/first_index_offset.h"
+#include "src/tint/ast/transform/first_index_offset.h"
 
 #include <memory>
 #include <utility>
 #include <vector>
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using FirstIndexOffsetTest = TransformTest;
@@ -618,4 +618,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/for_loop_to_loop.cc b/src/tint/ast/transform/for_loop_to_loop.cc
similarity index 82%
rename from src/tint/transform/for_loop_to_loop.cc
rename to src/tint/ast/transform/for_loop_to_loop.cc
index 63ccb12..8b52e99 100644
--- a/src/tint/transform/for_loop_to_loop.cc
+++ b/src/tint/ast/transform/for_loop_to_loop.cc
@@ -12,21 +12,21 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/for_loop_to_loop.h"
+#include "src/tint/ast/transform/for_loop_to_loop.h"
 
 #include <utility>
 
 #include "src/tint/ast/break_statement.h"
 #include "src/tint/program_builder.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::ForLoopToLoop);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::ForLoopToLoop);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 bool ShouldRun(const Program* program) {
     for (auto* node : program->ASTNodes().Objects()) {
-        if (node->Is<ast::ForLoopStatement>()) {
+        if (node->Is<ForLoopStatement>()) {
             return true;
         }
     }
@@ -47,8 +47,8 @@
     ProgramBuilder b;
     CloneContext ctx{&b, src, /* auto_clone_symbols */ true};
 
-    ctx.ReplaceAll([&](const ast::ForLoopStatement* for_loop) -> const ast::Statement* {
-        utils::Vector<const ast::Statement*, 8> stmts;
+    ctx.ReplaceAll([&](const ForLoopStatement* for_loop) -> const Statement* {
+        utils::Vector<const Statement*, 8> stmts;
         if (auto* cond = for_loop->condition) {
             // !condition
             auto* not_cond = b.Not(ctx.Clone(cond));
@@ -63,7 +63,7 @@
             stmts.Push(ctx.Clone(stmt));
         }
 
-        const ast::BlockStatement* continuing = nullptr;
+        const BlockStatement* continuing = nullptr;
         if (auto* cont = for_loop->continuing) {
             continuing = b.Block(ctx.Clone(cont));
         }
@@ -82,4 +82,4 @@
     return Program(std::move(b));
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/for_loop_to_loop.h b/src/tint/ast/transform/for_loop_to_loop.h
similarity index 80%
rename from src/tint/transform/for_loop_to_loop.h
rename to src/tint/ast/transform/for_loop_to_loop.h
index 8ed53c5..3d8536e 100644
--- a/src/tint/transform/for_loop_to_loop.h
+++ b/src/tint/ast/transform/for_loop_to_loop.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_FOR_LOOP_TO_LOOP_H_
-#define SRC_TINT_TRANSFORM_FOR_LOOP_TO_LOOP_H_
+#ifndef SRC_TINT_AST_TRANSFORM_FOR_LOOP_TO_LOOP_H_
+#define SRC_TINT_AST_TRANSFORM_FOR_LOOP_TO_LOOP_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// ForLoopToLoop is a Transform that converts a for-loop statement into a loop
 /// statement. This is required by the SPIR-V writer.
@@ -35,6 +35,6 @@
                       DataMap& outputs) const override;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_FOR_LOOP_TO_LOOP_H_
+#endif  // SRC_TINT_AST_TRANSFORM_FOR_LOOP_TO_LOOP_H_
diff --git a/src/tint/transform/for_loop_to_loop_test.cc b/src/tint/ast/transform/for_loop_to_loop_test.cc
similarity index 96%
rename from src/tint/transform/for_loop_to_loop_test.cc
rename to src/tint/ast/transform/for_loop_to_loop_test.cc
index fa34f56..cdfc28f 100644
--- a/src/tint/transform/for_loop_to_loop_test.cc
+++ b/src/tint/ast/transform/for_loop_to_loop_test.cc
@@ -12,11 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/for_loop_to_loop.h"
+#include "src/tint/ast/transform/for_loop_to_loop.h"
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using ForLoopToLoopTest = TransformTest;
@@ -369,4 +369,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/localize_struct_array_assignment.cc b/src/tint/ast/transform/localize_struct_array_assignment.cc
similarity index 61%
rename from src/tint/transform/localize_struct_array_assignment.cc
rename to src/tint/ast/transform/localize_struct_array_assignment.cc
index 775da6a..286dd29 100644
--- a/src/tint/transform/localize_struct_array_assignment.cc
+++ b/src/tint/ast/transform/localize_struct_array_assignment.cc
@@ -12,25 +12,25 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/localize_struct_array_assignment.h"
+#include "src/tint/ast/transform/localize_struct_array_assignment.h"
 
 #include <unordered_map>
 #include <utility>
 
 #include "src/tint/ast/assignment_statement.h"
+#include "src/tint/ast/transform/simplify_pointers.h"
 #include "src/tint/ast/traverse_expressions.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/member_accessor_expression.h"
 #include "src/tint/sem/statement.h"
 #include "src/tint/sem/value_expression.h"
 #include "src/tint/sem/variable.h"
-#include "src/tint/transform/simplify_pointers.h"
 #include "src/tint/type/reference.h"
 #include "src/tint/utils/scoped_assignment.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::LocalizeStructArrayAssignment);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::LocalizeStructArrayAssignment);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// PIMPL state for the transform
 struct LocalizeStructArrayAssignment::State {
@@ -43,14 +43,14 @@
     ApplyResult Run() {
         struct Shared {
             bool process_nested_nodes = false;
-            utils::Vector<const ast::Statement*, 4> insert_before_stmts;
-            utils::Vector<const ast::Statement*, 4> insert_after_stmts;
+            utils::Vector<const Statement*, 4> insert_before_stmts;
+            utils::Vector<const Statement*, 4> insert_after_stmts;
         } s;
 
         bool made_changes = false;
 
         for (auto* node : ctx.src->ASTNodes().Objects()) {
-            if (auto* assign_stmt = node->As<ast::AssignmentStatement>()) {
+            if (auto* assign_stmt = node->As<AssignmentStatement>()) {
                 // Process if it's an assignment statement to a dynamically indexed array
                 // within a struct on a function or private storage variable. This
                 // specific use-case is what FXC fails to compile with:
@@ -70,7 +70,7 @@
                     // Reset shared state for this assignment statement
                     s = Shared{};
 
-                    const ast::Expression* new_lhs = nullptr;
+                    const Expression* new_lhs = nullptr;
                     {
                         TINT_SCOPED_ASSIGNMENT(s.process_nested_nodes, true);
                         new_lhs = ctx.Clone(assign_stmt->lhs);
@@ -98,53 +98,52 @@
             return SkipTransform;
         }
 
-        ctx.ReplaceAll(
-            [&](const ast::IndexAccessorExpression* index_access) -> const ast::Expression* {
-                if (!s.process_nested_nodes) {
-                    return nullptr;
+        ctx.ReplaceAll([&](const IndexAccessorExpression* index_access) -> const Expression* {
+            if (!s.process_nested_nodes) {
+                return nullptr;
+            }
+
+            // Indexing a member access expr?
+            auto* mem_access = index_access->object->As<MemberAccessorExpression>();
+            if (!mem_access) {
+                return nullptr;
+            }
+
+            // Process any nested IndexAccessorExpressions
+            mem_access = ctx.Clone(mem_access);
+
+            // Store the address of the member access into a let as we need to read
+            // the value twice e.g. let tint_symbol = &(s.a1);
+            auto mem_access_ptr = b.Sym();
+            s.insert_before_stmts.Push(b.Decl(b.Let(mem_access_ptr, b.AddressOf(mem_access))));
+
+            // Disable further transforms when cloning
+            TINT_SCOPED_ASSIGNMENT(s.process_nested_nodes, false);
+
+            // Copy entire array out of struct into local temp var
+            // e.g. var tint_symbol_1 = *(tint_symbol);
+            auto tmp_var = b.Sym();
+            s.insert_before_stmts.Push(b.Decl(b.Var(tmp_var, b.Deref(mem_access_ptr))));
+
+            // Replace input index_access with a clone of itself, but with its
+            // .object replaced by the new temp var. This is returned from this
+            // function to modify the original assignment statement. e.g.
+            // tint_symbol_1[uniforms.i]
+            auto* new_index_access = b.IndexAccessor(tmp_var, ctx.Clone(index_access->index));
+
+            // Assign temp var back to array
+            // e.g. *(tint_symbol) = tint_symbol_1;
+            auto* assign_rhs_to_temp = b.Assign(b.Deref(mem_access_ptr), tmp_var);
+            {
+                utils::Vector<const Statement*, 8> stmts{assign_rhs_to_temp};
+                for (auto* stmt : s.insert_after_stmts) {
+                    stmts.Push(stmt);
                 }
+                s.insert_after_stmts = std::move(stmts);
+            }
 
-                // Indexing a member access expr?
-                auto* mem_access = index_access->object->As<ast::MemberAccessorExpression>();
-                if (!mem_access) {
-                    return nullptr;
-                }
-
-                // Process any nested IndexAccessorExpressions
-                mem_access = ctx.Clone(mem_access);
-
-                // Store the address of the member access into a let as we need to read
-                // the value twice e.g. let tint_symbol = &(s.a1);
-                auto mem_access_ptr = b.Sym();
-                s.insert_before_stmts.Push(b.Decl(b.Let(mem_access_ptr, b.AddressOf(mem_access))));
-
-                // Disable further transforms when cloning
-                TINT_SCOPED_ASSIGNMENT(s.process_nested_nodes, false);
-
-                // Copy entire array out of struct into local temp var
-                // e.g. var tint_symbol_1 = *(tint_symbol);
-                auto tmp_var = b.Sym();
-                s.insert_before_stmts.Push(b.Decl(b.Var(tmp_var, b.Deref(mem_access_ptr))));
-
-                // Replace input index_access with a clone of itself, but with its
-                // .object replaced by the new temp var. This is returned from this
-                // function to modify the original assignment statement. e.g.
-                // tint_symbol_1[uniforms.i]
-                auto* new_index_access = b.IndexAccessor(tmp_var, ctx.Clone(index_access->index));
-
-                // Assign temp var back to array
-                // e.g. *(tint_symbol) = tint_symbol_1;
-                auto* assign_rhs_to_temp = b.Assign(b.Deref(mem_access_ptr), tmp_var);
-                {
-                    utils::Vector<const ast::Statement*, 8> stmts{assign_rhs_to_temp};
-                    for (auto* stmt : s.insert_after_stmts) {
-                        stmts.Push(stmt);
-                    }
-                    s.insert_after_stmts = std::move(stmts);
-                }
-
-                return new_index_access;
-            });
+            return new_index_access;
+        });
 
         ctx.Clone();
         return Program(std::move(b));
@@ -160,24 +159,23 @@
 
     /// Returns true if `expr` contains an index accessor expression to a
     /// structure member of array type.
-    bool ContainsStructArrayIndex(const ast::Expression* expr) {
+    bool ContainsStructArrayIndex(const Expression* expr) {
         bool result = false;
-        ast::TraverseExpressions(
-            expr, b.Diagnostics(), [&](const ast::IndexAccessorExpression* ia) {
-                // Indexing using a runtime value?
-                auto* idx_sem = src->Sem().GetVal(ia->index);
-                if (!idx_sem->ConstantValue()) {
-                    // Indexing a member access expr?
-                    if (auto* ma = ia->object->As<ast::MemberAccessorExpression>()) {
-                        // That accesses an array?
-                        if (src->TypeOf(ma)->UnwrapRef()->Is<type::Array>()) {
-                            result = true;
-                            return ast::TraverseAction::Stop;
-                        }
+        TraverseExpressions(expr, b.Diagnostics(), [&](const IndexAccessorExpression* ia) {
+            // Indexing using a runtime value?
+            auto* idx_sem = src->Sem().GetVal(ia->index);
+            if (!idx_sem->ConstantValue()) {
+                // Indexing a member access expr?
+                if (auto* ma = ia->object->As<MemberAccessorExpression>()) {
+                    // That accesses an array?
+                    if (src->TypeOf(ma)->UnwrapRef()->Is<type::Array>()) {
+                        result = true;
+                        return TraverseAction::Stop;
                     }
                 }
-                return ast::TraverseAction::Descend;
-            });
+            }
+            return TraverseAction::Descend;
+        });
 
         return result;
     }
@@ -186,7 +184,7 @@
     // of the assignment statement.
     // See https://www.w3.org/TR/WGSL/#originating-variable-section
     std::pair<const type::Type*, builtin::AddressSpace> GetOriginatingTypeAndAddressSpace(
-        const ast::AssignmentStatement* assign_stmt) {
+        const AssignmentStatement* assign_stmt) {
         auto* root_ident = src->Sem().GetVal(assign_stmt->lhs)->RootIdentifier();
         if (TINT_UNLIKELY(!root_ident)) {
             TINT_ICE(Transform, b.Diagnostics())
@@ -222,4 +220,4 @@
     return State{src}.Run();
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/localize_struct_array_assignment.h b/src/tint/ast/transform/localize_struct_array_assignment.h
similarity index 82%
rename from src/tint/transform/localize_struct_array_assignment.h
rename to src/tint/ast/transform/localize_struct_array_assignment.h
index 8173fa8..5770e9f 100644
--- a/src/tint/transform/localize_struct_array_assignment.h
+++ b/src/tint/ast/transform/localize_struct_array_assignment.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_LOCALIZE_STRUCT_ARRAY_ASSIGNMENT_H_
-#define SRC_TINT_TRANSFORM_LOCALIZE_STRUCT_ARRAY_ASSIGNMENT_H_
+#ifndef SRC_TINT_AST_TRANSFORM_LOCALIZE_STRUCT_ARRAY_ASSIGNMENT_H_
+#define SRC_TINT_AST_TRANSFORM_LOCALIZE_STRUCT_ARRAY_ASSIGNMENT_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// This transforms replaces assignment to dynamically-indexed fixed-size arrays
 /// in structs on shader-local variables with code that copies the arrays to a
@@ -45,6 +45,6 @@
     struct State;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_LOCALIZE_STRUCT_ARRAY_ASSIGNMENT_H_
+#endif  // SRC_TINT_AST_TRANSFORM_LOCALIZE_STRUCT_ARRAY_ASSIGNMENT_H_
diff --git a/src/tint/transform/localize_struct_array_assignment_test.cc b/src/tint/ast/transform/localize_struct_array_assignment_test.cc
similarity index 97%
rename from src/tint/transform/localize_struct_array_assignment_test.cc
rename to src/tint/ast/transform/localize_struct_array_assignment_test.cc
index 9fabd95..85bbfed 100644
--- a/src/tint/transform/localize_struct_array_assignment_test.cc
+++ b/src/tint/ast/transform/localize_struct_array_assignment_test.cc
@@ -12,13 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/localize_struct_array_assignment.h"
-#include "src/tint/transform/simplify_pointers.h"
-#include "src/tint/transform/unshadow.h"
+#include "src/tint/ast/transform/localize_struct_array_assignment.h"
+#include "src/tint/ast/transform/simplify_pointers.h"
+#include "src/tint/ast/transform/unshadow.h"
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using LocalizeStructArrayAssignmentTest = TransformTest;
@@ -844,4 +844,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/merge_return.cc b/src/tint/ast/transform/merge_return.cc
similarity index 84%
rename from src/tint/transform/merge_return.cc
rename to src/tint/ast/transform/merge_return.cc
index f9f2feb..aa5d26a 100644
--- a/src/tint/transform/merge_return.cc
+++ b/src/tint/ast/transform/merge_return.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/merge_return.h"
+#include "src/tint/ast/transform/merge_return.h"
 
 #include <utility>
 
@@ -21,21 +21,21 @@
 #include "src/tint/switch.h"
 #include "src/tint/utils/scoped_assignment.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::MergeReturn);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::MergeReturn);
 
 using namespace tint::number_suffixes;  // NOLINT
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 namespace {
 
 /// Returns `true` if `stmt` has the behavior `behavior`.
-bool HasBehavior(const Program* program, const ast::Statement* stmt, sem::Behavior behavior) {
+bool HasBehavior(const Program* program, const Statement* stmt, sem::Behavior behavior) {
     return program->Sem().Get(stmt)->Behaviors().Contains(behavior);
 }
 
 /// Returns `true` if `func` needs to be transformed.
-bool NeedsTransform(const Program* program, const ast::Function* func) {
+bool NeedsTransform(const Program* program, const Function* func) {
     // Entry points and intrinsic declarations never need transforming.
     if (func->IsEntryPoint() || func->body == nullptr) {
         return false;
@@ -49,7 +49,7 @@
         if (HasBehavior(program, s, sem::Behavior::kReturn)) {
             // If this statement is itself a return, it will be the only exit point,
             // so no need to apply the transform to the function.
-            if (s->Is<ast::ReturnStatement>()) {
+            if (s->Is<ReturnStatement>()) {
                 return false;
             } else {
                 // Apply the transform in all other cases.
@@ -78,7 +78,7 @@
     ProgramBuilder& b;
 
     /// The function.
-    const ast::Function* function;
+    const Function* function;
 
     /// The symbol for the return flag variable.
     Symbol flag;
@@ -92,32 +92,32 @@
   public:
     /// Constructor
     /// @param context the clone context
-    State(CloneContext& context, const ast::Function* func)
+    State(CloneContext& context, const Function* func)
         : ctx(context), b(*ctx.dst), function(func) {}
 
     /// Process a statement (recursively).
-    void ProcessStatement(const ast::Statement* stmt) {
+    void ProcessStatement(const Statement* stmt) {
         if (stmt == nullptr || !HasBehavior(ctx.src, stmt, sem::Behavior::kReturn)) {
             return;
         }
 
         Switch(
-            stmt, [&](const ast::BlockStatement* block) { ProcessBlock(block); },
-            [&](const ast::CaseStatement* c) { ProcessStatement(c->body); },
-            [&](const ast::ForLoopStatement* f) {
+            stmt, [&](const BlockStatement* block) { ProcessBlock(block); },
+            [&](const CaseStatement* c) { ProcessStatement(c->body); },
+            [&](const ForLoopStatement* f) {
                 TINT_SCOPED_ASSIGNMENT(is_in_loop_or_switch, true);
                 ProcessStatement(f->body);
             },
-            [&](const ast::IfStatement* i) {
+            [&](const IfStatement* i) {
                 ProcessStatement(i->body);
                 ProcessStatement(i->else_statement);
             },
-            [&](const ast::LoopStatement* l) {
+            [&](const LoopStatement* l) {
                 TINT_SCOPED_ASSIGNMENT(is_in_loop_or_switch, true);
                 ProcessStatement(l->body);
             },
-            [&](const ast::ReturnStatement* r) {
-                utils::Vector<const ast::Statement*, 3> stmts;
+            [&](const ReturnStatement* r) {
+                utils::Vector<const Statement*, 3> stmts;
                 // Set the return flag to signal that we have hit a return.
                 stmts.Push(b.Assign(b.Expr(flag), true));
                 if (r->value) {
@@ -130,25 +130,25 @@
                 }
                 ctx.Replace(r, b.Block(std::move(stmts)));
             },
-            [&](const ast::SwitchStatement* s) {
+            [&](const SwitchStatement* s) {
                 TINT_SCOPED_ASSIGNMENT(is_in_loop_or_switch, true);
                 for (auto* c : s->body) {
                     ProcessStatement(c);
                 }
             },
-            [&](const ast::WhileStatement* w) {
+            [&](const WhileStatement* w) {
                 TINT_SCOPED_ASSIGNMENT(is_in_loop_or_switch, true);
                 ProcessStatement(w->body);
             },
             [&](Default) { TINT_ICE(Transform, b.Diagnostics()) << "unhandled statement type"; });
     }
 
-    void ProcessBlock(const ast::BlockStatement* block) {
+    void ProcessBlock(const BlockStatement* block) {
         // We will rebuild the contents of the block statement.
         // We may introduce conditionals around statements that follow a statement with the
         // `Return` behavior, so build a stack of statement lists that represent the new
         // (potentially nested) conditional blocks.
-        utils::Vector<utils::Vector<const ast::Statement*, 8>, 8> new_stmts({{}});
+        utils::Vector<utils::Vector<const Statement*, 8>, 8> new_stmts({{}});
 
         // Insert variables for the return flag and return value at the top of the function.
         if (block == function->body) {
@@ -173,8 +173,7 @@
                 if (is_in_loop_or_switch) {
                     // We're in a loop/switch, and so we would have inserted a `break`.
                     // If we've just come out of a loop/switch statement, we need to `break` again.
-                    if (s->IsAnyOf<ast::LoopStatement, ast::ForLoopStatement,
-                                   ast::SwitchStatement>()) {
+                    if (s->IsAnyOf<LoopStatement, ForLoopStatement, SwitchStatement>()) {
                         // If the loop only has the 'Return' behavior, we can just unconditionally
                         // break. Otherwise check the return flag.
                         if (HasBehavior(ctx.src, s, sem::Behavior::kNext)) {
@@ -194,7 +193,7 @@
 
         // Descend the stack of new block statements, wrapping them in conditionals.
         while (new_stmts.Length() > 1) {
-            const ast::IfStatement* i = nullptr;
+            const IfStatement* i = nullptr;
             if (new_stmts.Back().Length() > 0) {
                 i = b.If(b.Not(b.Expr(flag)), b.Block(new_stmts.Back()));
             }
@@ -239,4 +238,4 @@
     return Program(std::move(b));
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/merge_return.h b/src/tint/ast/transform/merge_return.h
similarity index 79%
rename from src/tint/transform/merge_return.h
rename to src/tint/ast/transform/merge_return.h
index fa9654b..4b11098 100644
--- a/src/tint/transform/merge_return.h
+++ b/src/tint/ast/transform/merge_return.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_MERGE_RETURN_H_
-#define SRC_TINT_TRANSFORM_MERGE_RETURN_H_
+#ifndef SRC_TINT_AST_TRANSFORM_MERGE_RETURN_H_
+#define SRC_TINT_AST_TRANSFORM_MERGE_RETURN_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// Merge return statements into a single return at the end of the function.
 class MergeReturn final : public utils::Castable<MergeReturn, Transform> {
@@ -33,6 +33,6 @@
                       DataMap& outputs) const override;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_MERGE_RETURN_H_
+#endif  // SRC_TINT_AST_TRANSFORM_MERGE_RETURN_H_
diff --git a/src/tint/transform/merge_return_test.cc b/src/tint/ast/transform/merge_return_test.cc
similarity index 98%
rename from src/tint/transform/merge_return_test.cc
rename to src/tint/ast/transform/merge_return_test.cc
index 02a565c..b7ec516 100644
--- a/src/tint/transform/merge_return_test.cc
+++ b/src/tint/ast/transform/merge_return_test.cc
@@ -12,13 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/merge_return.h"
+#include "src/tint/ast/transform/merge_return.h"
 
 #include <utility>
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using MergeReturnTest = TransformTest;
@@ -857,4 +857,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/module_scope_var_to_entry_point_param.cc b/src/tint/ast/transform/module_scope_var_to_entry_point_param.cc
similarity index 89%
rename from src/tint/transform/module_scope_var_to_entry_point_param.cc
rename to src/tint/ast/transform/module_scope_var_to_entry_point_param.cc
index 14e16bb..16257ba 100644
--- a/src/tint/transform/module_scope_var_to_entry_point_param.cc
+++ b/src/tint/ast/transform/module_scope_var_to_entry_point_param.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/module_scope_var_to_entry_point_param.h"
+#include "src/tint/ast/transform/module_scope_var_to_entry_point_param.h"
 
 #include <unordered_map>
 #include <unordered_set>
@@ -28,19 +28,19 @@
 #include "src/tint/sem/variable.h"
 #include "src/tint/utils/string.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::ModuleScopeVarToEntryPointParam);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::ModuleScopeVarToEntryPointParam);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
-using StructMemberList = utils::Vector<const ast::StructMember*, 8>;
+using StructMemberList = utils::Vector<const StructMember*, 8>;
 
 // The name of the struct member for arrays that are wrapped in structures.
 const char* kWrappedArrayMemberName = "arr";
 
 bool ShouldRun(const Program* program) {
     for (auto* decl : program->AST().GlobalDeclarations()) {
-        if (decl->Is<ast::Variable>()) {
+        if (decl->Is<Variable>()) {
             return true;
         }
     }
@@ -110,7 +110,7 @@
     /// @param workgroup_parameter_members reference to a list of a workgroup struct members
     /// @param is_pointer output signalling whether the replacement is a pointer
     /// @param is_wrapped output signalling whether the replacement is wrapped in a struct
-    void ProcessVariableInEntryPoint(const ast::Function* func,
+    void ProcessVariableInEntryPoint(const Function* func,
                                      const sem::Variable* var,
                                      Symbol new_var_symbol,
                                      std::function<Symbol()> workgroup_param,
@@ -128,7 +128,7 @@
                 // For a texture or sampler variable, redeclare it as an entry point parameter.
                 // Disable entry point parameter validation.
                 auto* disable_validation =
-                    ctx.dst->Disable(ast::DisabledValidation::kEntryPointParameter);
+                    ctx.dst->Disable(DisabledValidation::kEntryPointParameter);
                 auto attrs = ctx.Clone(var->Declaration()->attributes);
                 attrs.Push(disable_validation);
                 auto* param = ctx.dst->Param(new_var_symbol, store_type(), attrs);
@@ -141,8 +141,8 @@
                 // Variables into the Storage and Uniform address spaces are redeclared as entry
                 // point parameters with a pointer type.
                 auto attributes = ctx.Clone(var->Declaration()->attributes);
-                attributes.Push(ctx.dst->Disable(ast::DisabledValidation::kEntryPointParameter));
-                attributes.Push(ctx.dst->Disable(ast::DisabledValidation::kIgnoreAddressSpace));
+                attributes.Push(ctx.dst->Disable(DisabledValidation::kEntryPointParameter));
+                attributes.Push(ctx.dst->Disable(DisabledValidation::kIgnoreAddressSpace));
 
                 auto param_type = store_type();
                 if (auto* arr = ty->As<type::Array>();
@@ -190,7 +190,7 @@
                     is_pointer = true;
                 } else {
                     auto* disable_validation =
-                        ctx.dst->Disable(ast::DisabledValidation::kIgnoreAddressSpace);
+                        ctx.dst->Disable(DisabledValidation::kIgnoreAddressSpace);
                     auto* initializer = ctx.Clone(var->Declaration()->initializer);
                     auto* local_var = ctx.dst->Var(new_var_symbol, store_type(), sc, initializer,
                                                    utils::Vector{disable_validation});
@@ -218,7 +218,7 @@
     /// @param var the variable
     /// @param new_var_symbol the symbol to use for the replacement
     /// @param is_pointer output signalling whether the replacement is a pointer or not
-    void ProcessVariableInUserFunction(const ast::Function* func,
+    void ProcessVariableInUserFunction(const Function* func,
                                        const sem::Variable* var,
                                        Symbol new_var_symbol,
                                        bool& is_pointer) {
@@ -247,7 +247,7 @@
         }
 
         // Use a pointer for non-handle types.
-        utils::Vector<const ast::Attribute*, 2> attributes;
+        utils::Vector<const Attribute*, 2> attributes;
         if (!ty->is_handle()) {
             param_type = sc == builtin::AddressSpace::kStorage
                              ? ctx.dst->ty.pointer(param_type, sc, var->Access())
@@ -255,9 +255,8 @@
             is_pointer = true;
 
             // Disable validation of the parameter's address space and of arguments passed to it.
-            attributes.Push(ctx.dst->Disable(ast::DisabledValidation::kIgnoreAddressSpace));
-            attributes.Push(
-                ctx.dst->Disable(ast::DisabledValidation::kIgnoreInvalidPointerArgument));
+            attributes.Push(ctx.dst->Disable(DisabledValidation::kIgnoreAddressSpace));
+            attributes.Push(ctx.dst->Disable(DisabledValidation::kIgnoreInvalidPointerArgument));
         }
 
         // Redeclare the variable as a parameter.
@@ -271,18 +270,18 @@
     /// @param new_var the symbol to use for replacement
     /// @param is_pointer true if `new_var` is a pointer to the new variable
     /// @param member_name if valid, the name of the struct member that holds this variable
-    void ReplaceUsesInFunction(const ast::Function* func,
+    void ReplaceUsesInFunction(const Function* func,
                                const sem::Variable* var,
                                Symbol new_var,
                                bool is_pointer,
                                Symbol member_name) {
         for (auto* user : var->Users()) {
             if (user->Stmt()->Function()->Declaration() == func) {
-                const ast::Expression* expr = ctx.dst->Expr(new_var);
+                const Expression* expr = ctx.dst->Expr(new_var);
                 if (is_pointer) {
                     // If this identifier is used by an address-of operator, just remove the
                     // address-of instead of adding a deref, since we already have a pointer.
-                    auto* ident = user->Declaration()->As<ast::IdentifierExpression>();
+                    auto* ident = user->Declaration()->As<IdentifierExpression>();
                     if (ident_to_address_of_.count(ident) && !member_name.IsValid()) {
                         ctx.Replace(ident_to_address_of_[ident], expr);
                         continue;
@@ -302,19 +301,19 @@
     /// Process the module.
     void Process() {
         // Predetermine the list of function calls that need to be replaced.
-        using CallList = utils::Vector<const ast::CallExpression*, 8>;
-        std::unordered_map<const ast::Function*, CallList> calls_to_replace;
+        using CallList = utils::Vector<const CallExpression*, 8>;
+        std::unordered_map<const Function*, CallList> calls_to_replace;
 
-        utils::Vector<const ast::Function*, 8> functions_to_process;
+        utils::Vector<const Function*, 8> functions_to_process;
 
         // Collect private variables into a single structure.
         StructMemberList private_struct_members;
-        utils::Vector<std::function<const ast::AssignmentStatement*()>, 4> private_initializers;
-        std::unordered_set<const ast::Function*> uses_privates;
+        utils::Vector<std::function<const AssignmentStatement*()>, 4> private_initializers;
+        std::unordered_set<const Function*> uses_privates;
 
         // Build a list of functions that transitively reference any module-scope variables.
         for (auto* decl : ctx.src->Sem().Module()->DependencyOrderedDeclarations()) {
-            if (auto* var = decl->As<ast::Var>()) {
+            if (auto* var = decl->As<Var>()) {
                 auto* sem_var = ctx.src->Sem().Get(var);
                 if (sem_var->AddressSpace() == builtin::AddressSpace::kPrivate) {
                     // Create a member in the private variable struct.
@@ -335,7 +334,7 @@
                 continue;
             }
 
-            auto* func_ast = decl->As<ast::Function>();
+            auto* func_ast = decl->As<Function>();
             if (!func_ast) {
                 continue;
             }
@@ -376,11 +375,11 @@
         // TODO(jrprice): We should add support for bidirectional SEM tree traversal so that we can
         // do this on the fly instead.
         for (auto* node : ctx.src->ASTNodes().Objects()) {
-            auto* address_of = node->As<ast::UnaryOpExpression>();
-            if (!address_of || address_of->op != ast::UnaryOp::kAddressOf) {
+            auto* address_of = node->As<UnaryOpExpression>();
+            if (!address_of || address_of->op != UnaryOp::kAddressOf) {
                 continue;
             }
-            if (auto* ident = address_of->expr->As<ast::IdentifierExpression>()) {
+            if (auto* ident = address_of->expr->As<IdentifierExpression>()) {
                 ident_to_address_of_[ident] = address_of;
             }
         }
@@ -414,12 +413,12 @@
             if (uses_privates.count(func_ast)) {
                 if (is_entry_point) {
                     // Create a local declaration for the private variable struct.
-                    auto* var = ctx.dst->Var(
-                        PrivateStructVariableName(), ctx.dst->ty(PrivateStructName()),
-                        builtin::AddressSpace::kPrivate,
-                        utils::Vector{
-                            ctx.dst->Disable(ast::DisabledValidation::kIgnoreAddressSpace),
-                        });
+                    auto* var =
+                        ctx.dst->Var(PrivateStructVariableName(), ctx.dst->ty(PrivateStructName()),
+                                     builtin::AddressSpace::kPrivate,
+                                     utils::Vector{
+                                         ctx.dst->Disable(DisabledValidation::kIgnoreAddressSpace),
+                                     });
                     ctx.InsertFront(func_ast->body->statements, ctx.dst->Decl(var));
 
                     // Initialize the members of that struct with the original initializers.
@@ -482,7 +481,7 @@
             // Allow pointer aliasing if needed.
             if (needs_pointer_aliasing) {
                 ctx.InsertBack(func_ast->attributes,
-                               ctx.dst->Disable(ast::DisabledValidation::kIgnorePointerAliasing));
+                               ctx.dst->Disable(DisabledValidation::kIgnorePointerAliasing));
             }
 
             if (!workgroup_parameter_members.IsEmpty()) {
@@ -492,12 +491,12 @@
                     ctx.dst->Structure(ctx.dst->Sym(), std::move(workgroup_parameter_members));
                 auto param_type =
                     ctx.dst->ty.pointer(ctx.dst->ty.Of(str), builtin::AddressSpace::kWorkgroup);
-                auto* param = ctx.dst->Param(
-                    workgroup_param(), param_type,
-                    utils::Vector{
-                        ctx.dst->Disable(ast::DisabledValidation::kEntryPointParameter),
-                        ctx.dst->Disable(ast::DisabledValidation::kIgnoreAddressSpace),
-                    });
+                auto* param =
+                    ctx.dst->Param(workgroup_param(), param_type,
+                                   utils::Vector{
+                                       ctx.dst->Disable(DisabledValidation::kEntryPointParameter),
+                                       ctx.dst->Disable(DisabledValidation::kIgnoreAddressSpace),
+                                   });
                 ctx.InsertFront(func_ast->params, param);
             }
 
@@ -508,7 +507,7 @@
 
                 // Pass the private variable struct pointer if needed.
                 if (uses_privates.count(target_sem->Declaration())) {
-                    const ast::Expression* arg = ctx.dst->Expr(PrivateStructVariableName());
+                    const Expression* arg = ctx.dst->Expr(PrivateStructVariableName());
                     if (is_entry_point) {
                         arg = ctx.dst->AddressOf(arg);
                     }
@@ -531,7 +530,7 @@
 
                     auto new_var = it->second;
                     bool is_handle = target_var->Type()->UnwrapRef()->is_handle();
-                    const ast::Expression* arg = ctx.dst->Expr(new_var.symbol);
+                    const Expression* arg = ctx.dst->Expr(new_var.symbol);
                     if (new_var.is_wrapped) {
                         // The variable is wrapped in a struct, so we need to pass a pointer to the
                         // struct member instead.
@@ -577,8 +576,7 @@
     std::unordered_set<const sem::Struct*> cloned_structs_;
 
     // Map from identifier expression to the address-of expression that uses it.
-    std::unordered_map<const ast::IdentifierExpression*, const ast::UnaryOpExpression*>
-        ident_to_address_of_;
+    std::unordered_map<const IdentifierExpression*, const UnaryOpExpression*> ident_to_address_of_;
 
     // The name of the structure that contains all the module-scope private variables.
     Symbol private_struct_name;
@@ -607,4 +605,4 @@
     return Program(std::move(b));
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/module_scope_var_to_entry_point_param.h b/src/tint/ast/transform/module_scope_var_to_entry_point_param.h
similarity index 86%
rename from src/tint/transform/module_scope_var_to_entry_point_param.h
rename to src/tint/ast/transform/module_scope_var_to_entry_point_param.h
index 4f4f562..258c24c 100644
--- a/src/tint/transform/module_scope_var_to_entry_point_param.h
+++ b/src/tint/ast/transform/module_scope_var_to_entry_point_param.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_MODULE_SCOPE_VAR_TO_ENTRY_POINT_PARAM_H_
-#define SRC_TINT_TRANSFORM_MODULE_SCOPE_VAR_TO_ENTRY_POINT_PARAM_H_
+#ifndef SRC_TINT_AST_TRANSFORM_MODULE_SCOPE_VAR_TO_ENTRY_POINT_PARAM_H_
+#define SRC_TINT_AST_TRANSFORM_MODULE_SCOPE_VAR_TO_ENTRY_POINT_PARAM_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// Move module-scope variables into the entry point as parameters.
 ///
@@ -78,6 +78,6 @@
     struct State;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_MODULE_SCOPE_VAR_TO_ENTRY_POINT_PARAM_H_
+#endif  // SRC_TINT_AST_TRANSFORM_MODULE_SCOPE_VAR_TO_ENTRY_POINT_PARAM_H_
diff --git a/src/tint/transform/module_scope_var_to_entry_point_param_test.cc b/src/tint/ast/transform/module_scope_var_to_entry_point_param_test.cc
similarity index 99%
rename from src/tint/transform/module_scope_var_to_entry_point_param_test.cc
rename to src/tint/ast/transform/module_scope_var_to_entry_point_param_test.cc
index 5991a1a..eb7f048 100644
--- a/src/tint/transform/module_scope_var_to_entry_point_param_test.cc
+++ b/src/tint/ast/transform/module_scope_var_to_entry_point_param_test.cc
@@ -12,13 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/module_scope_var_to_entry_point_param.h"
+#include "src/tint/ast/transform/module_scope_var_to_entry_point_param.h"
 
 #include <utility>
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using ModuleScopeVarToEntryPointParamTest = TransformTest;
@@ -1369,4 +1369,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/multiplanar_external_texture.cc b/src/tint/ast/transform/multiplanar_external_texture.cc
similarity index 95%
rename from src/tint/transform/multiplanar_external_texture.cc
rename to src/tint/ast/transform/multiplanar_external_texture.cc
index 2105781..87844f8 100644
--- a/src/tint/transform/multiplanar_external_texture.cc
+++ b/src/tint/ast/transform/multiplanar_external_texture.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/multiplanar_external_texture.h"
+#include "src/tint/ast/transform/multiplanar_external_texture.h"
 
 #include <string>
 #include <vector>
@@ -24,12 +24,12 @@
 #include "src/tint/sem/variable.h"
 #include "src/tint/type/texture_dimension.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::MultiplanarExternalTexture);
-TINT_INSTANTIATE_TYPEINFO(tint::transform::MultiplanarExternalTexture::NewBindingPoints);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::MultiplanarExternalTexture);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::MultiplanarExternalTexture::NewBindingPoints);
 
 using namespace tint::number_suffixes;  // NOLINT
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 bool ShouldRun(const Program* program) {
@@ -143,7 +143,7 @@
 
             // Replace the original texture_external binding with a texture_2d<f32> binding.
             auto cloned_attributes = ctx.Clone(global->attributes);
-            const ast::Expression* cloned_initializer = ctx.Clone(global->initializer);
+            const Expression* cloned_initializer = ctx.Clone(global->initializer);
 
             auto* replacement =
                 b.Var(syms.plane_0, b.ty.sampled_texture(type::TextureDimension::k2d, b.ty.f32()),
@@ -153,7 +153,7 @@
 
         // We must update all the texture_external parameters for user declared functions.
         for (auto* fn : ctx.src->AST().Functions()) {
-            for (const ast::Variable* param : fn->params) {
+            for (const Variable* param : fn->params) {
                 if (auto* sem_var = sem.Get(param)) {
                     if (!sem_var->Type()->UnwrapRef()->Is<type::ExternalTexture>()) {
                         continue;
@@ -184,7 +184,7 @@
 
         // Transform the external texture builtin calls into calls to the external texture
         // functions.
-        ctx.ReplaceAll([&](const ast::CallExpression* expr) -> const ast::CallExpression* {
+        ctx.ReplaceAll([&](const CallExpression* expr) -> const CallExpression* {
             auto* call = sem.Get(expr)->UnwrapMaterialize()->As<sem::Call>();
             auto* builtin = call->Target()->As<sem::Builtin>();
 
@@ -305,10 +305,10 @@
     /// @param call_type determines which function body to generate
     /// @returns a statement list that makes of the body of the chosen function
     auto buildTextureBuiltinBody(builtin::Function call_type) {
-        utils::Vector<const ast::Statement*, 16> stmts;
-        const ast::CallExpression* single_plane_call = nullptr;
-        const ast::CallExpression* plane_0_call = nullptr;
-        const ast::CallExpression* plane_1_call = nullptr;
+        utils::Vector<const Statement*, 16> stmts;
+        const CallExpression* single_plane_call = nullptr;
+        const CallExpression* plane_0_call = nullptr;
+        const CallExpression* plane_1_call = nullptr;
         switch (call_type) {
             case builtin::Function::kTextureSampleBaseClampToEdge:
                 stmts.Push(b.Decl(b.Let(
@@ -395,9 +395,9 @@
     /// @param expr the call expression being transformed
     /// @param syms the expanded symbols to be used in the new call
     /// @returns a call expression to textureSampleExternal
-    const ast::CallExpression* createTextureSampleBaseClampToEdge(const ast::CallExpression* expr,
-                                                                  NewBindingSymbols syms) {
-        const ast::Expression* plane_0_binding_param = ctx.Clone(expr->args[0]);
+    const CallExpression* createTextureSampleBaseClampToEdge(const CallExpression* expr,
+                                                             NewBindingSymbols syms) {
+        const Expression* plane_0_binding_param = ctx.Clone(expr->args[0]);
 
         if (TINT_UNLIKELY(expr->args.Length() != 3)) {
             TINT_ICE(Transform, b.Diagnostics())
@@ -443,7 +443,7 @@
     /// @param call the call expression being transformed
     /// @param syms the expanded symbols to be used in the new call
     /// @returns a call expression to textureLoadExternal
-    const ast::CallExpression* createTextureLoad(const sem::Call* call, NewBindingSymbols syms) {
+    const CallExpression* createTextureLoad(const sem::Call* call, NewBindingSymbols syms) {
         if (TINT_UNLIKELY(call->Arguments().Length() != 2)) {
             TINT_ICE(Transform, b.Diagnostics())
                 << "expected textureLoad call with a texture_external to have 2 arguments, found "
@@ -524,4 +524,4 @@
     return Program(std::move(b));
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/multiplanar_external_texture.h b/src/tint/ast/transform/multiplanar_external_texture.h
similarity index 88%
rename from src/tint/transform/multiplanar_external_texture.h
rename to src/tint/ast/transform/multiplanar_external_texture.h
index c47c345..69fc21e 100644
--- a/src/tint/transform/multiplanar_external_texture.h
+++ b/src/tint/ast/transform/multiplanar_external_texture.h
@@ -12,19 +12,19 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_MULTIPLANAR_EXTERNAL_TEXTURE_H_
-#define SRC_TINT_TRANSFORM_MULTIPLANAR_EXTERNAL_TEXTURE_H_
+#ifndef SRC_TINT_AST_TRANSFORM_MULTIPLANAR_EXTERNAL_TEXTURE_H_
+#define SRC_TINT_AST_TRANSFORM_MULTIPLANAR_EXTERNAL_TEXTURE_H_
 
 #include <unordered_map>
 #include <utility>
 
 #include "src/tint/ast/struct_member.h"
+#include "src/tint/ast/transform/transform.h"
 #include "src/tint/builtin/function.h"
 #include "src/tint/sem/binding_point.h"
 #include "src/tint/sem/external_texture.h"
-#include "src/tint/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// Within the MultiplanarExternalTexture transform, each instance of a
 /// texture_external binding is unpacked into two texture_2d<f32> bindings
@@ -52,7 +52,7 @@
     /// NewBindingPoints is consumed by the MultiplanarExternalTexture transform.
     /// Data holds information about location of each texture_external binding and
     /// which binding slots it should expand into.
-    struct NewBindingPoints final : public utils::Castable<Data, transform::Data> {
+    struct NewBindingPoints final : public utils::Castable<NewBindingPoints, Data> {
         /// Constructor
         /// @param bm a map to the new binding slots to use.
         explicit NewBindingPoints(BindingsMap bm);
@@ -78,6 +78,6 @@
     struct State;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_MULTIPLANAR_EXTERNAL_TEXTURE_H_
+#endif  // SRC_TINT_AST_TRANSFORM_MULTIPLANAR_EXTERNAL_TEXTURE_H_
diff --git a/src/tint/transform/multiplanar_external_texture_test.cc b/src/tint/ast/transform/multiplanar_external_texture_test.cc
similarity index 99%
rename from src/tint/transform/multiplanar_external_texture_test.cc
rename to src/tint/ast/transform/multiplanar_external_texture_test.cc
index 916d56b..25c7765 100644
--- a/src/tint/transform/multiplanar_external_texture_test.cc
+++ b/src/tint/ast/transform/multiplanar_external_texture_test.cc
@@ -12,10 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/multiplanar_external_texture.h"
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/multiplanar_external_texture.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using MultiplanarExternalTextureTest = TransformTest;
@@ -77,7 +77,8 @@
 }
 )";
     auto* expect =
-        R"(error: missing new binding point data for tint::transform::MultiplanarExternalTexture)";
+        "error: missing new binding point data for "
+        "tint::ast::transform::MultiplanarExternalTexture";
 
     auto got = Run<MultiplanarExternalTexture>(src);
     EXPECT_EQ(expect, str(got));
@@ -1812,4 +1813,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/num_workgroups_from_uniform.cc b/src/tint/ast/transform/num_workgroups_from_uniform.cc
similarity index 91%
rename from src/tint/transform/num_workgroups_from_uniform.cc
rename to src/tint/ast/transform/num_workgroups_from_uniform.cc
index 60e9a72..6f7daad 100644
--- a/src/tint/transform/num_workgroups_from_uniform.cc
+++ b/src/tint/ast/transform/num_workgroups_from_uniform.cc
@@ -12,28 +12,28 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/num_workgroups_from_uniform.h"
+#include "src/tint/ast/transform/num_workgroups_from_uniform.h"
 
 #include <memory>
 #include <string>
 #include <unordered_set>
 #include <utility>
 
+#include "src/tint/ast/transform/canonicalize_entry_point_io.h"
 #include "src/tint/builtin/builtin_value.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/function.h"
-#include "src/tint/transform/canonicalize_entry_point_io.h"
 #include "src/tint/utils/hash.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::NumWorkgroupsFromUniform);
-TINT_INSTANTIATE_TYPEINFO(tint::transform::NumWorkgroupsFromUniform::Config);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::NumWorkgroupsFromUniform);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::NumWorkgroupsFromUniform::Config);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 bool ShouldRun(const Program* program) {
     for (auto* node : program->ASTNodes().Objects()) {
-        if (auto* attr = node->As<ast::BuiltinAttribute>()) {
+        if (auto* attr = node->As<BuiltinAttribute>()) {
             if (program->Sem().Get(attr)->Value() == builtin::BuiltinValue::kNumWorkgroups) {
                 return true;
             }
@@ -86,7 +86,7 @@
     std::unordered_set<Accessor, Accessor::Hasher> to_replace;
     for (auto* func : src->AST().Functions()) {
         // num_workgroups is only valid for compute stages.
-        if (func->PipelineStage() != ast::PipelineStage::kCompute) {
+        if (func->PipelineStage() != PipelineStage::kCompute) {
             continue;
         }
 
@@ -126,7 +126,7 @@
 
     // Get (or create, on first call) the uniform buffer that will receive the
     // number of workgroups.
-    const ast::Variable* num_workgroups_ubo = nullptr;
+    const Variable* num_workgroups_ubo = nullptr;
     auto get_ubo = [&]() {
         if (!num_workgroups_ubo) {
             auto* num_workgroups_struct =
@@ -166,11 +166,11 @@
     // Now replace all the places where the builtins are accessed with the value
     // loaded from the uniform buffer.
     for (auto* node : src->ASTNodes().Objects()) {
-        auto* accessor = node->As<ast::MemberAccessorExpression>();
+        auto* accessor = node->As<MemberAccessorExpression>();
         if (!accessor) {
             continue;
         }
-        auto* ident = accessor->object->As<ast::IdentifierExpression>();
+        auto* ident = accessor->object->As<IdentifierExpression>();
         if (!ident) {
             continue;
         }
@@ -190,4 +190,4 @@
 NumWorkgroupsFromUniform::Config::Config(const Config&) = default;
 NumWorkgroupsFromUniform::Config::~Config() = default;
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/num_workgroups_from_uniform.h b/src/tint/ast/transform/num_workgroups_from_uniform.h
similarity index 87%
rename from src/tint/transform/num_workgroups_from_uniform.h
rename to src/tint/ast/transform/num_workgroups_from_uniform.h
index 049c1db..cecb03d 100644
--- a/src/tint/transform/num_workgroups_from_uniform.h
+++ b/src/tint/ast/transform/num_workgroups_from_uniform.h
@@ -12,20 +12,20 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_NUM_WORKGROUPS_FROM_UNIFORM_H_
-#define SRC_TINT_TRANSFORM_NUM_WORKGROUPS_FROM_UNIFORM_H_
+#ifndef SRC_TINT_AST_TRANSFORM_NUM_WORKGROUPS_FROM_UNIFORM_H_
+#define SRC_TINT_AST_TRANSFORM_NUM_WORKGROUPS_FROM_UNIFORM_H_
 
 #include <optional>
 
+#include "src/tint/ast/transform/transform.h"
 #include "src/tint/sem/binding_point.h"
-#include "src/tint/transform/transform.h"
 
 // Forward declarations
 namespace tint {
 class CloneContext;
 }  // namespace tint
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// NumWorkgroupsFromUniform is a transform that implements the `num_workgroups`
 /// builtin by loading it from a uniform buffer.
@@ -52,7 +52,7 @@
     ~NumWorkgroupsFromUniform() override;
 
     /// Configuration options for the NumWorkgroupsFromUniform transform.
-    struct Config final : public utils::Castable<Data, transform::Data> {
+    struct Config final : public utils::Castable<Config, Data> {
         /// Constructor
         /// @param ubo_bp the binding point to use for the generated uniform buffer. If ubo_bp
         /// contains no value, a free binding point will be used to ensure the generated program is
@@ -78,6 +78,6 @@
                       DataMap& outputs) const override;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_NUM_WORKGROUPS_FROM_UNIFORM_H_
+#endif  // SRC_TINT_AST_TRANSFORM_NUM_WORKGROUPS_FROM_UNIFORM_H_
diff --git a/src/tint/transform/num_workgroups_from_uniform_test.cc b/src/tint/ast/transform/num_workgroups_from_uniform_test.cc
similarity index 97%
rename from src/tint/transform/num_workgroups_from_uniform_test.cc
rename to src/tint/ast/transform/num_workgroups_from_uniform_test.cc
index 435ab33..b46f6ab 100644
--- a/src/tint/transform/num_workgroups_from_uniform_test.cc
+++ b/src/tint/ast/transform/num_workgroups_from_uniform_test.cc
@@ -12,15 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/num_workgroups_from_uniform.h"
+#include "src/tint/ast/transform/num_workgroups_from_uniform.h"
 
 #include <utility>
 
-#include "src/tint/transform/canonicalize_entry_point_io.h"
-#include "src/tint/transform/test_helper.h"
-#include "src/tint/transform/unshadow.h"
+#include "src/tint/ast/transform/canonicalize_entry_point_io.h"
+#include "src/tint/ast/transform/test_helper.h"
+#include "src/tint/ast/transform/unshadow.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using NumWorkgroupsFromUniformTest = TransformTest;
@@ -53,8 +53,7 @@
 )";
 
     auto* expect =
-        "error: missing transform data for "
-        "tint::transform::NumWorkgroupsFromUniform";
+        "error: missing transform data for tint::ast::transform::NumWorkgroupsFromUniform";
 
     DataMap data;
     data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
@@ -694,4 +693,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/packed_vec3.cc b/src/tint/ast/transform/packed_vec3.cc
similarity index 91%
rename from src/tint/transform/packed_vec3.cc
rename to src/tint/ast/transform/packed_vec3.cc
index 16d8af4..30f3e1c 100644
--- a/src/tint/transform/packed_vec3.cc
+++ b/src/tint/ast/transform/packed_vec3.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/packed_vec3.h"
+#include "src/tint/ast/transform/packed_vec3.h"
 
 #include <algorithm>
 #include <string>
@@ -35,11 +35,11 @@
 #include "src/tint/utils/hashset.h"
 #include "src/tint/utils/vector.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::PackedVec3);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::PackedVec3);
 
 using namespace tint::number_suffixes;  // NOLINT
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// PIMPL state for the transform
 struct PackedVec3::State {
@@ -94,7 +94,7 @@
     /// Create a `__packed_vec3` type with the same element type as `ty`.
     /// @param ty a three-element vector type
     /// @returns the new AST type
-    ast::Type MakePackedVec3(const type::Type* ty) {
+    Type MakePackedVec3(const type::Type* ty) {
         auto* vec = ty->As<type::Vector>();
         TINT_ASSERT(Transform, vec != nullptr && vec->Width() == 3);
         return b.ty(builtin::Builtin::kPackedVec3, CreateASTTypeFor(ctx, vec->type()));
@@ -109,10 +109,10 @@
     /// @param ty the type to rewrite
     /// @param array_element `true` if this is being called for the element of an array
     /// @returns the new AST type, or nullptr if rewriting was not necessary
-    ast::Type RewriteType(const type::Type* ty, bool array_element = false) {
+    Type RewriteType(const type::Type* ty, bool array_element = false) {
         return Switch(
             ty,
-            [&](const type::Vector* vec) -> ast::Type {
+            [&](const type::Vector* vec) -> Type {
                 if (IsVec3(vec)) {
                     if (array_element) {
                         // Create a struct with a single `__packed_vec3` member.
@@ -134,7 +134,7 @@
                 }
                 return {};
             },
-            [&](const type::Matrix* mat) -> ast::Type {
+            [&](const type::Matrix* mat) -> Type {
                 // Rewrite the matrix as an array of columns that use the aligned wrapper struct.
                 auto new_col_type = RewriteType(mat->ColumnType(), /* array_element */ true);
                 if (new_col_type) {
@@ -142,11 +142,11 @@
                 }
                 return {};
             },
-            [&](const type::Array* arr) -> ast::Type {
+            [&](const type::Array* arr) -> Type {
                 // Rewrite the array with the modified element type.
                 auto new_type = RewriteType(arr->ElemType(), /* array_element */ true);
                 if (new_type) {
-                    utils::Vector<const ast::Attribute*, 1> attrs;
+                    utils::Vector<const Attribute*, 1> attrs;
                     if (arr->Count()->Is<type::RuntimeArrayCount>()) {
                         return b.ty.array(new_type, std::move(attrs));
                     } else if (auto count = arr->ConstantCount()) {
@@ -159,21 +159,21 @@
                 }
                 return {};
             },
-            [&](const type::Struct* str) -> ast::Type {
+            [&](const type::Struct* str) -> Type {
                 if (ContainsVec3(str)) {
                     auto name = rewritten_structs.GetOrCreate(str, [&]() {
-                        utils::Vector<const ast::StructMember*, 4> members;
+                        utils::Vector<const StructMember*, 4> members;
                         for (auto* member : str->Members()) {
                             // If the member type contains a vec3, rewrite it.
                             auto new_type = RewriteType(member->Type());
                             if (new_type) {
                                 // Copy the member attributes.
                                 bool needs_align = true;
-                                utils::Vector<const ast::Attribute*, 4> attributes;
+                                utils::Vector<const Attribute*, 4> attributes;
                                 if (auto* sem_mem = member->As<sem::StructMember>()) {
                                     for (auto* attr : sem_mem->Declaration()->attributes) {
-                                        if (attr->IsAnyOf<ast::StructMemberAlignAttribute,
-                                                          ast::StructMemberOffsetAttribute>()) {
+                                        if (attr->IsAnyOf<StructMemberAlignAttribute,
+                                                          StructMemberOffsetAttribute>()) {
                                             needs_align = false;
                                         }
                                         attributes.Push(ctx.Clone(attr));
@@ -219,12 +219,12 @@
     Symbol MakePackUnpackHelper(
         const char* name_prefix,
         const type::Type* ty,
-        const std::function<const ast::Expression*(const ast::Expression*, const type::Type*)>&
+        const std::function<const Expression*(const Expression*, const type::Type*)>&
             pack_or_unpack_element,
-        const std::function<ast::Type()>& in_type,
-        const std::function<ast::Type()>& out_type) {
+        const std::function<Type()>& in_type,
+        const std::function<Type()>& out_type) {
         // Allocate a variable to hold the return value of the function.
-        utils::Vector<const ast::Statement*, 4> statements;
+        utils::Vector<const Statement*, 4> statements;
         statements.Push(b.Decl(b.Var("result", out_type())));
 
         // Helper that generates a loop to copy and pack/unpack elements of an array to the result:
@@ -256,7 +256,7 @@
             [&](const type::Struct* str) {
                 // Copy the struct members over one at a time, packing/unpacking as necessary.
                 for (auto* member : str->Members()) {
-                    const ast::Expression* element =
+                    const Expression* element =
                         b.MemberAccessor("in", b.Ident(ctx.Clone(member->Name())));
                     if (ContainsVec3(member->Type())) {
                         element = pack_or_unpack_element(element, member->Type());
@@ -280,16 +280,16 @@
     /// @param expr the composite value expression to unpack
     /// @param ty the unpacked type
     /// @returns an expression that holds the unpacked value
-    const ast::Expression* UnpackComposite(const ast::Expression* expr, const type::Type* ty) {
+    const Expression* UnpackComposite(const Expression* expr, const type::Type* ty) {
         auto helper = unpack_helpers.GetOrCreate(ty, [&]() {
             return MakePackUnpackHelper(
                 "tint_unpack_vec3_in_composite", ty,
-                [&](const ast::Expression* element,
-                    const type::Type* element_type) -> const ast::Expression* {
+                [&](const Expression* element,
+                    const type::Type* element_type) -> const Expression* {
                     if (element_type->Is<type::Vector>()) {
                         // Unpack a `__packed_vec3` by casting it to a regular vec3.
                         // If it is an array element, extract the vector from the wrapper struct.
-                        if (element->Is<ast::IndexAccessorExpression>()) {
+                        if (element->Is<IndexAccessorExpression>()) {
                             element = b.MemberAccessor(element, kStructMemberName);
                         }
                         return b.Call(CreateASTTypeFor(ctx, element_type), element);
@@ -308,17 +308,17 @@
     /// @param expr the composite value expression to pack
     /// @param ty the unpacked type
     /// @returns an expression that holds the packed value
-    const ast::Expression* PackComposite(const ast::Expression* expr, const type::Type* ty) {
+    const Expression* PackComposite(const Expression* expr, const type::Type* ty) {
         auto helper = pack_helpers.GetOrCreate(ty, [&]() {
             return MakePackUnpackHelper(
                 "tint_pack_vec3_in_composite", ty,
-                [&](const ast::Expression* element,
-                    const type::Type* element_type) -> const ast::Expression* {
+                [&](const Expression* element,
+                    const type::Type* element_type) -> const Expression* {
                     if (element_type->Is<type::Vector>()) {
                         // Pack a vector element by casting it to a packed_vec3.
                         // If it is an array element, construct a wrapper struct.
                         auto* packed = b.Call(MakePackedVec3(element_type), element);
-                        if (element->Is<ast::IndexAccessorExpression>()) {
+                        if (element->Is<IndexAccessorExpression>()) {
                             packed = b.Call(RewriteType(element_type, true), packed);
                         }
                         return packed;
@@ -400,7 +400,7 @@
                 },
                 [&](const sem::Statement* stmt) {
                     // Pack the RHS of assignment statements that are writing to packed types.
-                    if (auto* assign = stmt->Declaration()->As<ast::AssignmentStatement>()) {
+                    if (auto* assign = stmt->Declaration()->As<AssignmentStatement>()) {
                         auto* lhs = sem.GetVal(assign->lhs);
                         auto* rhs = sem.GetVal(assign->rhs);
                         if (!ContainsVec3(rhs->Type()) ||
@@ -463,7 +463,7 @@
         for (auto* expr : to_unpack_sorted) {
             TINT_ASSERT(Transform, ContainsVec3(expr->Type()));
             auto* packed = ctx.Clone(expr->Declaration());
-            const ast::Expression* unpacked = nullptr;
+            const Expression* unpacked = nullptr;
             if (IsVec3(expr->Type())) {
                 if (expr->UnwrapLoad()->Is<sem::IndexAccessorExpression>()) {
                     // If we are unpacking a vec3 from an array element, extract the vector from the
@@ -484,7 +484,7 @@
         for (auto* expr : to_pack_sorted) {
             TINT_ASSERT(Transform, ContainsVec3(expr->Type()));
             auto* unpacked = ctx.Clone(expr->Declaration());
-            const ast::Expression* packed = nullptr;
+            const Expression* packed = nullptr;
             if (IsVec3(expr->Type())) {
                 // Cast the regular vec3 to a packed vector type.
                 packed = b.Call(MakePackedVec3(expr->Type()), unpacked);
@@ -518,4 +518,4 @@
     return State{src}.Run();
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/packed_vec3.h b/src/tint/ast/transform/packed_vec3.h
similarity index 89%
rename from src/tint/transform/packed_vec3.h
rename to src/tint/ast/transform/packed_vec3.h
index d13111b..ae2cf1d 100644
--- a/src/tint/transform/packed_vec3.h
+++ b/src/tint/ast/transform/packed_vec3.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_PACKED_VEC3_H_
-#define SRC_TINT_TRANSFORM_PACKED_VEC3_H_
+#ifndef SRC_TINT_AST_TRANSFORM_PACKED_VEC3_H_
+#define SRC_TINT_AST_TRANSFORM_PACKED_VEC3_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// A transform to be used by the MSL backend which will:
 /// * Replace `vec3<T>` types with an internal `__packed_vec3` type when they are used in
@@ -54,6 +54,6 @@
     struct State;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_PACKED_VEC3_H_
+#endif  // SRC_TINT_AST_TRANSFORM_PACKED_VEC3_H_
diff --git a/src/tint/transform/packed_vec3_test.cc b/src/tint/ast/transform/packed_vec3_test.cc
similarity index 99%
rename from src/tint/transform/packed_vec3_test.cc
rename to src/tint/ast/transform/packed_vec3_test.cc
index a7f829f..29d9919 100644
--- a/src/tint/transform/packed_vec3_test.cc
+++ b/src/tint/ast/transform/packed_vec3_test.cc
@@ -12,21 +12,21 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/packed_vec3.h"
+#include "src/tint/ast/transform/packed_vec3.h"
 
 #include <string>
 #include <utility>
 #include <vector>
 
 #include "src/tint/ast/module.h"
+#include "src/tint/ast/transform/test_helper.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/struct.h"
 #include "src/tint/sem/variable.h"
-#include "src/tint/transform/test_helper.h"
 #include "src/tint/type/array.h"
 #include "src/tint/utils/string.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using PackedVec3Test = TransformTest;
@@ -8092,4 +8092,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/pad_structs.cc b/src/tint/ast/transform/pad_structs.cc
similarity index 79%
rename from src/tint/transform/pad_structs.cc
rename to src/tint/ast/transform/pad_structs.cc
index cfa8c90..57211ac 100644
--- a/src/tint/transform/pad_structs.cc
+++ b/src/tint/ast/transform/pad_structs.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/pad_structs.h"
+#include "src/tint/ast/transform/pad_structs.h"
 
 #include <string>
 #include <unordered_map>
@@ -27,14 +27,14 @@
 
 using namespace tint::number_suffixes;  // NOLINT
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::PadStructs);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::PadStructs);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 namespace {
 
-void CreatePadding(utils::Vector<const ast::StructMember*, 8>* new_members,
-                   utils::Hashset<const ast::StructMember*, 8>* padding_members,
+void CreatePadding(utils::Vector<const StructMember*, 8>* new_members,
+                   utils::Hashset<const StructMember*, 8>* padding_members,
                    ProgramBuilder* b,
                    uint32_t bytes) {
     const size_t count = bytes / 4u;
@@ -59,17 +59,17 @@
     CloneContext ctx{&b, src, /* auto_clone_symbols */ true};
     auto& sem = src->Sem();
 
-    std::unordered_map<const ast::Struct*, const ast::Struct*> replaced_structs;
-    utils::Hashset<const ast::StructMember*, 8> padding_members;
+    std::unordered_map<const Struct*, const Struct*> replaced_structs;
+    utils::Hashset<const StructMember*, 8> padding_members;
 
-    ctx.ReplaceAll([&](const ast::Struct* ast_str) -> const ast::Struct* {
+    ctx.ReplaceAll([&](const Struct* ast_str) -> const Struct* {
         auto* str = sem.Get(ast_str);
         if (!str || !str->IsHostShareable()) {
             return nullptr;
         }
         uint32_t offset = 0;
         bool has_runtime_sized_array = false;
-        utils::Vector<const ast::StructMember*, 8> new_members;
+        utils::Vector<const StructMember*, 8> new_members;
         for (auto* mem : str->Members()) {
             auto name = mem->Name().Name();
 
@@ -104,19 +104,18 @@
             CreatePadding(&new_members, &padding_members, ctx.dst, struct_size - offset);
         }
 
-        utils::Vector<const ast::Attribute*, 1> struct_attribs;
+        utils::Vector<const Attribute*, 1> struct_attribs;
         if (!padding_members.IsEmpty()) {
-            struct_attribs =
-                utils::Vector{b.Disable(ast::DisabledValidation::kIgnoreStructMemberLimit)};
+            struct_attribs = utils::Vector{b.Disable(DisabledValidation::kIgnoreStructMemberLimit)};
         }
 
-        auto* new_struct = b.create<ast::Struct>(ctx.Clone(ast_str->name), std::move(new_members),
-                                                 std::move(struct_attribs));
+        auto* new_struct = b.create<Struct>(ctx.Clone(ast_str->name), std::move(new_members),
+                                            std::move(struct_attribs));
         replaced_structs[ast_str] = new_struct;
         return new_struct;
     });
 
-    ctx.ReplaceAll([&](const ast::CallExpression* ast_call) -> const ast::CallExpression* {
+    ctx.ReplaceAll([&](const CallExpression* ast_call) -> const CallExpression* {
         if (ast_call->args.Length() == 0) {
             return nullptr;
         }
@@ -139,7 +138,7 @@
             return nullptr;
         }
 
-        utils::Vector<const ast::Expression*, 8> new_args;
+        utils::Vector<const Expression*, 8> new_args;
 
         auto* arg = ast_call->args.begin();
         for (auto* member : new_struct->members) {
@@ -157,4 +156,4 @@
     return Program(std::move(b));
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/pad_structs.h b/src/tint/ast/transform/pad_structs.h
similarity index 82%
rename from src/tint/transform/pad_structs.h
rename to src/tint/ast/transform/pad_structs.h
index f5bf8cc..be234a4 100644
--- a/src/tint/transform/pad_structs.h
+++ b/src/tint/ast/transform/pad_structs.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_PAD_STRUCTS_H_
-#define SRC_TINT_TRANSFORM_PAD_STRUCTS_H_
+#ifndef SRC_TINT_AST_TRANSFORM_PAD_STRUCTS_H_
+#define SRC_TINT_AST_TRANSFORM_PAD_STRUCTS_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// This transform turns all explicit alignment and sizing into padding
 /// members of structs. This is required for GLSL ES, since it not support
@@ -38,6 +38,6 @@
                       DataMap& outputs) const override;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_PAD_STRUCTS_H_
+#endif  // SRC_TINT_AST_TRANSFORM_PAD_STRUCTS_H_
diff --git a/src/tint/transform/pad_structs_test.cc b/src/tint/ast/transform/pad_structs_test.cc
similarity index 97%
rename from src/tint/transform/pad_structs_test.cc
rename to src/tint/ast/transform/pad_structs_test.cc
index 0826467..89ce34c 100644
--- a/src/tint/transform/pad_structs_test.cc
+++ b/src/tint/ast/transform/pad_structs_test.cc
@@ -12,14 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/pad_structs.h"
+#include "src/tint/ast/transform/pad_structs.h"
 
 #include <memory>
 #include <utility>
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using PadStructsTest = TransformTest;
@@ -605,4 +605,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/preserve_padding.cc b/src/tint/ast/transform/preserve_padding.cc
similarity index 90%
rename from src/tint/transform/preserve_padding.cc
rename to src/tint/ast/transform/preserve_padding.cc
index 0e4daee..ee266a7 100644
--- a/src/tint/transform/preserve_padding.cc
+++ b/src/tint/ast/transform/preserve_padding.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/preserve_padding.h"
+#include "src/tint/ast/transform/preserve_padding.h"
 
 #include <unordered_set>
 #include <utility>
@@ -24,11 +24,11 @@
 #include "src/tint/utils/map.h"
 #include "src/tint/utils/vector.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::PreservePadding);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::PreservePadding);
 
 using namespace tint::number_suffixes;  // NOLINT
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 PreservePadding::PreservePadding() = default;
 
@@ -44,13 +44,13 @@
     /// @returns the ApplyResult
     ApplyResult Run() {
         // Gather a list of assignments that need to be transformed.
-        std::unordered_set<const ast::AssignmentStatement*> assignments_to_transform;
+        std::unordered_set<const AssignmentStatement*> assignments_to_transform;
         for (auto* node : ctx.src->ASTNodes().Objects()) {
             Switch(
                 node,  //
-                [&](const ast::AssignmentStatement* assign) {
+                [&](const AssignmentStatement* assign) {
                     auto* ty = sem.GetVal(assign->lhs)->Type();
-                    if (assign->lhs->Is<ast::PhonyExpression>()) {
+                    if (assign->lhs->Is<PhonyExpression>()) {
                         // Ignore phony assignment.
                         return;
                     }
@@ -65,7 +65,7 @@
                         assignments_to_transform.insert(assign);
                     }
                 },
-                [&](const ast::Enable* enable) {
+                [&](const Enable* enable) {
                     // Check if the full pointer parameters extension is already enabled.
                     if (enable->HasExtension(
                             builtin::Extension::kChromiumExperimentalFullPtrParameters)) {
@@ -78,7 +78,7 @@
         }
 
         // Replace all assignments that include padding with decomposed versions.
-        ctx.ReplaceAll([&](const ast::AssignmentStatement* assign) -> const ast::Statement* {
+        ctx.ReplaceAll([&](const AssignmentStatement* assign) -> const Statement* {
             if (!assignments_to_transform.count(assign)) {
                 return nullptr;
             }
@@ -96,9 +96,9 @@
     /// @param lhs the lhs expression (in the destination program)
     /// @param rhs the rhs expression (in the destination program)
     /// @returns the statement that performs the assignment
-    const ast::Statement* MakeAssignment(const type::Type* ty,
-                                         const ast::Expression* lhs,
-                                         const ast::Expression* rhs) {
+    const Statement* MakeAssignment(const type::Type* ty,
+                                    const Expression* lhs,
+                                    const Expression* rhs) {
         if (!HasPadding(ty)) {
             // No padding - use a regular assignment.
             return b.Assign(lhs, rhs);
@@ -120,7 +120,7 @@
             EnableExtension();
             auto helper = helpers.GetOrCreate(ty, [&]() {
                 auto helper_name = b.Symbols().New("assign_and_preserve_padding");
-                utils::Vector<const ast::Parameter*, 2> params = {
+                utils::Vector<const Parameter*, 2> params = {
                     b.Param(kDestParamName,
                             b.ty.pointer(CreateASTTypeFor(ctx, ty), builtin::AddressSpace::kStorage,
                                          builtin::Access::kReadWrite)),
@@ -137,7 +137,7 @@
             [&](const type::Array* arr) {
                 // Call a helper function that uses a loop to assigns each element separately.
                 return call_helper([&]() {
-                    utils::Vector<const ast::Statement*, 8> body;
+                    utils::Vector<const Statement*, 8> body;
                     auto* idx = b.Var("i", b.Expr(0_u));
                     body.Push(
                         b.For(b.Decl(idx), b.LessThan(idx, u32(arr->ConstantCount().value())),
@@ -151,7 +151,7 @@
             [&](const type::Matrix* mat) {
                 // Call a helper function that assigns each column separately.
                 return call_helper([&]() {
-                    utils::Vector<const ast::Statement*, 4> body;
+                    utils::Vector<const Statement*, 4> body;
                     for (uint32_t i = 0; i < mat->columns(); i++) {
                         body.Push(MakeAssignment(mat->ColumnType(),
                                                  b.IndexAccessor(b.Deref(kDestParamName), u32(i)),
@@ -163,7 +163,7 @@
             [&](const type::Struct* str) {
                 // Call a helper function that assigns each member separately.
                 return call_helper([&]() {
-                    utils::Vector<const ast::Statement*, 8> body;
+                    utils::Vector<const Statement*, 8> body;
                     for (auto member : str->Members()) {
                         auto name = member->Name().Name();
                         body.Push(MakeAssignment(member->Type(),
@@ -244,4 +244,4 @@
     return State(program).Run();
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/preserve_padding.h b/src/tint/ast/transform/preserve_padding.h
similarity index 84%
rename from src/tint/transform/preserve_padding.h
rename to src/tint/ast/transform/preserve_padding.h
index e025c2e..fc460c6 100644
--- a/src/tint/transform/preserve_padding.h
+++ b/src/tint/ast/transform/preserve_padding.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_PRESERVE_PADDING_H_
-#define SRC_TINT_TRANSFORM_PRESERVE_PADDING_H_
+#ifndef SRC_TINT_AST_TRANSFORM_PRESERVE_PADDING_H_
+#define SRC_TINT_AST_TRANSFORM_PRESERVE_PADDING_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// Decompose assignments of whole structure and array types to preserve padding bytes.
 ///
@@ -42,6 +42,6 @@
     struct State;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_PRESERVE_PADDING_H_
+#endif  // SRC_TINT_AST_TRANSFORM_PRESERVE_PADDING_H_
diff --git a/src/tint/transform/preserve_padding_test.cc b/src/tint/ast/transform/preserve_padding_test.cc
similarity index 98%
rename from src/tint/transform/preserve_padding_test.cc
rename to src/tint/ast/transform/preserve_padding_test.cc
index 2b4869a..4ebe210 100644
--- a/src/tint/transform/preserve_padding_test.cc
+++ b/src/tint/ast/transform/preserve_padding_test.cc
@@ -12,13 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/preserve_padding.h"
+#include "src/tint/ast/transform/preserve_padding.h"
 
 #include <utility>
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using PreservePaddingTest = TransformTest;
@@ -776,4 +776,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/promote_initializers_to_let.cc b/src/tint/ast/transform/promote_initializers_to_let.cc
similarity index 89%
rename from src/tint/transform/promote_initializers_to_let.cc
rename to src/tint/ast/transform/promote_initializers_to_let.cc
index cb18e04..9560145 100644
--- a/src/tint/transform/promote_initializers_to_let.cc
+++ b/src/tint/ast/transform/promote_initializers_to_let.cc
@@ -12,22 +12,22 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/promote_initializers_to_let.h"
+#include "src/tint/ast/transform/promote_initializers_to_let.h"
 
 #include <utility>
 
+#include "src/tint/ast/transform/utils/hoist_to_decl_before.h"
 #include "src/tint/ast/traverse_expressions.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/call.h"
 #include "src/tint/sem/statement.h"
 #include "src/tint/sem/value_constructor.h"
-#include "src/tint/transform/utils/hoist_to_decl_before.h"
 #include "src/tint/type/struct.h"
 #include "src/tint/utils/hashset.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::PromoteInitializersToLet);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::PromoteInitializersToLet);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 PromoteInitializersToLet::PromoteInitializersToLet() = default;
 
@@ -69,7 +69,7 @@
             }
         }
 
-        if (auto* src_var_decl = expr->Stmt()->Declaration()->As<ast::VariableDeclStatement>()) {
+        if (auto* src_var_decl = expr->Stmt()->Declaration()->As<VariableDeclStatement>()) {
             if (src_var_decl->variable->initializer == expr->Declaration()) {
                 // This statement is just a variable declaration with the initializer as the
                 // initializer value. This is what we're attempting to transform to, and so
@@ -84,7 +84,7 @@
     // A list of expressions that should be hoisted.
     utils::Vector<const sem::ValueExpression*, 32> to_hoist;
     // A set of expressions that are constant, which _may_ need to be hoisted.
-    utils::Hashset<const ast::Expression*, 32> const_chains;
+    utils::Hashset<const Expression*, 32> const_chains;
 
     // Walk the AST nodes. This order guarantees that leaf-expressions are visited first.
     for (auto* node : src->ASTNodes().Objects()) {
@@ -104,12 +104,10 @@
                 // visit leaf-expressions first, this means the content of const_chains only
                 // contains the outer-most constant expressions.
                 auto* expr = sem->Declaration();
-                bool ok = ast::TraverseExpressions(
-                    expr, b.Diagnostics(), [&](const ast::Expression* child) {
-                        const_chains.Remove(child);
-                        return child == expr ? ast::TraverseAction::Descend
-                                             : ast::TraverseAction::Skip;
-                    });
+                bool ok = TraverseExpressions(expr, b.Diagnostics(), [&](const Expression* child) {
+                    const_chains.Remove(child);
+                    return child == expr ? TraverseAction::Descend : TraverseAction::Skip;
+                });
                 if (!ok) {
                     return Program(std::move(b));
                 }
@@ -153,4 +151,4 @@
     return Program(std::move(b));
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/promote_initializers_to_let.h b/src/tint/ast/transform/promote_initializers_to_let.h
similarity index 82%
rename from src/tint/transform/promote_initializers_to_let.h
rename to src/tint/ast/transform/promote_initializers_to_let.h
index a08ad36..7014942 100644
--- a/src/tint/transform/promote_initializers_to_let.h
+++ b/src/tint/ast/transform/promote_initializers_to_let.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_PROMOTE_INITIALIZERS_TO_LET_H_
-#define SRC_TINT_TRANSFORM_PROMOTE_INITIALIZERS_TO_LET_H_
+#ifndef SRC_TINT_AST_TRANSFORM_PROMOTE_INITIALIZERS_TO_LET_H_
+#define SRC_TINT_AST_TRANSFORM_PROMOTE_INITIALIZERS_TO_LET_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// A transform that hoists array and structure initializers, and identifiers resolving to a
 /// 'const' array to a 'let' variable, declared just before the statement of usage.
@@ -39,6 +39,6 @@
                       DataMap& outputs) const override;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_PROMOTE_INITIALIZERS_TO_LET_H_
+#endif  // SRC_TINT_AST_TRANSFORM_PROMOTE_INITIALIZERS_TO_LET_H_
diff --git a/src/tint/transform/promote_initializers_to_let_test.cc b/src/tint/ast/transform/promote_initializers_to_let_test.cc
similarity index 99%
rename from src/tint/transform/promote_initializers_to_let_test.cc
rename to src/tint/ast/transform/promote_initializers_to_let_test.cc
index fc593d5..aedd225 100644
--- a/src/tint/transform/promote_initializers_to_let_test.cc
+++ b/src/tint/ast/transform/promote_initializers_to_let_test.cc
@@ -12,11 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/promote_initializers_to_let.h"
+#include "src/tint/ast/transform/promote_initializers_to_let.h"
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using PromoteInitializersToLetTest = TransformTest;
@@ -1385,4 +1385,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/promote_side_effects_to_decl.cc b/src/tint/ast/transform/promote_side_effects_to_decl.cc
similarity index 79%
rename from src/tint/transform/promote_side_effects_to_decl.cc
rename to src/tint/ast/transform/promote_side_effects_to_decl.cc
index fef15ee..345caf1 100644
--- a/src/tint/transform/promote_side_effects_to_decl.cc
+++ b/src/tint/ast/transform/promote_side_effects_to_decl.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/promote_side_effects_to_decl.h"
+#include "src/tint/ast/transform/promote_side_effects_to_decl.h"
 
 #include <memory>
 #include <string>
@@ -20,6 +20,8 @@
 #include <utility>
 #include <vector>
 
+#include "src/tint/ast/transform/utils/get_insertion_point.h"
+#include "src/tint/ast/transform/utils/hoist_to_decl_before.h"
 #include "src/tint/ast/traverse_expressions.h"
 #include "src/tint/sem/block_statement.h"
 #include "src/tint/sem/call.h"
@@ -29,13 +31,11 @@
 #include "src/tint/sem/variable.h"
 #include "src/tint/sem/while_statement.h"
 #include "src/tint/transform/manager.h"
-#include "src/tint/transform/utils/get_insertion_point.h"
-#include "src/tint/transform/utils/hoist_to_decl_before.h"
 #include "src/tint/utils/scoped_assignment.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::PromoteSideEffectsToDecl);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::PromoteSideEffectsToDecl);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 // Base state class for common members
@@ -97,49 +97,48 @@
 // need to be hoisted to ensure order of evaluation, both those that give
 // side-effects, as well as those that receive, and returns a set of these
 // expressions.
-using ToHoistSet = std::unordered_set<const ast::Expression*>;
+using ToHoistSet = std::unordered_set<const Expression*>;
 class DecomposeSideEffects::CollectHoistsState : public StateBase {
     // Expressions to hoist because they either cause or receive side-effects.
     ToHoistSet to_hoist;
 
     // Used to mark expressions as not or no longer having side-effects.
-    std::unordered_set<const ast::Expression*> no_side_effects;
+    std::unordered_set<const Expression*> no_side_effects;
 
     // Returns true if `expr` has side-effects. Unlike invoking
     // sem::ValueExpression::HasSideEffects(), this function takes into account whether
     // `expr` has been hoisted, returning false in that case. Furthermore, it
     // returns the correct result on parent expression nodes by traversing the
     // expression tree, memoizing the results to ensure O(1) amortized lookup.
-    bool HasSideEffects(const ast::Expression* expr) {
+    bool HasSideEffects(const Expression* expr) {
         if (no_side_effects.count(expr)) {
             return false;
         }
 
         return Switch(
-            expr,
-            [&](const ast::CallExpression* e) -> bool { return sem.Get(e)->HasSideEffects(); },
-            [&](const ast::BinaryExpression* e) {
+            expr, [&](const CallExpression* e) -> bool { return sem.Get(e)->HasSideEffects(); },
+            [&](const BinaryExpression* e) {
                 if (HasSideEffects(e->lhs) || HasSideEffects(e->rhs)) {
                     return true;
                 }
                 no_side_effects.insert(e);
                 return false;
             },
-            [&](const ast::IndexAccessorExpression* e) {
+            [&](const IndexAccessorExpression* e) {
                 if (HasSideEffects(e->object) || HasSideEffects(e->index)) {
                     return true;
                 }
                 no_side_effects.insert(e);
                 return false;
             },
-            [&](const ast::MemberAccessorExpression* e) {
+            [&](const MemberAccessorExpression* e) {
                 if (HasSideEffects(e->object)) {
                     return true;
                 }
                 no_side_effects.insert(e);
                 return false;
             },
-            [&](const ast::BitcastExpression* e) {  //
+            [&](const BitcastExpression* e) {  //
                 if (HasSideEffects(e->expr)) {
                     return true;
                 }
@@ -147,22 +146,22 @@
                 return false;
             },
 
-            [&](const ast::UnaryOpExpression* e) {  //
+            [&](const UnaryOpExpression* e) {  //
                 if (HasSideEffects(e->expr)) {
                     return true;
                 }
                 no_side_effects.insert(e);
                 return false;
             },
-            [&](const ast::IdentifierExpression* e) {
+            [&](const IdentifierExpression* e) {
                 no_side_effects.insert(e);
                 return false;
             },
-            [&](const ast::LiteralExpression* e) {
+            [&](const LiteralExpression* e) {
                 no_side_effects.insert(e);
                 return false;
             },
-            [&](const ast::PhonyExpression* e) {
+            [&](const PhonyExpression* e) {
                 no_side_effects.insert(e);
                 return false;
             },
@@ -173,14 +172,14 @@
     }
 
     // Adds `e` to `to_hoist` for hoisting to a let later on.
-    void Hoist(const ast::Expression* e) {
+    void Hoist(const Expression* e) {
         no_side_effects.insert(e);
         to_hoist.emplace(e);
     }
 
     // Hoists any expressions in `maybe_hoist` and clears it
     template <size_t N>
-    void Flush(tint::utils::Vector<const ast::Expression*, N>& maybe_hoist) {
+    void Flush(tint::utils::Vector<const Expression*, N>& maybe_hoist) {
         for (auto* m : maybe_hoist) {
             Hoist(m);
         }
@@ -198,13 +197,13 @@
     // over-hoist the lhs expressions, as these may be be chained to refer to a
     // single memory location.
     template <size_t N>
-    bool ProcessExpression(const ast::Expression* expr,
-                           tint::utils::Vector<const ast::Expression*, N>& maybe_hoist) {
-        auto process = [&](const ast::Expression* e) -> bool {
+    bool ProcessExpression(const Expression* expr,
+                           tint::utils::Vector<const Expression*, N>& maybe_hoist) {
+        auto process = [&](const Expression* e) -> bool {
             return ProcessExpression(e, maybe_hoist);
         };
 
-        auto default_process = [&](const ast::Expression* e) {
+        auto default_process = [&](const Expression* e) {
             auto maybe = process(e);
             if (maybe) {
                 maybe_hoist.Push(e);
@@ -215,7 +214,7 @@
             return false;
         };
 
-        auto binary_process = [&](const ast::Expression* lhs, const ast::Expression* rhs) {
+        auto binary_process = [&](const Expression* lhs, const Expression* rhs) {
             // If neither side causes side-effects, but at least one receives them,
             // let parent node hoist. This avoids over-hoisting side-effect receivers
             // of compound binary expressions (e.g. for "((a && b) && c) && f()", we
@@ -235,8 +234,7 @@
             return false;
         };
 
-        auto accessor_process = [&](const ast::Expression* lhs,
-                                    const ast::Expression* rhs = nullptr) {
+        auto accessor_process = [&](const Expression* lhs, const Expression* rhs = nullptr) {
             auto maybe = process(lhs);
             // If lhs is a variable, let parent node hoist otherwise flush it right
             // away. This is to avoid over-hoisting the lhs of accessor chains (e.g.
@@ -255,7 +253,7 @@
 
         return Switch(
             expr,
-            [&](const ast::CallExpression* e) -> bool {
+            [&](const CallExpression* e) -> bool {
                 // We eagerly flush any variables in maybe_hoist for the current
                 // call expression. Then we scope maybe_hoist to the processing of
                 // the call args. This ensures that given: g(c, a(0), d) we hoist
@@ -276,7 +274,7 @@
                 // no_side_effects() first.
                 return true;
             },
-            [&](const ast::IdentifierExpression* e) {
+            [&](const IdentifierExpression* e) {
                 if (auto* sem_e = sem.GetVal(e)) {
                     if (auto* var_user = sem_e->UnwrapLoad()->As<sem::VariableUser>()) {
                         // Don't hoist constants.
@@ -297,7 +295,7 @@
                 }
                 return false;
             },
-            [&](const ast::BinaryExpression* e) {
+            [&](const BinaryExpression* e) {
                 if (e->IsLogical() && HasSideEffects(e)) {
                     // Don't hoist children of logical binary expressions with
                     // side-effects. These will be handled by DecomposeState.
@@ -307,27 +305,25 @@
                 }
                 return binary_process(e->lhs, e->rhs);
             },
-            [&](const ast::BitcastExpression* e) {  //
+            [&](const BitcastExpression* e) {  //
                 return process(e->expr);
             },
-            [&](const ast::UnaryOpExpression* e) {  //
+            [&](const UnaryOpExpression* e) {  //
                 auto r = process(e->expr);
                 // Don't hoist address-of expressions.
                 // E.g. for "g(&b, a(0))", we hoist "a(0)" only.
-                if (e->op == ast::UnaryOp::kAddressOf) {
+                if (e->op == UnaryOp::kAddressOf) {
                     return false;
                 }
                 return r;
             },
-            [&](const ast::IndexAccessorExpression* e) {
-                return accessor_process(e->object, e->index);
-            },
-            [&](const ast::MemberAccessorExpression* e) { return accessor_process(e->object); },
-            [&](const ast::LiteralExpression*) {
+            [&](const IndexAccessorExpression* e) { return accessor_process(e->object, e->index); },
+            [&](const MemberAccessorExpression* e) { return accessor_process(e->object); },
+            [&](const LiteralExpression*) {
                 // Leaf
                 return false;
             },
-            [&](const ast::PhonyExpression*) {
+            [&](const PhonyExpression*) {
                 // Leaf
                 return false;
             },
@@ -338,12 +334,12 @@
     }
 
     // Starts the recursive processing of a statement's expression(s) to hoist side-effects to lets.
-    void ProcessExpression(const ast::Expression* expr) {
+    void ProcessExpression(const Expression* expr) {
         if (!expr) {
             return;
         }
 
-        tint::utils::Vector<const ast::Expression*, 8> maybe_hoist;
+        tint::utils::Vector<const Expression*, 8> maybe_hoist;
         ProcessExpression(expr, maybe_hoist);
     }
 
@@ -354,31 +350,31 @@
         // Traverse all statements, recursively processing their expression tree(s)
         // to hoist side-effects to lets.
         for (auto* node : ctx.src->ASTNodes().Objects()) {
-            auto* stmt = node->As<ast::Statement>();
+            auto* stmt = node->As<Statement>();
             if (!stmt) {
                 continue;
             }
 
             Switch(
                 stmt,  //
-                [&](const ast::AssignmentStatement* s) {
-                    tint::utils::Vector<const ast::Expression*, 8> maybe_hoist;
+                [&](const AssignmentStatement* s) {
+                    tint::utils::Vector<const Expression*, 8> maybe_hoist;
                     ProcessExpression(s->lhs, maybe_hoist);
                     ProcessExpression(s->rhs, maybe_hoist);
                 },
-                [&](const ast::CallStatement* s) {  //
+                [&](const CallStatement* s) {  //
                     ProcessExpression(s->expr);
                 },
-                [&](const ast::ForLoopStatement* s) { ProcessExpression(s->condition); },
-                [&](const ast::WhileStatement* s) { ProcessExpression(s->condition); },
-                [&](const ast::IfStatement* s) {  //
+                [&](const ForLoopStatement* s) { ProcessExpression(s->condition); },
+                [&](const WhileStatement* s) { ProcessExpression(s->condition); },
+                [&](const IfStatement* s) {  //
                     ProcessExpression(s->condition);
                 },
-                [&](const ast::ReturnStatement* s) {  //
+                [&](const ReturnStatement* s) {  //
                     ProcessExpression(s->value);
                 },
-                [&](const ast::SwitchStatement* s) { ProcessExpression(s->condition); },
-                [&](const ast::VariableDeclStatement* s) {
+                [&](const SwitchStatement* s) { ProcessExpression(s->condition); },
+                [&](const VariableDeclStatement* s) {
                     ProcessExpression(s->variable->initializer);
                 });
         }
@@ -394,20 +390,20 @@
     ToHoistSet to_hoist;
 
     // Returns true if `binary_expr` should be decomposed for short-circuit eval.
-    bool IsLogicalWithSideEffects(const ast::BinaryExpression* binary_expr) {
+    bool IsLogicalWithSideEffects(const BinaryExpression* binary_expr) {
         return binary_expr->IsLogical() && (sem.GetVal(binary_expr->lhs)->HasSideEffects() ||
                                             sem.GetVal(binary_expr->rhs)->HasSideEffects());
     }
 
     // Recursive function used to decompose an expression for short-circuit eval.
     template <size_t N>
-    const ast::Expression* Decompose(const ast::Expression* expr,
-                                     tint::utils::Vector<const ast::Statement*, N>* curr_stmts) {
+    const Expression* Decompose(const Expression* expr,
+                                tint::utils::Vector<const Statement*, N>* curr_stmts) {
         // Helper to avoid passing in same args.
         auto decompose = [&](auto& e) { return Decompose(e, curr_stmts); };
 
         // Clones `expr`, possibly hoisting it to a let.
-        auto clone_maybe_hoisted = [&](const ast::Expression* e) -> const ast::Expression* {
+        auto clone_maybe_hoisted = [&](const Expression* e) -> const Expression* {
             if (to_hoist.count(e)) {
                 auto name = b.Symbols().New();
                 auto* v = b.Let(name, ctx.Clone(e));
@@ -420,7 +416,7 @@
 
         return Switch(
             expr,
-            [&](const ast::BinaryExpression* bin_expr) -> const ast::Expression* {
+            [&](const BinaryExpression* bin_expr) -> const Expression* {
                 if (!IsLogicalWithSideEffects(bin_expr)) {
                     // No short-circuit, emit usual binary expr
                     ctx.Replace(bin_expr->lhs, decompose(bin_expr->lhs));
@@ -461,16 +457,16 @@
                 auto name = b.Sym();
                 curr_stmts->Push(b.Decl(b.Var(name, decompose(bin_expr->lhs))));
 
-                const ast::Expression* if_cond = nullptr;
+                const Expression* if_cond = nullptr;
                 if (bin_expr->IsLogicalOr()) {
                     if_cond = b.Not(name);
                 } else {
                     if_cond = b.Expr(name);
                 }
 
-                const ast::BlockStatement* if_body = nullptr;
+                const BlockStatement* if_body = nullptr;
                 {
-                    tint::utils::Vector<const ast::Statement*, N> stmts;
+                    tint::utils::Vector<const Statement*, N> stmts;
                     TINT_SCOPED_ASSIGNMENT(curr_stmts, &stmts);
                     auto* new_rhs = decompose(bin_expr->rhs);
                     curr_stmts->Push(b.Assign(name, new_rhs));
@@ -481,36 +477,36 @@
 
                 return b.Expr(name);
             },
-            [&](const ast::IndexAccessorExpression* idx) {
+            [&](const IndexAccessorExpression* idx) {
                 ctx.Replace(idx->object, decompose(idx->object));
                 ctx.Replace(idx->index, decompose(idx->index));
                 return clone_maybe_hoisted(idx);
             },
-            [&](const ast::BitcastExpression* bitcast) {
+            [&](const BitcastExpression* bitcast) {
                 ctx.Replace(bitcast->expr, decompose(bitcast->expr));
                 return clone_maybe_hoisted(bitcast);
             },
-            [&](const ast::CallExpression* call) {
+            [&](const CallExpression* call) {
                 for (auto* a : call->args) {
                     ctx.Replace(a, decompose(a));
                 }
                 return clone_maybe_hoisted(call);
             },
-            [&](const ast::MemberAccessorExpression* member) {
+            [&](const MemberAccessorExpression* member) {
                 ctx.Replace(member->object, decompose(member->object));
                 return clone_maybe_hoisted(member);
             },
-            [&](const ast::UnaryOpExpression* unary) {
+            [&](const UnaryOpExpression* unary) {
                 ctx.Replace(unary->expr, decompose(unary->expr));
                 return clone_maybe_hoisted(unary);
             },
-            [&](const ast::LiteralExpression* lit) {
+            [&](const LiteralExpression* lit) {
                 return clone_maybe_hoisted(lit);  // Leaf expression, just clone as is
             },
-            [&](const ast::IdentifierExpression* id) {
+            [&](const IdentifierExpression* id) {
                 return clone_maybe_hoisted(id);  // Leaf expression, just clone as is
             },
-            [&](const ast::PhonyExpression* phony) {
+            [&](const PhonyExpression* phony) {
                 return clone_maybe_hoisted(phony);  // Leaf expression, just clone as is
             },
             [&](Default) {
@@ -522,8 +518,7 @@
 
     // Inserts statements in `stmts` before `stmt`
     template <size_t N>
-    void InsertBefore(tint::utils::Vector<const ast::Statement*, N>& stmts,
-                      const ast::Statement* stmt) {
+    void InsertBefore(tint::utils::Vector<const Statement*, N>& stmts, const Statement* stmt) {
         if (!stmts.IsEmpty()) {
             auto ip = utils::GetInsertionPoint(ctx, stmt);
             for (auto* s : stmts) {
@@ -534,86 +529,86 @@
 
     // Decomposes expressions of `stmt`, returning a replacement statement or
     // nullptr if not replacing it.
-    const ast::Statement* DecomposeStatement(const ast::Statement* stmt) {
+    const Statement* DecomposeStatement(const Statement* stmt) {
         return Switch(
             stmt,
-            [&](const ast::AssignmentStatement* s) -> const ast::Statement* {
+            [&](const AssignmentStatement* s) -> const Statement* {
                 if (!sem.GetVal(s->lhs)->HasSideEffects() &&
                     !sem.GetVal(s->rhs)->HasSideEffects()) {
                     return nullptr;
                 }
                 // lhs before rhs
-                tint::utils::Vector<const ast::Statement*, 8> stmts;
+                tint::utils::Vector<const Statement*, 8> stmts;
                 ctx.Replace(s->lhs, Decompose(s->lhs, &stmts));
                 ctx.Replace(s->rhs, Decompose(s->rhs, &stmts));
                 InsertBefore(stmts, s);
                 return ctx.CloneWithoutTransform(s);
             },
-            [&](const ast::CallStatement* s) -> const ast::Statement* {
+            [&](const CallStatement* s) -> const Statement* {
                 if (!sem.Get(s->expr)->HasSideEffects()) {
                     return nullptr;
                 }
-                tint::utils::Vector<const ast::Statement*, 8> stmts;
+                tint::utils::Vector<const Statement*, 8> stmts;
                 ctx.Replace(s->expr, Decompose(s->expr, &stmts));
                 InsertBefore(stmts, s);
                 return ctx.CloneWithoutTransform(s);
             },
-            [&](const ast::ForLoopStatement* s) -> const ast::Statement* {
+            [&](const ForLoopStatement* s) -> const Statement* {
                 if (!s->condition || !sem.GetVal(s->condition)->HasSideEffects()) {
                     return nullptr;
                 }
-                tint::utils::Vector<const ast::Statement*, 8> stmts;
+                tint::utils::Vector<const Statement*, 8> stmts;
                 ctx.Replace(s->condition, Decompose(s->condition, &stmts));
                 InsertBefore(stmts, s);
                 return ctx.CloneWithoutTransform(s);
             },
-            [&](const ast::WhileStatement* s) -> const ast::Statement* {
+            [&](const WhileStatement* s) -> const Statement* {
                 if (!sem.GetVal(s->condition)->HasSideEffects()) {
                     return nullptr;
                 }
-                tint::utils::Vector<const ast::Statement*, 8> stmts;
+                tint::utils::Vector<const Statement*, 8> stmts;
                 ctx.Replace(s->condition, Decompose(s->condition, &stmts));
                 InsertBefore(stmts, s);
                 return ctx.CloneWithoutTransform(s);
             },
-            [&](const ast::IfStatement* s) -> const ast::Statement* {
+            [&](const IfStatement* s) -> const Statement* {
                 if (!sem.GetVal(s->condition)->HasSideEffects()) {
                     return nullptr;
                 }
-                tint::utils::Vector<const ast::Statement*, 8> stmts;
+                tint::utils::Vector<const Statement*, 8> stmts;
                 ctx.Replace(s->condition, Decompose(s->condition, &stmts));
                 InsertBefore(stmts, s);
                 return ctx.CloneWithoutTransform(s);
             },
-            [&](const ast::ReturnStatement* s) -> const ast::Statement* {
+            [&](const ReturnStatement* s) -> const Statement* {
                 if (!s->value || !sem.GetVal(s->value)->HasSideEffects()) {
                     return nullptr;
                 }
-                tint::utils::Vector<const ast::Statement*, 8> stmts;
+                tint::utils::Vector<const Statement*, 8> stmts;
                 ctx.Replace(s->value, Decompose(s->value, &stmts));
                 InsertBefore(stmts, s);
                 return ctx.CloneWithoutTransform(s);
             },
-            [&](const ast::SwitchStatement* s) -> const ast::Statement* {
+            [&](const SwitchStatement* s) -> const Statement* {
                 if (!sem.Get(s->condition)) {
                     return nullptr;
                 }
-                tint::utils::Vector<const ast::Statement*, 8> stmts;
+                tint::utils::Vector<const Statement*, 8> stmts;
                 ctx.Replace(s->condition, Decompose(s->condition, &stmts));
                 InsertBefore(stmts, s);
                 return ctx.CloneWithoutTransform(s);
             },
-            [&](const ast::VariableDeclStatement* s) -> const ast::Statement* {
+            [&](const VariableDeclStatement* s) -> const Statement* {
                 auto* var = s->variable;
                 if (!var->initializer || !sem.GetVal(var->initializer)->HasSideEffects()) {
                     return nullptr;
                 }
-                tint::utils::Vector<const ast::Statement*, 8> stmts;
+                tint::utils::Vector<const Statement*, 8> stmts;
                 ctx.Replace(var->initializer, Decompose(var->initializer, &stmts));
                 InsertBefore(stmts, s);
                 return b.Decl(ctx.CloneWithoutTransform(var));
             },
-            [](Default) -> const ast::Statement* {
+            [](Default) -> const Statement* {
                 // Other statement types don't have expressions
                 return nullptr;
             });
@@ -626,7 +621,7 @@
     void Run() {
         // We replace all BlockStatements as this allows us to iterate over the
         // block statements and ctx.InsertBefore hoisted declarations on them.
-        ctx.ReplaceAll([&](const ast::BlockStatement* block) -> const ast::Statement* {
+        ctx.ReplaceAll([&](const BlockStatement* block) -> const Statement* {
             for (auto* stmt : block->statements) {
                 if (auto* new_stmt = DecomposeStatement(stmt)) {
                     ctx.Replace(stmt, new_stmt);
@@ -634,7 +629,7 @@
 
                 // Handle for loops, as they are the only other AST node that
                 // contains statements outside of BlockStatements.
-                if (auto* fl = stmt->As<ast::ForLoopStatement>()) {
+                if (auto* fl = stmt->As<ForLoopStatement>()) {
                     if (auto* new_stmt = DecomposeStatement(fl->initializer)) {
                         ctx.Replace(fl->initializer, new_stmt);
                     }
@@ -674,10 +669,10 @@
 Transform::ApplyResult PromoteSideEffectsToDecl::Apply(const Program* src,
                                                        const DataMap& inputs,
                                                        DataMap& outputs) const {
-    transform::Manager manager;
+    tint::transform::Manager manager;
     manager.Add<SimplifySideEffectStatements>();
     manager.Add<DecomposeSideEffects>();
     return manager.Apply(src, inputs, outputs);
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/promote_side_effects_to_decl.h b/src/tint/ast/transform/promote_side_effects_to_decl.h
similarity index 80%
rename from src/tint/transform/promote_side_effects_to_decl.h
rename to src/tint/ast/transform/promote_side_effects_to_decl.h
index 36426b6..784b079 100644
--- a/src/tint/transform/promote_side_effects_to_decl.h
+++ b/src/tint/ast/transform/promote_side_effects_to_decl.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_PROMOTE_SIDE_EFFECTS_TO_DECL_H_
-#define SRC_TINT_TRANSFORM_PROMOTE_SIDE_EFFECTS_TO_DECL_H_
+#ifndef SRC_TINT_AST_TRANSFORM_PROMOTE_SIDE_EFFECTS_TO_DECL_H_
+#define SRC_TINT_AST_TRANSFORM_PROMOTE_SIDE_EFFECTS_TO_DECL_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// A transform that hoists expressions with side-effects to variable
 /// declarations before the statement of usage with the goal of ensuring
@@ -37,6 +37,6 @@
                       DataMap& outputs) const override;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_PROMOTE_SIDE_EFFECTS_TO_DECL_H_
+#endif  // SRC_TINT_AST_TRANSFORM_PROMOTE_SIDE_EFFECTS_TO_DECL_H_
diff --git a/src/tint/transform/promote_side_effects_to_decl_test.cc b/src/tint/ast/transform/promote_side_effects_to_decl_test.cc
similarity index 99%
rename from src/tint/transform/promote_side_effects_to_decl_test.cc
rename to src/tint/ast/transform/promote_side_effects_to_decl_test.cc
index 636a809..9cd2e0f 100644
--- a/src/tint/transform/promote_side_effects_to_decl_test.cc
+++ b/src/tint/ast/transform/promote_side_effects_to_decl_test.cc
@@ -12,11 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/promote_side_effects_to_decl.h"
+#include "src/tint/ast/transform/promote_side_effects_to_decl.h"
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using PromoteSideEffectsToDeclTest = TransformTest;
@@ -4134,4 +4134,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/remove_continue_in_switch.cc b/src/tint/ast/transform/remove_continue_in_switch.cc
similarity index 86%
rename from src/tint/transform/remove_continue_in_switch.cc
rename to src/tint/ast/transform/remove_continue_in_switch.cc
index cf0158f..0ae266d 100644
--- a/src/tint/transform/remove_continue_in_switch.cc
+++ b/src/tint/ast/transform/remove_continue_in_switch.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/remove_continue_in_switch.h"
+#include "src/tint/ast/transform/remove_continue_in_switch.h"
 
 #include <string>
 #include <unordered_map>
@@ -20,18 +20,18 @@
 
 #include "src/tint/ast/continue_statement.h"
 #include "src/tint/ast/switch_statement.h"
+#include "src/tint/ast/transform/utils/get_insertion_point.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/block_statement.h"
 #include "src/tint/sem/for_loop_statement.h"
 #include "src/tint/sem/loop_statement.h"
 #include "src/tint/sem/switch_statement.h"
 #include "src/tint/sem/while_statement.h"
-#include "src/tint/transform/utils/get_insertion_point.h"
 #include "src/tint/utils/map.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::RemoveContinueInSwitch);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::RemoveContinueInSwitch);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// PIMPL state for the transform
 struct RemoveContinueInSwitch::State {
@@ -45,7 +45,7 @@
         bool made_changes = false;
 
         for (auto* node : src->ASTNodes().Objects()) {
-            auto* cont = node->As<ast::ContinueStatement>();
+            auto* cont = node->As<ContinueStatement>();
             if (!cont) {
                 continue;
             }
@@ -103,12 +103,12 @@
     const sem::Info& sem = src->Sem();
 
     // Map of switch statement to 'tint_continue' variable.
-    std::unordered_map<const ast::SwitchStatement*, Symbol> switch_to_cont_var_name;
+    std::unordered_map<const SwitchStatement*, Symbol> switch_to_cont_var_name;
 
     // If `cont` is within a switch statement within a loop, returns a pointer to
     // that switch statement.
-    static const ast::SwitchStatement* GetParentSwitchInLoop(const sem::Info& sem,
-                                                             const ast::ContinueStatement* cont) {
+    static const SwitchStatement* GetParentSwitchInLoop(const sem::Info& sem,
+                                                        const ContinueStatement* cont) {
         // Find whether first parent is a switch or a loop
         auto* sem_stmt = sem.Get(cont);
         auto* sem_parent = sem_stmt->FindFirstParent<sem::SwitchStatement, sem::LoopBlockStatement,
@@ -116,7 +116,7 @@
         if (!sem_parent) {
             return nullptr;
         }
-        return sem_parent->Declaration()->As<ast::SwitchStatement>();
+        return sem_parent->Declaration()->As<SwitchStatement>();
     }
 };
 
@@ -130,4 +130,4 @@
     return state.Run();
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/remove_continue_in_switch.h b/src/tint/ast/transform/remove_continue_in_switch.h
similarity index 81%
rename from src/tint/transform/remove_continue_in_switch.h
rename to src/tint/ast/transform/remove_continue_in_switch.h
index a888513..53e27c8 100644
--- a/src/tint/transform/remove_continue_in_switch.h
+++ b/src/tint/ast/transform/remove_continue_in_switch.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_REMOVE_CONTINUE_IN_SWITCH_H_
-#define SRC_TINT_TRANSFORM_REMOVE_CONTINUE_IN_SWITCH_H_
+#ifndef SRC_TINT_AST_TRANSFORM_REMOVE_CONTINUE_IN_SWITCH_H_
+#define SRC_TINT_AST_TRANSFORM_REMOVE_CONTINUE_IN_SWITCH_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// This transform replaces continue statements in switch cases with setting a
 /// bool variable, and checking if the variable is set after the switch to
@@ -40,6 +40,6 @@
     struct State;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_REMOVE_CONTINUE_IN_SWITCH_H_
+#endif  // SRC_TINT_AST_TRANSFORM_REMOVE_CONTINUE_IN_SWITCH_H_
diff --git a/src/tint/transform/remove_continue_in_switch_test.cc b/src/tint/ast/transform/remove_continue_in_switch_test.cc
similarity index 97%
rename from src/tint/transform/remove_continue_in_switch_test.cc
rename to src/tint/ast/transform/remove_continue_in_switch_test.cc
index 0b52457..84ad5cd 100644
--- a/src/tint/transform/remove_continue_in_switch_test.cc
+++ b/src/tint/ast/transform/remove_continue_in_switch_test.cc
@@ -12,10 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/remove_continue_in_switch.h"
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/remove_continue_in_switch.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using RemoveContinueInSwitchTest = TransformTest;
@@ -614,4 +614,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/remove_phonies.cc b/src/tint/ast/transform/remove_phonies.cc
similarity index 84%
rename from src/tint/transform/remove_phonies.cc
rename to src/tint/ast/transform/remove_phonies.cc
index e5aecd2..7197347 100644
--- a/src/tint/transform/remove_phonies.cc
+++ b/src/tint/ast/transform/remove_phonies.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/remove_phonies.h"
+#include "src/tint/ast/transform/remove_phonies.h"
 
 #include <memory>
 #include <unordered_map>
@@ -28,9 +28,9 @@
 #include "src/tint/utils/map.h"
 #include "src/tint/utils/scoped_assignment.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::RemovePhonies);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::RemovePhonies);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using SinkSignature = std::vector<const type::Type*>;
@@ -53,14 +53,14 @@
     for (auto* node : src->ASTNodes().Objects()) {
         Switch(
             node,
-            [&](const ast::AssignmentStatement* stmt) {
-                if (stmt->lhs->Is<ast::PhonyExpression>()) {
+            [&](const AssignmentStatement* stmt) {
+                if (stmt->lhs->Is<PhonyExpression>()) {
                     made_changes = true;
 
-                    std::vector<const ast::Expression*> side_effects;
-                    if (!ast::TraverseExpressions(
-                            stmt->rhs, b.Diagnostics(), [&](const ast::CallExpression* expr) {
-                                // ast::CallExpression may map to a function or builtin call
+                    std::vector<const Expression*> side_effects;
+                    if (!TraverseExpressions(
+                            stmt->rhs, b.Diagnostics(), [&](const CallExpression* expr) {
+                                // CallExpression may map to a function or builtin call
                                 // (both may have side-effects), or a value constructor or value
                                 // conversion (both do not have side effects).
                                 auto* call = sem.Get<sem::Call>(expr);
@@ -68,14 +68,14 @@
                                     // Semantic node must be a Materialize, in which case the
                                     // expression was creation-time (compile time), so could not
                                     // have side effects. Just skip.
-                                    return ast::TraverseAction::Skip;
+                                    return TraverseAction::Skip;
                                 }
                                 if (call->Target()->IsAnyOf<sem::Function, sem::Builtin>() &&
                                     call->HasSideEffects()) {
                                     side_effects.push_back(expr);
-                                    return ast::TraverseAction::Skip;
+                                    return TraverseAction::Skip;
                                 }
-                                return ast::TraverseAction::Descend;
+                                return TraverseAction::Descend;
                             })) {
                         return;
                     }
@@ -88,12 +88,12 @@
                     }
 
                     if (side_effects.size() == 1) {
-                        if (auto* call_expr = side_effects[0]->As<ast::CallExpression>()) {
+                        if (auto* call_expr = side_effects[0]->As<CallExpression>()) {
                             // Phony assignment with single call side effect.
                             auto* call = sem.Get(call_expr)->Unwrap()->As<sem::Call>();
                             if (call->Target()->MustUse()) {
                                 // Replace phony assignment assignment to uniquely named let.
-                                ctx.Replace<ast::Statement>(stmt, [&, call_expr] {  //
+                                ctx.Replace<Statement>(stmt, [&, call_expr] {  //
                                     auto name = b.Symbols().New("tint_phony");
                                     auto* rhs = ctx.Clone(call_expr);
                                     return b.Decl(b.Let(name, rhs));
@@ -118,7 +118,7 @@
                         }
                         auto sink = sinks.GetOrCreate(sig, [&] {
                             auto name = b.Symbols().New("phony_sink");
-                            utils::Vector<const ast::Parameter*, 8> params;
+                            utils::Vector<const Parameter*, 8> params;
                             for (auto* ty : sig) {
                                 auto ast_ty = CreateASTTypeFor(ctx, ty);
                                 params.Push(b.Param("p" + std::to_string(params.Length()), ast_ty));
@@ -126,7 +126,7 @@
                             b.Func(name, params, b.ty.void_(), {});
                             return name;
                         });
-                        utils::Vector<const ast::Expression*, 8> args;
+                        utils::Vector<const Expression*, 8> args;
                         for (auto* arg : side_effects) {
                             args.Push(ctx.Clone(arg));
                         }
@@ -134,7 +134,7 @@
                     });
                 }
             },
-            [&](const ast::CallStatement* stmt) {
+            [&](const CallStatement* stmt) {
                 // Remove call statements to const value-returning functions.
                 // TODO(crbug.com/tint/1637): Remove if `stmt->expr` has no side-effects.
                 auto* sem_expr = sem.Get(stmt->expr);
@@ -153,4 +153,4 @@
     return Program(std::move(b));
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/remove_phonies.h b/src/tint/ast/transform/remove_phonies.h
similarity index 82%
rename from src/tint/transform/remove_phonies.h
rename to src/tint/ast/transform/remove_phonies.h
index 7b1f9fd..1379252 100644
--- a/src/tint/transform/remove_phonies.h
+++ b/src/tint/ast/transform/remove_phonies.h
@@ -12,15 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_REMOVE_PHONIES_H_
-#define SRC_TINT_TRANSFORM_REMOVE_PHONIES_H_
+#ifndef SRC_TINT_AST_TRANSFORM_REMOVE_PHONIES_H_
+#define SRC_TINT_AST_TRANSFORM_REMOVE_PHONIES_H_
 
 #include <string>
 #include <unordered_map>
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// RemovePhonies is a Transform that removes all phony-assignment statements,
 /// while preserving function call expressions in the RHS of the assignment that
@@ -39,6 +39,6 @@
                       DataMap& outputs) const override;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_REMOVE_PHONIES_H_
+#endif  // SRC_TINT_AST_TRANSFORM_REMOVE_PHONIES_H_
diff --git a/src/tint/transform/remove_phonies_test.cc b/src/tint/ast/transform/remove_phonies_test.cc
similarity index 97%
rename from src/tint/transform/remove_phonies_test.cc
rename to src/tint/ast/transform/remove_phonies_test.cc
index 60252a1..718e303 100644
--- a/src/tint/transform/remove_phonies_test.cc
+++ b/src/tint/ast/transform/remove_phonies_test.cc
@@ -12,15 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/remove_phonies.h"
+#include "src/tint/ast/transform/remove_phonies.h"
 
 #include <memory>
 #include <utility>
 #include <vector>
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using RemovePhoniesTest = TransformTest;
@@ -484,4 +484,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/remove_unreachable_statements.cc b/src/tint/ast/transform/remove_unreachable_statements.cc
similarity index 89%
rename from src/tint/transform/remove_unreachable_statements.cc
rename to src/tint/ast/transform/remove_unreachable_statements.cc
index f9bf202..7ee5cf0 100644
--- a/src/tint/transform/remove_unreachable_statements.cc
+++ b/src/tint/ast/transform/remove_unreachable_statements.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/remove_unreachable_statements.h"
+#include "src/tint/ast/transform/remove_unreachable_statements.h"
 
 #include <memory>
 #include <unordered_map>
@@ -28,9 +28,9 @@
 #include "src/tint/utils/map.h"
 #include "src/tint/utils/scoped_assignment.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::RemoveUnreachableStatements);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::RemoveUnreachableStatements);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 RemoveUnreachableStatements::RemoveUnreachableStatements() = default;
 
@@ -60,4 +60,4 @@
     return Program(std::move(b));
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/remove_unreachable_statements.h b/src/tint/ast/transform/remove_unreachable_statements.h
similarity index 78%
rename from src/tint/transform/remove_unreachable_statements.h
rename to src/tint/ast/transform/remove_unreachable_statements.h
index dd1054d..2049e70 100644
--- a/src/tint/transform/remove_unreachable_statements.h
+++ b/src/tint/ast/transform/remove_unreachable_statements.h
@@ -12,15 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_REMOVE_UNREACHABLE_STATEMENTS_H_
-#define SRC_TINT_TRANSFORM_REMOVE_UNREACHABLE_STATEMENTS_H_
+#ifndef SRC_TINT_AST_TRANSFORM_REMOVE_UNREACHABLE_STATEMENTS_H_
+#define SRC_TINT_AST_TRANSFORM_REMOVE_UNREACHABLE_STATEMENTS_H_
 
 #include <string>
 #include <unordered_map>
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// RemoveUnreachableStatements is a Transform that removes all statements
 /// marked as unreachable.
@@ -39,6 +39,6 @@
                       DataMap& outputs) const override;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_REMOVE_UNREACHABLE_STATEMENTS_H_
+#endif  // SRC_TINT_AST_TRANSFORM_REMOVE_UNREACHABLE_STATEMENTS_H_
diff --git a/src/tint/transform/remove_unreachable_statements_test.cc b/src/tint/ast/transform/remove_unreachable_statements_test.cc
similarity index 95%
rename from src/tint/transform/remove_unreachable_statements_test.cc
rename to src/tint/ast/transform/remove_unreachable_statements_test.cc
index 9267e6f..45f1869 100644
--- a/src/tint/transform/remove_unreachable_statements_test.cc
+++ b/src/tint/ast/transform/remove_unreachable_statements_test.cc
@@ -12,11 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/remove_unreachable_statements.h"
+#include "src/tint/ast/transform/remove_unreachable_statements.h"
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using RemoveUnreachableStatementsTest = TransformTest;
@@ -252,4 +252,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/renamer.cc b/src/tint/ast/transform/renamer.cc
similarity index 95%
rename from src/tint/transform/renamer.cc
rename to src/tint/ast/transform/renamer.cc
index 92589b1..b7c03a1 100644
--- a/src/tint/transform/renamer.cc
+++ b/src/tint/ast/transform/renamer.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/renamer.h"
+#include "src/tint/ast/transform/renamer.h"
 
 #include <memory>
 #include <utility>
@@ -27,11 +27,11 @@
 #include "src/tint/switch.h"
 #include "src/tint/utils/unicode.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::Renamer);
-TINT_INSTANTIATE_TYPEINFO(tint::transform::Renamer::Data);
-TINT_INSTANTIATE_TYPEINFO(tint::transform::Renamer::Config);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::Renamer);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::Renamer::Data);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::Renamer::Config);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 namespace {
 
@@ -1265,10 +1265,10 @@
     }
 
     // Identifiers that need to keep their symbols preserved.
-    utils::Hashset<const ast::Identifier*, 16> preserved_identifiers;
+    utils::Hashset<const Identifier*, 16> preserved_identifiers;
 
     for (auto* node : src->ASTNodes().Objects()) {
-        auto preserve_if_builtin_type = [&](const ast::Identifier* ident) {
+        auto preserve_if_builtin_type = [&](const Identifier* ident) {
             if (!global_decls.Contains(ident->symbol)) {
                 preserved_identifiers.Add(ident);
             }
@@ -1276,7 +1276,7 @@
 
         Switch(
             node,
-            [&](const ast::MemberAccessorExpression* accessor) {
+            [&](const MemberAccessorExpression* accessor) {
                 auto* sem = src->Sem().Get(accessor)->UnwrapLoad();
                 if (sem->Is<sem::Swizzle>()) {
                     preserved_identifiers.Add(accessor->member);
@@ -1288,19 +1288,19 @@
                     }
                 }
             },
-            [&](const ast::DiagnosticAttribute* diagnostic) {
+            [&](const DiagnosticAttribute* diagnostic) {
                 if (auto* category = diagnostic->control.rule_name->category) {
                     preserved_identifiers.Add(category);
                 }
                 preserved_identifiers.Add(diagnostic->control.rule_name->name);
             },
-            [&](const ast::DiagnosticDirective* diagnostic) {
+            [&](const DiagnosticDirective* diagnostic) {
                 if (auto* category = diagnostic->control.rule_name->category) {
                     preserved_identifiers.Add(category);
                 }
                 preserved_identifiers.Add(diagnostic->control.rule_name->name);
             },
-            [&](const ast::IdentifierExpression* expr) {
+            [&](const IdentifierExpression* expr) {
                 Switch(
                     src->Sem().Get(expr),  //
                     [&](const sem::BuiltinEnumExpressionBase*) {
@@ -1310,7 +1310,7 @@
                         preserve_if_builtin_type(expr->identifier);
                     });
             },
-            [&](const ast::CallExpression* call) {
+            [&](const CallExpression* call) {
                 Switch(
                     src->Sem().Get(call)->UnwrapMaterialize()->As<sem::Call>()->Target(),
                     [&](const sem::Builtin*) {
@@ -1372,7 +1372,7 @@
     ProgramBuilder b;
     CloneContext ctx{&b, src, /* auto_clone_symbols */ false};
 
-    ctx.ReplaceAll([&](const ast::Identifier* ident) -> const ast::Identifier* {
+    ctx.ReplaceAll([&](const Identifier* ident) -> const Identifier* {
         const auto symbol = ident->symbol;
         if (preserved_identifiers.Contains(ident) || !should_rename(symbol)) {
             return nullptr;  // Preserve symbol
@@ -1382,12 +1382,12 @@
         auto replacement = remappings.GetOrCreate(symbol, [&] { return b.Symbols().New(); });
 
         // Reconstruct the identifier
-        if (auto* tmpl_ident = ident->As<ast::TemplatedIdentifier>()) {
+        if (auto* tmpl_ident = ident->As<TemplatedIdentifier>()) {
             auto args = ctx.Clone(tmpl_ident->arguments);
-            return ctx.dst->create<ast::TemplatedIdentifier>(ctx.Clone(ident->source), replacement,
-                                                             std::move(args), utils::Empty);
+            return ctx.dst->create<TemplatedIdentifier>(ctx.Clone(ident->source), replacement,
+                                                        std::move(args), utils::Empty);
         }
-        return ctx.dst->create<ast::Identifier>(ctx.Clone(ident->source), replacement);
+        return ctx.dst->create<Identifier>(ctx.Clone(ident->source), replacement);
     });
 
     ctx.Clone();
@@ -1401,4 +1401,4 @@
     return Program(std::move(b));
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/renamer.h b/src/tint/ast/transform/renamer.h
similarity index 92%
rename from src/tint/transform/renamer.h
rename to src/tint/ast/transform/renamer.h
index 015e386..fb839c2 100644
--- a/src/tint/transform/renamer.h
+++ b/src/tint/ast/transform/renamer.h
@@ -12,15 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_RENAMER_H_
-#define SRC_TINT_TRANSFORM_RENAMER_H_
+#ifndef SRC_TINT_AST_TRANSFORM_RENAMER_H_
+#define SRC_TINT_AST_TRANSFORM_RENAMER_H_
 
 #include <string>
 #include <unordered_map>
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// Renamer is a Transform that renames all the symbols in a program.
 class Renamer final : public utils::Castable<Renamer, Transform> {
@@ -91,6 +91,6 @@
                       DataMap& outputs) const override;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_RENAMER_H_
+#endif  // SRC_TINT_AST_TRANSFORM_RENAMER_H_
diff --git a/src/tint/transform/renamer_test.cc b/src/tint/ast/transform/renamer_test.cc
similarity index 99%
rename from src/tint/transform/renamer_test.cc
rename to src/tint/ast/transform/renamer_test.cc
index cd321fb..fe7e845 100644
--- a/src/tint/transform/renamer_test.cc
+++ b/src/tint/ast/transform/renamer_test.cc
@@ -12,18 +12,18 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/renamer.h"
+#include "src/tint/ast/transform/renamer.h"
 
 #include <memory>
 #include <unordered_set>
 #include <vector>
 
 #include "gmock/gmock.h"
+#include "src/tint/ast/transform/test_helper.h"
 #include "src/tint/builtin/builtin.h"
 #include "src/tint/builtin/texel_format.h"
-#include "src/tint/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 constexpr const char kUnicodeIdentifier[] =  // "𝖎𝖉𝖊𝖓𝖙𝖎𝖋𝖎𝖊𝖗123"
@@ -2057,4 +2057,4 @@
                          testing::ValuesIn(Identifiers()));
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/robustness.cc b/src/tint/ast/transform/robustness.cc
similarity index 93%
rename from src/tint/transform/robustness.cc
rename to src/tint/ast/transform/robustness.cc
index 3860de4..120d256 100644
--- a/src/tint/transform/robustness.cc
+++ b/src/tint/ast/transform/robustness.cc
@@ -12,12 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/robustness.h"
+#include "src/tint/ast/transform/robustness.h"
 
 #include <algorithm>
 #include <limits>
 #include <utility>
 
+#include "src/tint/ast/transform/utils/hoist_to_decl_before.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/block_statement.h"
 #include "src/tint/sem/builtin.h"
@@ -29,15 +30,14 @@
 #include "src/tint/sem/statement.h"
 #include "src/tint/sem/value_expression.h"
 #include "src/tint/switch.h"
-#include "src/tint/transform/utils/hoist_to_decl_before.h"
 #include "src/tint/type/reference.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::Robustness);
-TINT_INSTANTIATE_TYPEINFO(tint::transform::Robustness::Config);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::Robustness);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::Robustness::Config);
 
 using namespace tint::number_suffixes;  // NOLINT
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// PIMPL state for the transform
 struct Robustness::State {
@@ -58,7 +58,7 @@
         for (auto* node : ctx.src->ASTNodes().Objects()) {
             Switch(
                 node,  //
-                [&](const ast::IndexAccessorExpression* e) {
+                [&](const IndexAccessorExpression* e) {
                     // obj[idx]
                     // Array, matrix and vector indexing may require robustness transformation.
                     auto* expr = sem.Get(e)->Unwrap()->As<sem::IndexAccessorExpression>();
@@ -73,7 +73,7 @@
                             break;
                     }
                 },
-                [&](const ast::IdentifierExpression* e) {
+                [&](const IdentifierExpression* e) {
                     // Identifiers may resolve to pointer lets, which may be predicated.
                     // Inspect.
                     if (auto* user = sem.Get<sem::VariableUser>(e)) {
@@ -86,42 +86,42 @@
                         }
                     }
                 },
-                [&](const ast::AccessorExpression* e) {
+                [&](const AccessorExpression* e) {
                     // obj.member
                     // Propagate the predication from the object to this expression.
                     if (auto pred = predicates.Get(e->object)) {
                         predicates.Add(e, *pred);
                     }
                 },
-                [&](const ast::UnaryOpExpression* e) {
+                [&](const UnaryOpExpression* e) {
                     // Includes address-of, or indirection
                     // Propagate the predication from the inner expression to this expression.
                     if (auto pred = predicates.Get(e->expr)) {
                         predicates.Add(e, *pred);
                     }
                 },
-                [&](const ast::AssignmentStatement* s) {
+                [&](const AssignmentStatement* s) {
                     if (auto pred = predicates.Get(s->lhs)) {
                         // Assignment target is predicated
                         // Replace statement with condition on the predicate
                         ctx.Replace(s, b.If(*pred, b.Block(ctx.Clone(s))));
                     }
                 },
-                [&](const ast::CompoundAssignmentStatement* s) {
+                [&](const CompoundAssignmentStatement* s) {
                     if (auto pred = predicates.Get(s->lhs)) {
                         // Assignment expression is predicated
                         // Replace statement with condition on the predicate
                         ctx.Replace(s, b.If(*pred, b.Block(ctx.Clone(s))));
                     }
                 },
-                [&](const ast::IncrementDecrementStatement* s) {
+                [&](const IncrementDecrementStatement* s) {
                     if (auto pred = predicates.Get(s->lhs)) {
                         // Assignment expression is predicated
                         // Replace statement with condition on the predicate
                         ctx.Replace(s, b.If(*pred, b.Block(ctx.Clone(s))));
                     }
                 },
-                [&](const ast::CallExpression* e) {
+                [&](const CallExpression* e) {
                     if (auto* call = sem.Get<sem::Call>(e)) {
                         Switch(
                             call->Target(),  //
@@ -163,7 +163,7 @@
             //     predicated_expr = expr;
             //   }
             //
-            if (auto* expr = node->As<ast::Expression>()) {
+            if (auto* expr = node->As<Expression>()) {
                 if (auto pred = predicates.Get(expr)) {
                     // Expression is predicated
                     auto* sem_expr = sem.GetVal(expr);
@@ -202,15 +202,15 @@
     /// Alias to the source program's semantic info
     const sem::Info& sem = ctx.src->Sem();
     /// Map of expression to predicate condition
-    utils::Hashmap<const ast::Expression*, Symbol, 32> predicates{};
+    utils::Hashmap<const Expression*, Symbol, 32> predicates{};
 
     /// @return the `u32` typed expression that represents the maximum indexable value for the index
     /// accessor @p expr, or nullptr if there is no robustness limit for this expression.
-    const ast::Expression* DynamicLimitFor(const sem::IndexAccessorExpression* expr) {
+    const Expression* DynamicLimitFor(const sem::IndexAccessorExpression* expr) {
         auto* obj_type = expr->Object()->Type();
         return Switch(
             obj_type->UnwrapRef(),  //
-            [&](const type::Vector* vec) -> const ast::Expression* {
+            [&](const type::Vector* vec) -> const Expression* {
                 if (expr->Index()->ConstantValue() || expr->Index()->Is<sem::Swizzle>()) {
                     // Index and size is constant.
                     // Validation will have rejected any OOB accesses.
@@ -218,7 +218,7 @@
                 }
                 return b.Expr(u32(vec->Width() - 1u));
             },
-            [&](const type::Matrix* mat) -> const ast::Expression* {
+            [&](const type::Matrix* mat) -> const Expression* {
                 if (expr->Index()->ConstantValue()) {
                     // Index and size is constant.
                     // Validation will have rejected any OOB accesses.
@@ -226,7 +226,7 @@
                 }
                 return b.Expr(u32(mat->columns() - 1u));
             },
-            [&](const type::Array* arr) -> const ast::Expression* {
+            [&](const type::Array* arr) -> const Expression* {
                 if (arr->Count()->Is<type::RuntimeArrayCount>()) {
                     // Size is unknown until runtime.
                     // Must clamp, even if the index is constant.
@@ -248,7 +248,7 @@
                                           type::Array::kErrExpectedConstantCount);
                 return nullptr;
             },
-            [&](Default) -> const ast::Expression* {
+            [&](Default) -> const Expression* {
                 TINT_ICE(Transform, b.Diagnostics())
                     << "unhandled object type in robustness of array index: "
                     << obj_type->UnwrapRef()->FriendlyName();
@@ -350,7 +350,7 @@
     /// Applies predication to the non-texture builtin call, if required.
     void MaybePredicateNonTextureBuiltin(const sem::Call* call, const sem::Builtin* builtin) {
         // Gather the predications for the builtin arguments
-        const ast::Expression* predicate = nullptr;
+        const Expression* predicate = nullptr;
         for (auto* arg : call->Declaration()->args) {
             if (auto pred = predicates.Get(arg)) {
                 predicate = And(predicate, b.Expr(*pred));
@@ -393,7 +393,7 @@
         auto* texture_arg = expr->args[static_cast<size_t>(texture_arg_idx)];
 
         // Build the builtin predicate from the arguments
-        const ast::Expression* predicate = nullptr;
+        const Expression* predicate = nullptr;
 
         Symbol level_idx, num_levels;
         if (level_arg_idx >= 0) {
@@ -554,7 +554,7 @@
     }
 
     /// @returns a bitwise and of the two expressions, or the other expression if one is null.
-    const ast::Expression* And(const ast::Expression* lhs, const ast::Expression* rhs) {
+    const Expression* And(const Expression* lhs, const Expression* rhs) {
         if (lhs && rhs) {
             return b.And(lhs, rhs);
         }
@@ -568,11 +568,11 @@
     /// predicate.
     /// @param else_stmt - the statement to execute for the predication failure
     void PredicateCall(const sem::Call* call,
-                       const ast::Expression* predicate,
-                       const ast::BlockStatement* else_stmt = nullptr) {
+                       const Expression* predicate,
+                       const BlockStatement* else_stmt = nullptr) {
         auto* expr = call->Declaration();
         auto* stmt = call->Stmt();
-        auto* call_stmt = stmt->Declaration()->As<ast::CallStatement>();
+        auto* call_stmt = stmt->Declaration()->As<CallStatement>();
         if (call_stmt && call_stmt->expr == expr) {
             // Wrap the statement in an if-statement with the predicate condition.
             hoist.Replace(stmt, b.If(predicate, b.Block(ctx.Clone(stmt->Declaration())),
@@ -646,7 +646,7 @@
     }
 
     /// @returns a scalar or vector type with the element type @p scalar and width @p width
-    ast::Type ScalarOrVecTy(ast::Type scalar, uint32_t width) const {
+    Type ScalarOrVecTy(Type scalar, uint32_t width) const {
         if (width > 1) {
             return b.ty.vec(scalar, width);
         }
@@ -655,7 +655,7 @@
 
     /// @returns a vector constructed with the scalar expression @p scalar if @p width > 1,
     /// otherwise returns @p scalar.
-    const ast::Expression* ScalarOrVec(const ast::Expression* scalar, uint32_t width) {
+    const Expression* ScalarOrVec(const Expression* scalar, uint32_t width) {
         if (width > 1) {
             return b.Call(b.ty.vec<Infer>(width), scalar);
         }
@@ -664,13 +664,13 @@
 
     /// @returns @p val cast to a `vecN<i32>`, where `N` is @p width, or cast to i32 if @p width
     /// is 1.
-    const ast::CallExpression* CastToSigned(const ast::Expression* val, uint32_t width) {
+    const CallExpression* CastToSigned(const Expression* val, uint32_t width) {
         return b.Call(ScalarOrVecTy(b.ty.i32(), width), val);
     }
 
     /// @returns @p val cast to a `vecN<u32>`, where `N` is @p width, or cast to u32 if @p width
     /// is 1.
-    const ast::CallExpression* CastToUnsigned(const ast::Expression* val, uint32_t width) {
+    const CallExpression* CastToUnsigned(const Expression* val, uint32_t width) {
         return b.Call(ScalarOrVecTy(b.ty.u32(), width), val);
     }
 };
@@ -694,4 +694,4 @@
     return State{src, std::move(cfg)}.Run();
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/robustness.h b/src/tint/ast/transform/robustness.h
similarity index 92%
rename from src/tint/transform/robustness.h
rename to src/tint/ast/transform/robustness.h
index e916b16..35804b4 100644
--- a/src/tint/transform/robustness.h
+++ b/src/tint/ast/transform/robustness.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_ROBUSTNESS_H_
-#define SRC_TINT_TRANSFORM_ROBUSTNESS_H_
+#ifndef SRC_TINT_AST_TRANSFORM_ROBUSTNESS_H_
+#define SRC_TINT_AST_TRANSFORM_ROBUSTNESS_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// This transform is responsible for ensuring that all out of bounds accesses are prevented,
 /// either by conditioning the access (predication) or through clamping of the index to keep the
@@ -93,6 +93,6 @@
     struct State;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_ROBUSTNESS_H_
+#endif  // SRC_TINT_AST_TRANSFORM_ROBUSTNESS_H_
diff --git a/src/tint/transform/robustness_test.cc b/src/tint/ast/transform/robustness_test.cc
similarity index 99%
rename from src/tint/transform/robustness_test.cc
rename to src/tint/ast/transform/robustness_test.cc
index ee583cf..1200bb4 100644
--- a/src/tint/transform/robustness_test.cc
+++ b/src/tint/ast/transform/robustness_test.cc
@@ -12,11 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/robustness.h"
+#include "src/tint/ast/transform/robustness.h"
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 static std::ostream& operator<<(std::ostream& out, Robustness::Action action) {
     switch (action) {
@@ -5496,4 +5496,4 @@
                                          Robustness::Action::kClamp,
                                          Robustness::Action::kPredicate));
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/simplify_pointers.cc b/src/tint/ast/transform/simplify_pointers.cc
similarity index 84%
rename from src/tint/transform/simplify_pointers.cc
rename to src/tint/ast/transform/simplify_pointers.cc
index e8c2bf9..1fb8f5d 100644
--- a/src/tint/transform/simplify_pointers.cc
+++ b/src/tint/ast/transform/simplify_pointers.cc
@@ -12,24 +12,24 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/simplify_pointers.h"
+#include "src/tint/ast/transform/simplify_pointers.h"
 
 #include <memory>
 #include <unordered_map>
 #include <utility>
 #include <vector>
 
+#include "src/tint/ast/transform/unshadow.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/block_statement.h"
 #include "src/tint/sem/function.h"
 #include "src/tint/sem/statement.h"
 #include "src/tint/sem/variable.h"
 #include "src/tint/switch.h"
-#include "src/tint/transform/unshadow.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::SimplifyPointers);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::SimplifyPointers);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 namespace {
 
@@ -41,7 +41,7 @@
     /// Zero: no pointer op on `expr`
     int indirections = 0;
     /// The expression being operated on
-    const ast::Expression* expr = nullptr;
+    const Expression* expr = nullptr;
 };
 
 }  // namespace
@@ -64,29 +64,29 @@
     /// expression. The function-like argument `cb` is called for each found.
     /// @param expr the expression to traverse
     /// @param cb a function-like object with the signature
-    /// `void(const ast::Expression*)`, which is called for each array index
+    /// `void(const Expression*)`, which is called for each array index
     /// expression
     template <typename F>
-    static void CollectSavedArrayIndices(const ast::Expression* expr, F&& cb) {
-        if (auto* a = expr->As<ast::IndexAccessorExpression>()) {
+    static void CollectSavedArrayIndices(const Expression* expr, F&& cb) {
+        if (auto* a = expr->As<IndexAccessorExpression>()) {
             CollectSavedArrayIndices(a->object, cb);
-            if (!a->index->Is<ast::LiteralExpression>()) {
+            if (!a->index->Is<LiteralExpression>()) {
                 cb(a->index);
             }
             return;
         }
 
-        if (auto* m = expr->As<ast::MemberAccessorExpression>()) {
+        if (auto* m = expr->As<MemberAccessorExpression>()) {
             CollectSavedArrayIndices(m->object, cb);
             return;
         }
 
-        if (auto* u = expr->As<ast::UnaryOpExpression>()) {
+        if (auto* u = expr->As<UnaryOpExpression>()) {
             CollectSavedArrayIndices(u->expr, cb);
             return;
         }
 
-        // Note: Other ast::Expression types can be safely ignored as they cannot be
+        // Note: Other Expression types can be safely ignored as they cannot be
         // used to generate a reference or pointer.
         // See https://gpuweb.github.io/gpuweb/wgsl/#forming-references-and-pointers
     }
@@ -95,16 +95,16 @@
     /// indirection ops into a PointerOp.
     /// @param in the expression to walk
     /// @returns the reduced PointerOp
-    PointerOp Reduce(const ast::Expression* in) const {
+    PointerOp Reduce(const Expression* in) const {
         PointerOp op{0, in};
         while (true) {
-            if (auto* unary = op.expr->As<ast::UnaryOpExpression>()) {
+            if (auto* unary = op.expr->As<UnaryOpExpression>()) {
                 switch (unary->op) {
-                    case ast::UnaryOp::kIndirection:
+                    case UnaryOp::kIndirection:
                         op.indirections++;
                         op.expr = unary->expr;
                         continue;
-                    case ast::UnaryOp::kAddressOf:
+                    case UnaryOp::kAddressOf:
                         op.indirections--;
                         op.expr = unary->expr;
                         continue;
@@ -114,8 +114,8 @@
             }
             if (auto* user = ctx.src->Sem().Get<sem::VariableUser>(op.expr)) {
                 auto* var = user->Variable();
-                if (var->Is<sem::LocalVariable>() &&       //
-                    var->Declaration()->Is<ast::Let>() &&  //
+                if (var->Is<sem::LocalVariable>() &&  //
+                    var->Declaration()->Is<Let>() &&  //
                     var->Type()->Is<type::Pointer>()) {
                     op.expr = var->Declaration()->initializer;
                     continue;
@@ -129,7 +129,7 @@
     /// @returns the new program or SkipTransform if the transform is not required
     ApplyResult Run() {
         // A map of saved expressions to their saved variable name
-        utils::Hashmap<const ast::Expression*, Symbol, 8> saved_vars;
+        utils::Hashmap<const Expression*, Symbol, 8> saved_vars;
 
         bool needs_transform = false;
         for (auto* ty : ctx.src->Types()) {
@@ -146,8 +146,8 @@
         for (auto* node : ctx.src->ASTNodes().Objects()) {
             Switch(
                 node,  //
-                [&](const ast::VariableDeclStatement* let) {
-                    if (!let->variable->Is<ast::Let>()) {
+                [&](const VariableDeclStatement* let) {
+                    if (!let->variable->Is<Let>()) {
                         return;  // Not a `let` declaration. Ignore.
                     }
 
@@ -160,9 +160,9 @@
 
                     // Scan the initializer expression for array index expressions that need
                     // to be hoist to temporary "saved" variables.
-                    utils::Vector<const ast::VariableDeclStatement*, 8> saved;
+                    utils::Vector<const VariableDeclStatement*, 8> saved;
                     CollectSavedArrayIndices(
-                        var->Declaration()->initializer, [&](const ast::Expression* idx_expr) {
+                        var->Declaration()->initializer, [&](const Expression* idx_expr) {
                             // We have a sub-expression that needs to be saved.
                             // Create a new variable
                             auto saved_name = ctx.dst->Symbols().New(
@@ -205,8 +205,8 @@
                     // need for the original declaration to exist. Remove it.
                     RemoveStatement(ctx, let);
                 },
-                [&](const ast::UnaryOpExpression* op) {
-                    if (op->op == ast::UnaryOp::kAddressOf) {
+                [&](const UnaryOpExpression* op) {
+                    if (op->op == UnaryOp::kAddressOf) {
                         // Transform can be skipped if no address-of operator is used, as there
                         // will be no pointers that can be inlined.
                         needs_transform = true;
@@ -218,7 +218,7 @@
             return SkipTransform;
         }
 
-        // Register the ast::Expression transform handler.
+        // Register the Expression transform handler.
         // This performs two different transformations:
         // * Identifiers that resolve to the pointer-typed `let` declarations are
         // replaced with the recursively inlined initializer expression for the
@@ -226,7 +226,7 @@
         // * Sub-expressions inside the pointer-typed `let` initializer expression
         // that have been hoisted to a saved variable are replaced with the saved
         // variable identifier.
-        ctx.ReplaceAll([&](const ast::Expression* expr) -> const ast::Expression* {
+        ctx.ReplaceAll([&](const Expression* expr) -> const Expression* {
             // Look to see if we need to swap this Expression with a saved variable.
             if (auto saved_var = saved_vars.Find(expr)) {
                 return ctx.dst->Expr(*saved_var);
@@ -261,4 +261,4 @@
     return State(src).Run();
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/simplify_pointers.h b/src/tint/ast/transform/simplify_pointers.h
similarity index 85%
rename from src/tint/transform/simplify_pointers.h
rename to src/tint/ast/transform/simplify_pointers.h
index 8783d43..a4c67a5 100644
--- a/src/tint/transform/simplify_pointers.h
+++ b/src/tint/ast/transform/simplify_pointers.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_SIMPLIFY_POINTERS_H_
-#define SRC_TINT_TRANSFORM_SIMPLIFY_POINTERS_H_
+#ifndef SRC_TINT_AST_TRANSFORM_SIMPLIFY_POINTERS_H_
+#define SRC_TINT_AST_TRANSFORM_SIMPLIFY_POINTERS_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// SimplifyPointers is a Transform that moves all usage of function-scope
 /// `let` statements of a pointer type into their places of usage, while also
@@ -48,6 +48,6 @@
     struct State;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_SIMPLIFY_POINTERS_H_
+#endif  // SRC_TINT_AST_TRANSFORM_SIMPLIFY_POINTERS_H_
diff --git a/src/tint/transform/simplify_pointers_test.cc b/src/tint/ast/transform/simplify_pointers_test.cc
similarity index 96%
rename from src/tint/transform/simplify_pointers_test.cc
rename to src/tint/ast/transform/simplify_pointers_test.cc
index 4390c7b..adcf6dc 100644
--- a/src/tint/transform/simplify_pointers_test.cc
+++ b/src/tint/ast/transform/simplify_pointers_test.cc
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/simplify_pointers.h"
+#include "src/tint/ast/transform/simplify_pointers.h"
 
-#include "src/tint/transform/test_helper.h"
-#include "src/tint/transform/unshadow.h"
+#include "src/tint/ast/transform/test_helper.h"
+#include "src/tint/ast/transform/unshadow.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using SimplifyPointersTest = TransformTest;
@@ -392,4 +392,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/single_entry_point.cc b/src/tint/ast/transform/single_entry_point.cc
similarity index 85%
rename from src/tint/transform/single_entry_point.cc
rename to src/tint/ast/transform/single_entry_point.cc
index 5e80812..f896097 100644
--- a/src/tint/transform/single_entry_point.cc
+++ b/src/tint/ast/transform/single_entry_point.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/single_entry_point.h"
+#include "src/tint/ast/transform/single_entry_point.h"
 
 #include <unordered_set>
 #include <utility>
@@ -22,10 +22,10 @@
 #include "src/tint/sem/variable.h"
 #include "src/tint/switch.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::SingleEntryPoint);
-TINT_INSTANTIATE_TYPEINFO(tint::transform::SingleEntryPoint::Config);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::SingleEntryPoint);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::SingleEntryPoint::Config);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 SingleEntryPoint::SingleEntryPoint() = default;
 
@@ -45,7 +45,7 @@
     }
 
     // Find the target entry point.
-    const ast::Function* entry_point = nullptr;
+    const Function* entry_point = nullptr;
     for (auto* f : src->AST().Functions()) {
         if (!f->IsEntryPoint()) {
             continue;
@@ -69,7 +69,7 @@
     for (auto* decl : src->AST().GlobalDeclarations()) {
         Switch(
             decl,  //
-            [&](const ast::TypeDecl* ty) {
+            [&](const TypeDecl* ty) {
                 // Strip aliases that reference unused override declarations.
                 if (auto* arr = sem.Get(ty)->As<type::Array>()) {
                     auto* refs = sem.TransitivelyReferencedOverrides(arr);
@@ -85,9 +85,9 @@
                 // TODO(jrprice): Strip other unused types.
                 b.AST().AddTypeDecl(ctx.Clone(ty));
             },
-            [&](const ast::Override* override) {
+            [&](const Override* override) {
                 if (referenced_vars.Contains(sem.Get(override))) {
-                    if (!ast::HasAttribute<ast::IdAttribute>(override->attributes)) {
+                    if (!HasAttribute<IdAttribute>(override->attributes)) {
                         // If the override doesn't already have an @id() attribute, add one
                         // so that its allocated ID so that it won't be affected by other
                         // stripped away overrides
@@ -98,26 +98,24 @@
                     b.AST().AddGlobalVariable(ctx.Clone(override));
                 }
             },
-            [&](const ast::Var* var) {
+            [&](const Var* var) {
                 if (referenced_vars.Contains(sem.Get<sem::GlobalVariable>(var))) {
                     b.AST().AddGlobalVariable(ctx.Clone(var));
                 }
             },
-            [&](const ast::Const* c) {
+            [&](const Const* c) {
                 // Always keep 'const' declarations, as these can be used by attributes and array
                 // sizes, which are not tracked as transitively used by functions. They also don't
                 // typically get emitted by the backend unless they're actually used.
                 b.AST().AddGlobalVariable(ctx.Clone(c));
             },
-            [&](const ast::Function* func) {
+            [&](const Function* func) {
                 if (sem.Get(func)->HasAncestorEntryPoint(entry_point->name->symbol)) {
                     b.AST().AddFunction(ctx.Clone(func));
                 }
             },
-            [&](const ast::Enable* ext) { b.AST().AddEnable(ctx.Clone(ext)); },
-            [&](const ast::DiagnosticDirective* d) {
-                b.AST().AddDiagnosticDirective(ctx.Clone(d));
-            },
+            [&](const Enable* ext) { b.AST().AddEnable(ctx.Clone(ext)); },
+            [&](const DiagnosticDirective* d) { b.AST().AddDiagnosticDirective(ctx.Clone(d)); },
             [&](Default) {
                 TINT_UNREACHABLE(Transform, b.Diagnostics())
                     << "unhandled global declaration: " << decl->TypeInfo().name;
@@ -136,4 +134,4 @@
 SingleEntryPoint::Config::~Config() = default;
 SingleEntryPoint::Config& SingleEntryPoint::Config::operator=(const Config&) = default;
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/single_entry_point.h b/src/tint/ast/transform/single_entry_point.h
similarity index 86%
rename from src/tint/transform/single_entry_point.h
rename to src/tint/ast/transform/single_entry_point.h
index b91856b..69c38e3 100644
--- a/src/tint/transform/single_entry_point.h
+++ b/src/tint/ast/transform/single_entry_point.h
@@ -12,14 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_SINGLE_ENTRY_POINT_H_
-#define SRC_TINT_TRANSFORM_SINGLE_ENTRY_POINT_H_
+#ifndef SRC_TINT_AST_TRANSFORM_SINGLE_ENTRY_POINT_H_
+#define SRC_TINT_AST_TRANSFORM_SINGLE_ENTRY_POINT_H_
 
 #include <string>
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// Strip all but one entry point a module.
 ///
@@ -59,6 +59,6 @@
                       DataMap& outputs) const override;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_SINGLE_ENTRY_POINT_H_
+#endif  // SRC_TINT_AST_TRANSFORM_SINGLE_ENTRY_POINT_H_
diff --git a/src/tint/transform/single_entry_point_test.cc b/src/tint/ast/transform/single_entry_point_test.cc
similarity index 97%
rename from src/tint/transform/single_entry_point_test.cc
rename to src/tint/ast/transform/single_entry_point_test.cc
index f4f1dec..54c730f 100644
--- a/src/tint/transform/single_entry_point_test.cc
+++ b/src/tint/ast/transform/single_entry_point_test.cc
@@ -12,13 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/single_entry_point.h"
+#include "src/tint/ast/transform/single_entry_point.h"
 
 #include <utility>
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using SingleEntryPointTest = TransformTest;
@@ -26,7 +26,7 @@
 TEST_F(SingleEntryPointTest, Error_MissingTransformData) {
     auto* src = "";
 
-    auto* expect = "error: missing transform data for tint::transform::SingleEntryPoint";
+    auto* expect = "error: missing transform data for tint::ast::transform::SingleEntryPoint";
 
     auto got = Run<SingleEntryPoint>(src);
 
@@ -632,4 +632,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/spirv_atomic.cc b/src/tint/ast/transform/spirv_atomic.cc
similarity index 94%
rename from src/tint/transform/spirv_atomic.cc
rename to src/tint/ast/transform/spirv_atomic.cc
index d58d58b..aff4a7c 100644
--- a/src/tint/transform/spirv_atomic.cc
+++ b/src/tint/ast/transform/spirv_atomic.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/spirv_atomic.h"
+#include "src/tint/ast/transform/spirv_atomic.h"
 
 #include <string>
 #include <unordered_map>
@@ -31,10 +31,10 @@
 #include "src/tint/utils/map.h"
 #include "src/tint/utils/unique_vector.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::SpirvAtomic);
-TINT_INSTANTIATE_TYPEINFO(tint::transform::SpirvAtomic::Stub);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::SpirvAtomic);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::SpirvAtomic::Stub);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 using namespace tint::number_suffixes;  // NOLINT
 
@@ -70,7 +70,7 @@
         // Look for stub functions generated by the SPIR-V reader, which are used as placeholders
         // for atomic builtin calls.
         for (auto* fn : ctx.src->AST().Functions()) {
-            if (auto* stub = ast::GetAttribute<Stub>(fn->attributes)) {
+            if (auto* stub = GetAttribute<Stub>(fn->attributes)) {
                 auto* sem = ctx.src->Sem().Get(fn);
 
                 for (auto* call : sem->CallSites()) {
@@ -121,14 +121,14 @@
 
         // If we need to change structure members, then fork them.
         if (!forked_structs.empty()) {
-            ctx.ReplaceAll([&](const ast::Struct* str) {
+            ctx.ReplaceAll([&](const Struct* str) {
                 // Is `str` a structure we need to fork?
                 auto* str_ty = ctx.src->Sem().Get(str);
                 if (auto it = forked_structs.find(str_ty); it != forked_structs.end()) {
                     const auto& forked = it->second;
 
                     // Re-create the structure swapping in the atomic-flavoured members
-                    utils::Vector<const ast::StructMember*, 8> members;
+                    utils::Vector<const StructMember*, 8> members;
                     members.Reserve(str->members.Length());
                     for (size_t i = 0; i < str->members.Length(); i++) {
                         auto* member = str->members[i];
@@ -187,14 +187,14 @@
                     atomic_expressions.Add(index->Object());
                 },
                 [&](const sem::ValueExpression* e) {
-                    if (auto* unary = e->Declaration()->As<ast::UnaryOpExpression>()) {
+                    if (auto* unary = e->Declaration()->As<UnaryOpExpression>()) {
                         atomic_expressions.Add(ctx.src->Sem().GetVal(unary->expr));
                     }
                 });
         }
     }
 
-    ast::Type AtomicTypeFor(const type::Type* ty) {
+    Type AtomicTypeFor(const type::Type* ty) {
         return Switch(
             ty,  //
             [&](const type::I32*) { return b.ty.atomic(CreateASTTypeFor(ctx, ty)); },
@@ -221,7 +221,7 @@
             [&](const type::Reference* ref) { return AtomicTypeFor(ref->StoreType()); },
             [&](Default) {
                 TINT_ICE(Transform, b.Diagnostics()) << "unhandled type: " << ty->FriendlyName();
-                return ast::Type{};
+                return Type{};
             });
     }
 
@@ -249,7 +249,7 @@
             for (auto* vu : atomic_var->Users()) {
                 Switch(
                     vu->Stmt()->Declaration(),
-                    [&](const ast::AssignmentStatement* assign) {
+                    [&](const AssignmentStatement* assign) {
                         auto* sem_lhs = ctx.src->Sem().GetVal(assign->lhs);
                         if (is_ref_to_atomic_var(sem_lhs)) {
                             ctx.Replace(assign, [=] {
@@ -272,7 +272,7 @@
                             return;
                         }
                     },
-                    [&](const ast::VariableDeclStatement* decl) {
+                    [&](const VariableDeclStatement* decl) {
                         auto* var = decl->variable;
                         if (auto* sem_init = ctx.src->Sem().GetVal(var->initializer)) {
                             if (is_ref_to_atomic_var(sem_init->UnwrapLoad())) {
@@ -293,7 +293,7 @@
 SpirvAtomic::SpirvAtomic() = default;
 SpirvAtomic::~SpirvAtomic() = default;
 
-SpirvAtomic::Stub::Stub(ProgramID pid, ast::NodeID nid, builtin::Function b)
+SpirvAtomic::Stub::Stub(ProgramID pid, NodeID nid, builtin::Function b)
     : Base(pid, nid, utils::Empty), builtin(b) {}
 SpirvAtomic::Stub::~Stub() = default;
 std::string SpirvAtomic::Stub::InternalName() const {
@@ -309,4 +309,4 @@
     return State{src}.Run();
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/spirv_atomic.h b/src/tint/ast/transform/spirv_atomic.h
similarity index 85%
rename from src/tint/transform/spirv_atomic.h
rename to src/tint/ast/transform/spirv_atomic.h
index 907996b..4ada485 100644
--- a/src/tint/transform/spirv_atomic.h
+++ b/src/tint/ast/transform/spirv_atomic.h
@@ -12,21 +12,21 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_SPIRV_ATOMIC_H_
-#define SRC_TINT_TRANSFORM_SPIRV_ATOMIC_H_
+#ifndef SRC_TINT_AST_TRANSFORM_SPIRV_ATOMIC_H_
+#define SRC_TINT_AST_TRANSFORM_SPIRV_ATOMIC_H_
 
 #include <string>
 
 #include "src/tint/ast/internal_attribute.h"
+#include "src/tint/ast/transform/transform.h"
 #include "src/tint/builtin/function.h"
-#include "src/tint/transform/transform.h"
 
 // Forward declarations
 namespace tint {
 class CloneContext;
 }  // namespace tint
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// SpirvAtomic is a transform that replaces calls to stub functions created by the SPIR-V reader
 /// with calls to the WGSL atomic builtin. It also makes sure to replace variable declarations that
@@ -41,12 +41,12 @@
 
     /// Stub is an attribute applied to stub SPIR-V reader generated functions that need to be
     /// translated to an atomic builtin.
-    class Stub final : public utils::Castable<Stub, ast::InternalAttribute> {
+    class Stub final : public utils::Castable<Stub, InternalAttribute> {
       public:
         /// @param pid the identifier of the program that owns this node
         /// @param nid the unique node identifier
         /// @param builtin the atomic builtin this stub represents
-        Stub(ProgramID pid, ast::NodeID nid, builtin::Function builtin);
+        Stub(ProgramID pid, NodeID nid, builtin::Function builtin);
         /// Destructor
         ~Stub() override;
 
@@ -72,6 +72,6 @@
     struct State;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_SPIRV_ATOMIC_H_
+#endif  // SRC_TINT_AST_TRANSFORM_SPIRV_ATOMIC_H_
diff --git a/src/tint/transform/spirv_atomic_test.cc b/src/tint/ast/transform/spirv_atomic_test.cc
similarity index 99%
rename from src/tint/transform/spirv_atomic_test.cc
rename to src/tint/ast/transform/spirv_atomic_test.cc
index 29976b5..ea0889d 100644
--- a/src/tint/transform/spirv_atomic_test.cc
+++ b/src/tint/ast/transform/spirv_atomic_test.cc
@@ -12,19 +12,19 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/spirv_atomic.h"
+#include "src/tint/ast/transform/spirv_atomic.h"
 
 #include <memory>
 #include <string>
 #include <utility>
 #include <vector>
 
+#include "src/tint/ast/transform/test_helper.h"
 #include "src/tint/reader/wgsl/parser_impl.h"
-#include "src/tint/transform/test_helper.h"
 
 using namespace tint::number_suffixes;  // NOLINT
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 class SpirvAtomicTest : public TransformTest {
@@ -1377,4 +1377,4 @@
     EXPECT_EQ(expect, str(got));
 }
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/std140.cc b/src/tint/ast/transform/std140.cc
similarity index 94%
rename from src/tint/transform/std140.cc
rename to src/tint/ast/transform/std140.cc
index fed3943..69f7a1f 100644
--- a/src/tint/transform/std140.cc
+++ b/src/tint/ast/transform/std140.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/std140.h"
+#include "src/tint/ast/transform/std140.h"
 
 #include <algorithm>
 #include <string>
@@ -30,7 +30,7 @@
 #include "src/tint/utils/hashmap.h"
 #include "src/tint/utils/transform.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::Std140);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::Std140);
 
 using namespace tint::number_suffixes;  // NOLINT
 
@@ -77,7 +77,7 @@
 
 }  // namespace tint::utils
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// PIMPL state for the transform
 struct Std140::State {
@@ -102,7 +102,7 @@
 
         // Finally, replace all expression chains that used the authored types with those that
         // correctly use the forked types.
-        ctx.ReplaceAll([&](const ast::Expression* expr) -> const ast::Expression* {
+        ctx.ReplaceAll([&](const Expression* expr) -> const Expression* {
             if (auto access = AccessChainFor(expr)) {
                 if (!access->std140_mat_idx.has_value()) {
                     // loading a std140 type, which is not a whole or partial decomposed matrix
@@ -230,7 +230,7 @@
 
     // Map of structure member in src of a matrix type, to list of decomposed column
     // members in ctx.dst.
-    utils::Hashmap<const type::StructMember*, utils::Vector<const ast::StructMember*, 4>, 8>
+    utils::Hashmap<const type::StructMember*, utils::Vector<const StructMember*, 4>, 8>
         std140_mat_members;
 
     /// Describes a matrix that has been forked to a std140-structure holding the decomposed column
@@ -284,7 +284,7 @@
             if (str && str->UsedAs(builtin::AddressSpace::kUniform)) {
                 // Should this uniform buffer be forked for std140 usage?
                 bool fork_std140 = false;
-                utils::Vector<const ast::StructMember*, 8> members;
+                utils::Vector<const StructMember*, 8> members;
                 for (auto* member : str->Members()) {
                     if (auto* mat = member->Type()->As<type::Matrix>()) {
                         // Is this member a matrix that needs decomposition for std140-layout?
@@ -335,8 +335,8 @@
                     // Create a new forked structure, and insert it just under the original
                     // structure.
                     auto name = b.Symbols().New(str->Name().Name() + "_std140");
-                    auto* std140 = b.create<ast::Struct>(b.Ident(name), std::move(members),
-                                                         ctx.Clone(str->Declaration()->attributes));
+                    auto* std140 = b.create<Struct>(b.Ident(name), std::move(members),
+                                                    ctx.Clone(str->Declaration()->attributes));
                     ctx.InsertAfter(src->AST().GlobalDeclarations(), global, std140);
                     std140_structs.Add(str, name);
                 }
@@ -349,7 +349,7 @@
     /// Populates the #std140_uniforms set.
     void ReplaceUniformVarTypes() {
         for (auto* global : src->AST().GlobalVariables()) {
-            if (auto* var = global->As<ast::Var>()) {
+            if (auto* var = global->As<Var>()) {
                 auto* v = sem.Get(var);
                 if (v->AddressSpace() == builtin::AddressSpace::kUniform) {
                     if (auto std140_ty = Std140Type(v->Type()->UnwrapRef())) {
@@ -367,9 +367,7 @@
     /// @param str the structure that will hold the uniquely named member.
     /// @param unsuffixed the common name prefix to use for the new members.
     /// @param count the number of members that need to be created.
-    std::string PrefixForUniqueNames(const ast::Struct* str,
-                                     Symbol unsuffixed,
-                                     uint32_t count) const {
+    std::string PrefixForUniqueNames(const Struct* str, Symbol unsuffixed, uint32_t count) const {
         auto prefix = unsuffixed.Name();
         // Keep on inserting '_' between the unsuffixed name and the suffix numbers until the name
         // is unique.
@@ -400,14 +398,14 @@
     ///          If the semantic type is not split for std140-layout, then nullptr is returned.
     /// @note will construct new std140 structures to hold decomposed matrices, populating
     ///       #std140_mats.
-    ast::Type Std140Type(const type::Type* ty) {
+    Type Std140Type(const type::Type* ty) {
         return Switch(
             ty,  //
             [&](const type::Struct* str) {
                 if (auto std140 = std140_structs.Find(str)) {
                     return b.ty(*std140);
                 }
-                return ast::Type{};
+                return Type{};
             },
             [&](const type::Matrix* mat) {
                 if (MatrixNeedsDecomposing(mat)) {
@@ -426,13 +424,13 @@
                     });
                     return b.ty(std140_mat.name);
                 }
-                return ast::Type{};
+                return Type{};
             },
             [&](const type::Array* arr) {
                 if (auto std140 = Std140Type(arr->ElemType())) {
-                    utils::Vector<const ast::Attribute*, 1> attrs;
+                    utils::Vector<const Attribute*, 1> attrs;
                     if (!arr->IsStrideImplicit()) {
-                        attrs.Push(b.create<ast::StrideAttribute>(arr->Stride()));
+                        attrs.Push(b.create<StrideAttribute>(arr->Stride()));
                     }
                     auto count = arr->ConstantCount();
                     if (TINT_UNLIKELY(!count)) {
@@ -446,7 +444,7 @@
                     }
                     return b.ty.array(std140, b.Expr(u32(count.value())), std::move(attrs));
                 }
-                return ast::Type{};
+                return Type{};
             });
     }
 
@@ -455,7 +453,7 @@
     /// @param align the alignment in bytes of the matrix.
     /// @param size the size in bytes of the matrix.
     /// @returns a vector of decomposed matrix column vectors as structure members (in ctx.dst).
-    utils::Vector<const ast::StructMember*, 4> DecomposedMatrixStructMembers(
+    utils::Vector<const StructMember*, 4> DecomposedMatrixStructMembers(
         const type::Matrix* mat,
         const std::string& name_prefix,
         uint32_t align,
@@ -463,9 +461,9 @@
         // Replace the member with column vectors.
         const auto num_columns = mat->columns();
         // Build a struct member for each column of the matrix
-        utils::Vector<const ast::StructMember*, 4> out;
+        utils::Vector<const StructMember*, 4> out;
         for (uint32_t i = 0; i < num_columns; i++) {
-            utils::Vector<const ast::Attribute*, 1> attributes;
+            utils::Vector<const Attribute*, 1> attributes;
             if ((i == 0) && mat->Align() != align) {
                 // The matrix was @align() annotated with a larger alignment
                 // than the natural alignment for the matrix. This extra padding
@@ -493,7 +491,7 @@
     /// Walks the @p ast_expr, constructing and returning an AccessChain.
     /// @returns an AccessChain if the expression is an access to a std140-forked uniform buffer,
     ///          otherwise returns a std::nullopt.
-    std::optional<AccessChain> AccessChainFor(const ast::Expression* ast_expr) {
+    std::optional<AccessChain> AccessChainFor(const Expression* ast_expr) {
         auto* expr = sem.GetVal(ast_expr);
         if (!expr) {
             return std::nullopt;
@@ -576,10 +574,10 @@
                 [&](const sem::ValueExpression* e) {
                     // Walk past indirection and address-of unary ops.
                     return Switch(e->Declaration(),  //
-                                  [&](const ast::UnaryOpExpression* u) {
+                                  [&](const UnaryOpExpression* u) {
                                       switch (u->op) {
-                                          case ast::UnaryOp::kAddressOf:
-                                          case ast::UnaryOp::kIndirection:
+                                          case UnaryOp::kAddressOf:
+                                          case UnaryOp::kIndirection:
                                               expr = sem.GetVal(u->expr);
                                               return Action::kContinue;
                                           default:
@@ -660,8 +658,8 @@
     /// Generates and returns an expression that loads the value from a std140 uniform buffer,
     /// converting the final result to a non-std140 type.
     /// @param chain the access chain from a uniform buffer to the value to load.
-    const ast::Expression* LoadWithConvert(const AccessChain& chain) {
-        const ast::Expression* expr = nullptr;
+    const Expression* LoadWithConvert(const AccessChain& chain) {
+        const Expression* expr = nullptr;
         const type::Type* ty = nullptr;
         auto dynamic_index = [&](size_t idx) {
             return ctx.Clone(chain.dynamic_indices[idx]->Declaration());
@@ -678,7 +676,7 @@
     /// std140-forked type to the type @p ty. If @p expr is not a std140-forked type, then Convert()
     /// will simply return @p expr.
     /// @returns the converted value expression.
-    const ast::Expression* Convert(const type::Type* ty, const ast::Expression* expr) {
+    const Expression* Convert(const type::Type* ty, const Expression* expr) {
         // Get an existing, or create a new function for converting the std140 type to ty.
         auto fn = conv_fns.GetOrCreate(ty, [&] {
             auto std140_ty = Std140Type(ty);
@@ -690,20 +688,20 @@
             // The converter function takes a single argument of the std140 type.
             auto* param = b.Param("val", std140_ty);
 
-            utils::Vector<const ast::Statement*, 3> stmts;
+            utils::Vector<const Statement*, 3> stmts;
 
             Switch(
                 ty,  //
                 [&](const type::Struct* str) {
                     // Convert each of the structure members using either a converter function
                     // call, or by reassembling a std140 matrix from column vector members.
-                    utils::Vector<const ast::Expression*, 8> args;
+                    utils::Vector<const Expression*, 8> args;
                     for (auto* member : str->Members()) {
                         if (auto col_members = std140_mat_members.Find(member)) {
                             // std140 decomposed matrix. Reassemble.
                             auto mat_ty = CreateASTTypeFor(ctx, member->Type());
                             auto mat_args =
-                                utils::Transform(*col_members, [&](const ast::StructMember* m) {
+                                utils::Transform(*col_members, [&](const StructMember* m) {
                                     return b.MemberAccessor(param, m->name->symbol);
                                 });
                             args.Push(b.Call(mat_ty, std::move(mat_args)));
@@ -719,7 +717,7 @@
                     // Reassemble a std140 matrix from the structure of column vector members.
                     auto std140_mat = std140_mats.Get(mat);
                     if (TINT_LIKELY(std140_mat)) {
-                        utils::Vector<const ast::Expression*, 8> args;
+                        utils::Vector<const Expression*, 8> args;
                         // std140 decomposed matrix. Reassemble.
                         auto mat_ty = CreateASTTypeFor(ctx, mat);
                         auto mat_args = utils::Transform(std140_mat->columns, [&](Symbol name) {
@@ -782,7 +780,7 @@
     /// @param access the access chain from the uniform buffer to either the whole matrix or part of
     ///        the matrix (column, column-swizzle, or element).
     /// @returns the loaded value expression.
-    const ast::Expression* LoadMatrixWithFn(const AccessChain& access) {
+    const Expression* LoadMatrixWithFn(const AccessChain& access) {
         // Get an existing, or create a new function for loading the uniform buffer value.
         // This function is keyed off the uniform buffer variable and the access chain.
         auto fn = load_fns.GetOrCreate(LoadFnKey{access.var, access.indices}, [&] {
@@ -810,14 +808,14 @@
     ///               column-swizzle, or element).
     /// @note The matrix column must be statically indexed to use this method.
     /// @returns the loaded value expression.
-    const ast::Expression* LoadSubMatrixInline(const AccessChain& chain) {
+    const Expression* LoadSubMatrixInline(const AccessChain& chain) {
         // Method for generating dynamic index expressions.
         // As this is inline, we can just clone the expression.
         auto dynamic_index = [&](size_t idx) {
             return ctx.Clone(chain.dynamic_indices[idx]->Declaration());
         };
 
-        const ast::Expression* expr = nullptr;
+        const Expression* expr = nullptr;
         const type::Type* ty = nullptr;
 
         // Build the expression up to, but not including the matrix member
@@ -891,7 +889,7 @@
         std::string name = "load";
 
         // The switch cases
-        utils::Vector<const ast::CaseStatement*, 4> cases;
+        utils::Vector<const CaseStatement*, 4> cases;
 
         // The function return type.
         const type::Type* ret_ty = nullptr;
@@ -899,7 +897,7 @@
         // Build switch() cases for each column of the matrix
         auto num_columns = chain.std140_mat_ty->columns();
         for (uint32_t column_idx = 0; column_idx < num_columns; column_idx++) {
-            const ast::Expression* expr = nullptr;
+            const Expression* expr = nullptr;
             const type::Type* ty = nullptr;
 
             // Build the expression up to, but not including the matrix
@@ -991,7 +989,7 @@
             return b.Expr(dynamic_index_params[idx]->name->symbol);
         };
 
-        const ast::Expression* expr = nullptr;
+        const Expression* expr = nullptr;
         const type::Type* ty = nullptr;
         std::string name = "load";
 
@@ -1005,13 +1003,13 @@
             name += "_" + access_name;
         }
 
-        utils::Vector<const ast::Statement*, 2> stmts;
+        utils::Vector<const Statement*, 2> stmts;
 
         // Create a temporary pointer to the structure that holds the matrix columns
         auto* let = b.Let("s", b.AddressOf(expr));
         stmts.Push(b.Decl(let));
 
-        utils::Vector<const ast::MemberAccessorExpression*, 4> columns;
+        utils::Vector<const MemberAccessorExpression*, 4> columns;
         if (auto* str = tint::As<type::Struct>(ty)) {
             // Structure member matrix. The columns are decomposed into the structure.
             auto mat_member_idx = std::get<u32>(chain.indices[std140_mat_idx]);
@@ -1053,7 +1051,7 @@
     /// Return type of BuildAccessExpr()
     struct ExprTypeName {
         /// The new, post-access expression
-        const ast::Expression* expr;
+        const Expression* expr;
         /// The type of #expr
         const type::Type* type;
         /// A name segment which can be used to build sensible names for helper functions
@@ -1067,11 +1065,11 @@
     /// @param dynamic_index a function that obtains the i'th dynamic index
     /// @returns a ExprTypeName which holds the new expression, new type and a name segment which
     ///          can be used for creating helper function names.
-    ExprTypeName BuildAccessExpr(const ast::Expression* lhs,
+    ExprTypeName BuildAccessExpr(const Expression* lhs,
                                  const type::Type* ty,
                                  const AccessChain& chain,
                                  size_t index,
-                                 std::function<const ast::Expression*(size_t)> dynamic_index) {
+                                 std::function<const Expression*(size_t)> dynamic_index) {
         auto& access = chain.indices[index];
 
         if (std::get_if<UniformVariable>(&access)) {
@@ -1168,4 +1166,4 @@
     return State(src).Run();
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/std140.h b/src/tint/ast/transform/std140.h
similarity index 87%
rename from src/tint/transform/std140.h
rename to src/tint/ast/transform/std140.h
index ab1b31e..a07885f 100644
--- a/src/tint/transform/std140.h
+++ b/src/tint/ast/transform/std140.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_STD140_H_
-#define SRC_TINT_TRANSFORM_STD140_H_
+#ifndef SRC_TINT_AST_TRANSFORM_STD140_H_
+#define SRC_TINT_AST_TRANSFORM_STD140_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// Std140 is a transform that forks types used in the uniform address space that contain
 /// `matNx2<f32>` matrices into `N`x`vec2<f32>` column vectors, and `matNxM<f16>` matrices into
@@ -44,6 +44,6 @@
     struct State;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_STD140_H_
+#endif  // SRC_TINT_AST_TRANSFORM_STD140_H_
diff --git a/src/tint/transform/std140_exhaustive_test.cc b/src/tint/ast/transform/std140_exhaustive_test.cc
similarity index 99%
rename from src/tint/transform/std140_exhaustive_test.cc
rename to src/tint/ast/transform/std140_exhaustive_test.cc
index f50e1c4..417d028 100644
--- a/src/tint/transform/std140_exhaustive_test.cc
+++ b/src/tint/ast/transform/std140_exhaustive_test.cc
@@ -12,16 +12,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/std140.h"
+#include "src/tint/ast/transform/std140.h"
 
 #include <string>
 #include <utility>
 #include <vector>
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 #include "src/tint/utils/string.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 enum class MatrixType { f32, f16 };
@@ -4887,4 +4887,4 @@
                          }));
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/std140_f16_test.cc b/src/tint/ast/transform/std140_f16_test.cc
similarity index 99%
rename from src/tint/transform/std140_f16_test.cc
rename to src/tint/ast/transform/std140_f16_test.cc
index 898bb73..ce30e70 100644
--- a/src/tint/transform/std140_f16_test.cc
+++ b/src/tint/ast/transform/std140_f16_test.cc
@@ -12,16 +12,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/std140.h"
+#include "src/tint/ast/transform/std140.h"
 
 #include <string>
 #include <utility>
 #include <vector>
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 #include "src/tint/utils/string.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using Std140Test_F16 = TransformTest;
@@ -3593,4 +3593,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/std140_f32_test.cc b/src/tint/ast/transform/std140_f32_test.cc
similarity index 99%
rename from src/tint/transform/std140_f32_test.cc
rename to src/tint/ast/transform/std140_f32_test.cc
index b0bd467..4819420 100644
--- a/src/tint/transform/std140_f32_test.cc
+++ b/src/tint/ast/transform/std140_f32_test.cc
@@ -12,16 +12,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/std140.h"
+#include "src/tint/ast/transform/std140.h"
 
 #include <string>
 #include <utility>
 #include <vector>
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 #include "src/tint/utils/string.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using Std140Test_F32 = TransformTest;
@@ -3356,4 +3356,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/std140_test.cc b/src/tint/ast/transform/std140_test.cc
similarity index 96%
rename from src/tint/transform/std140_test.cc
rename to src/tint/ast/transform/std140_test.cc
index 73221bc..28e9fc7 100644
--- a/src/tint/transform/std140_test.cc
+++ b/src/tint/ast/transform/std140_test.cc
@@ -12,13 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/std140.h"
+#include "src/tint/ast/transform/std140.h"
 
 #include <string>
 #include <utility>
 #include <vector>
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 #include "src/tint/utils/string.h"
 
 // This file contains the should-run tests and a trival empty module test for Std140 transform.
@@ -27,7 +27,7 @@
 // transform on all shape of both f32 and f16 matricies and loop on all valid literal index when
 // required, please refer to std140_exhaustive_test.cc.
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using Std140Test = TransformTest;
@@ -197,4 +197,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/substitute_override.cc b/src/tint/ast/transform/substitute_override.cc
similarity index 89%
rename from src/tint/transform/substitute_override.cc
rename to src/tint/ast/transform/substitute_override.cc
index 04a9da0..fed559b 100644
--- a/src/tint/transform/substitute_override.cc
+++ b/src/tint/ast/transform/substitute_override.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/substitute_override.h"
+#include "src/tint/ast/transform/substitute_override.h"
 
 #include <functional>
 #include <utility>
@@ -24,15 +24,15 @@
 #include "src/tint/sem/variable.h"
 #include "src/tint/switch.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::SubstituteOverride);
-TINT_INSTANTIATE_TYPEINFO(tint::transform::SubstituteOverride::Config);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::SubstituteOverride);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::SubstituteOverride::Config);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 bool ShouldRun(const Program* program) {
     for (auto* node : program->AST().GlobalVariables()) {
-        if (node->Is<ast::Override>()) {
+        if (node->Is<Override>()) {
             return true;
         }
     }
@@ -61,12 +61,12 @@
         return SkipTransform;
     }
 
-    ctx.ReplaceAll([&](const ast::Override* w) -> const ast::Const* {
+    ctx.ReplaceAll([&](const Override* w) -> const Const* {
         auto* sem = ctx.src->Sem().Get(w);
 
         auto source = ctx.Clone(w->source);
         auto sym = ctx.Clone(w->name->symbol);
-        ast::Type ty = w->type ? ctx.Clone(w->type) : ast::Type{};
+        Type ty = w->type ? ctx.Clone(w->type) : Type{};
 
         // No replacement provided, just clone the override node as a const.
         auto iter = data->map.find(sem->OverrideId());
@@ -102,7 +102,7 @@
     // If the object is not materialized, and the 'override' variable is turned to a 'const', the
     // resulting type of the index may change. See: crbug.com/tint/1697.
     ctx.ReplaceAll(
-        [&](const ast::IndexAccessorExpression* expr) -> const ast::IndexAccessorExpression* {
+        [&](const IndexAccessorExpression* expr) -> const IndexAccessorExpression* {
             if (auto* sem = src->Sem().Get(expr)) {
                 if (auto* access = sem->UnwrapMaterialize()->As<sem::IndexAccessorExpression>()) {
                     if (access->Object()->UnwrapMaterialize()->Type()->HoldsAbstract() &&
@@ -128,4 +128,4 @@
 
 SubstituteOverride::Config& SubstituteOverride::Config::operator=(const Config&) = default;
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/substitute_override.h b/src/tint/ast/transform/substitute_override.h
similarity index 88%
rename from src/tint/transform/substitute_override.h
rename to src/tint/ast/transform/substitute_override.h
index 10200ca..7734973 100644
--- a/src/tint/transform/substitute_override.h
+++ b/src/tint/ast/transform/substitute_override.h
@@ -12,18 +12,18 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_SUBSTITUTE_OVERRIDE_H_
-#define SRC_TINT_TRANSFORM_SUBSTITUTE_OVERRIDE_H_
+#ifndef SRC_TINT_AST_TRANSFORM_SUBSTITUTE_OVERRIDE_H_
+#define SRC_TINT_AST_TRANSFORM_SUBSTITUTE_OVERRIDE_H_
 
 #include <string>
 #include <unordered_map>
 
 #include "tint/override_id.h"
 
+#include "src/tint/ast/transform/transform.h"
 #include "src/tint/reflection.h"
-#include "src/tint/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// A transform that replaces overrides with the constant values provided.
 ///
@@ -81,6 +81,6 @@
                       DataMap& outputs) const override;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_SUBSTITUTE_OVERRIDE_H_
+#endif  // SRC_TINT_AST_TRANSFORM_SUBSTITUTE_OVERRIDE_H_
diff --git a/src/tint/transform/substitute_override_test.cc b/src/tint/ast/transform/substitute_override_test.cc
similarity index 97%
rename from src/tint/transform/substitute_override_test.cc
rename to src/tint/ast/transform/substitute_override_test.cc
index 5deab72..01d9597 100644
--- a/src/tint/transform/substitute_override_test.cc
+++ b/src/tint/ast/transform/substitute_override_test.cc
@@ -12,11 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/substitute_override.h"
+#include "src/tint/ast/transform/substitute_override.h"
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using SubstituteOverrideTest = TransformTest;
@@ -290,4 +290,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/test_helper.h b/src/tint/ast/transform/test_helper.h
similarity index 95%
rename from src/tint/transform/test_helper.h
rename to src/tint/ast/transform/test_helper.h
index ac48c5f..08b8e30 100644
--- a/src/tint/transform/test_helper.h
+++ b/src/tint/ast/transform/test_helper.h
@@ -12,8 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_TEST_HELPER_H_
-#define SRC_TINT_TRANSFORM_TEST_HELPER_H_
+#ifndef SRC_TINT_AST_TRANSFORM_TEST_HELPER_H_
+#define SRC_TINT_AST_TRANSFORM_TEST_HELPER_H_
 
 #include <memory>
 #include <string>
@@ -25,7 +25,7 @@
 #include "src/tint/transform/manager.h"
 #include "src/tint/writer/wgsl/generator.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// @param program the program to get an output WGSL string from
 /// @returns the output program as a WGSL string, or an error string if the
@@ -103,7 +103,7 @@
             return Output(std::move(program));
         }
 
-        Manager manager;
+        tint::transform::Manager manager;
         for (auto* transform_ptr : std::initializer_list<Transform*>{new TRANSFORMS()...}) {
             manager.append(std::unique_ptr<Transform>(transform_ptr));
         }
@@ -160,6 +160,6 @@
 template <typename T>
 using TransformTestWithParam = TransformTestBase<testing::TestWithParam<T>>;
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_TEST_HELPER_H_
+#endif  // SRC_TINT_AST_TRANSFORM_TEST_HELPER_H_
diff --git a/src/tint/transform/texture_1d_to_2d.cc b/src/tint/ast/transform/texture_1d_to_2d.cc
similarity index 88%
rename from src/tint/transform/texture_1d_to_2d.cc
rename to src/tint/ast/transform/texture_1d_to_2d.cc
index 7c48db5..bbe4855 100644
--- a/src/tint/transform/texture_1d_to_2d.cc
+++ b/src/tint/ast/transform/texture_1d_to_2d.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/texture_1d_to_2d.h"
+#include "src/tint/ast/transform/texture_1d_to_2d.h"
 
 #include <utility>
 
@@ -23,11 +23,11 @@
 #include "src/tint/switch.h"
 #include "src/tint/type/texture_dimension.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::Texture1DTo2D);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::Texture1DTo2D);
 
 using namespace tint::number_suffixes;  // NOLINT
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 namespace {
 
@@ -85,18 +85,18 @@
             return SkipTransform;
         }
 
-        auto create_var = [&](const ast::Variable* v, ast::Type type) -> const ast::Variable* {
-            if (v->As<ast::Parameter>()) {
+        auto create_var = [&](const Variable* v, Type type) -> const Variable* {
+            if (v->As<Parameter>()) {
                 return ctx.dst->Param(ctx.Clone(v->name->symbol), type, ctx.Clone(v->attributes));
             } else {
                 return ctx.dst->Var(ctx.Clone(v->name->symbol), type, ctx.Clone(v->attributes));
             }
         };
 
-        ctx.ReplaceAll([&](const ast::Variable* v) -> const ast::Variable* {
-            const ast::Variable* r = Switch(
+        ctx.ReplaceAll([&](const Variable* v) -> const Variable* {
+            const Variable* r = Switch(
                 sem.Get(v)->Type()->UnwrapRef(),
-                [&](const type::SampledTexture* tex) -> const ast::Variable* {
+                [&](const type::SampledTexture* tex) -> const Variable* {
                     if (tex->dim() == type::TextureDimension::k1d) {
                         auto type = ctx.dst->ty.sampled_texture(type::TextureDimension::k2d,
                                                                 CreateASTTypeFor(ctx, tex->type()));
@@ -105,7 +105,7 @@
                         return nullptr;
                     }
                 },
-                [&](const type::StorageTexture* storage_tex) -> const ast::Variable* {
+                [&](const type::StorageTexture* storage_tex) -> const Variable* {
                     if (storage_tex->dim() == type::TextureDimension::k1d) {
                         auto type = ctx.dst->ty.storage_texture(type::TextureDimension::k2d,
                                                                 storage_tex->texel_format(),
@@ -119,7 +119,7 @@
             return r;
         });
 
-        ctx.ReplaceAll([&](const ast::CallExpression* c) -> const ast::Expression* {
+        ctx.ReplaceAll([&](const CallExpression* c) -> const Expression* {
             auto* call = sem.Get(c)->UnwrapMaterialize()->As<sem::Call>();
             if (!call) {
                 return nullptr;
@@ -141,7 +141,7 @@
             if (builtin->Type() == builtin::Function::kTextureDimensions) {
                 // If this textureDimensions() call is in a CallStatement, we can leave it
                 // unmodified since the return value will be dropped on the floor anyway.
-                if (call->Stmt()->Declaration()->Is<ast::CallStatement>()) {
+                if (call->Stmt()->Declaration()->Is<CallStatement>()) {
                     return nullptr;
                 }
                 auto* new_call = ctx.CloneWithoutTransform(c);
@@ -153,14 +153,14 @@
                 return nullptr;
             }
 
-            utils::Vector<const ast::Expression*, 8> args;
+            utils::Vector<const Expression*, 8> args;
             int index = 0;
             for (auto* arg : c->args) {
                 if (index == coords_index) {
                     auto* ctype = call->Arguments()[static_cast<size_t>(coords_index)]->Type();
                     auto* coords = c->args[static_cast<size_t>(coords_index)];
 
-                    const ast::LiteralExpression* half = nullptr;
+                    const LiteralExpression* half = nullptr;
                     if (ctype->is_integer_scalar()) {
                         half = ctx.dst->Expr(0_a);
                     } else {
@@ -189,4 +189,4 @@
     return State(src).Run();
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/texture_1d_to_2d.h b/src/tint/ast/transform/texture_1d_to_2d.h
similarity index 80%
rename from src/tint/transform/texture_1d_to_2d.h
rename to src/tint/ast/transform/texture_1d_to_2d.h
index c742e2a..2c43adf 100644
--- a/src/tint/transform/texture_1d_to_2d.h
+++ b/src/tint/ast/transform/texture_1d_to_2d.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_TEXTURE_1D_TO_2D_H_
-#define SRC_TINT_TRANSFORM_TEXTURE_1D_TO_2D_H_
+#ifndef SRC_TINT_AST_TRANSFORM_TEXTURE_1D_TO_2D_H_
+#define SRC_TINT_AST_TRANSFORM_TEXTURE_1D_TO_2D_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// This transform converts all 1D texture types and accesses to 2D.
 /// This is required for GLSL ES, which does not support 1D textures.
@@ -38,6 +38,6 @@
     struct State;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_TEXTURE_1D_TO_2D_H_
+#endif  // SRC_TINT_AST_TRANSFORM_TEXTURE_1D_TO_2D_H_
diff --git a/src/tint/transform/texture_1d_to_2d_test.cc b/src/tint/ast/transform/texture_1d_to_2d_test.cc
similarity index 97%
rename from src/tint/transform/texture_1d_to_2d_test.cc
rename to src/tint/ast/transform/texture_1d_to_2d_test.cc
index b68b51e..75da6fc 100644
--- a/src/tint/transform/texture_1d_to_2d_test.cc
+++ b/src/tint/ast/transform/texture_1d_to_2d_test.cc
@@ -12,10 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/texture_1d_to_2d.h"
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/texture_1d_to_2d.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using Texture1DTo2DTest = TransformTest;
@@ -297,4 +297,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/transform.cc b/src/tint/ast/transform/transform.cc
similarity index 90%
rename from src/tint/transform/transform.cc
rename to src/tint/ast/transform/transform.cc
index 453768f..2270aff 100644
--- a/src/tint/transform/transform.cc
+++ b/src/tint/ast/transform/transform.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
 #include <algorithm>
 #include <string>
@@ -27,10 +27,10 @@
 #include "src/tint/type/reference.h"
 #include "src/tint/type/sampler.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::Transform);
-TINT_INSTANTIATE_TYPEINFO(tint::transform::Data);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::Transform);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::Data);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 Data::Data() = default;
 Data::Data(const Data&) = default;
@@ -60,23 +60,23 @@
     return output;
 }
 
-void Transform::RemoveStatement(CloneContext& ctx, const ast::Statement* stmt) {
+void Transform::RemoveStatement(CloneContext& ctx, const Statement* stmt) {
     auto* sem = ctx.src->Sem().Get(stmt);
     if (auto* block = tint::As<sem::BlockStatement>(sem->Parent())) {
         ctx.Remove(block->Declaration()->statements, stmt);
         return;
     }
     if (TINT_LIKELY(tint::Is<sem::ForLoopStatement>(sem->Parent()))) {
-        ctx.Replace(stmt, static_cast<ast::Expression*>(nullptr));
+        ctx.Replace(stmt, static_cast<Expression*>(nullptr));
         return;
     }
     TINT_ICE(Transform, ctx.dst->Diagnostics())
         << "unable to remove statement from parent of type " << sem->TypeInfo().name;
 }
 
-ast::Type Transform::CreateASTTypeFor(CloneContext& ctx, const type::Type* ty) {
+Type Transform::CreateASTTypeFor(CloneContext& ctx, const type::Type* ty) {
     if (ty->Is<type::Void>()) {
-        return ast::Type{};
+        return Type{};
     }
     if (ty->Is<type::I32>()) {
         return ctx.dst->ty.i32();
@@ -108,9 +108,9 @@
     }
     if (auto* a = ty->As<type::Array>()) {
         auto el = CreateASTTypeFor(ctx, a->ElemType());
-        utils::Vector<const ast::Attribute*, 1> attrs;
+        utils::Vector<const Attribute*, 1> attrs;
         if (!a->IsStrideImplicit()) {
-            attrs.Push(ctx.dst->create<ast::StrideAttribute>(a->Stride()));
+            attrs.Push(ctx.dst->create<StrideAttribute>(a->Stride()));
         }
         if (a->Count()->Is<type::RuntimeArrayCount>()) {
             return ctx.dst->ty.array(el, std::move(attrs));
@@ -125,7 +125,7 @@
             // See crbug.com/tint/1764.
             // Look for a type alias for this array.
             for (auto* type_decl : ctx.src->AST().TypeDecls()) {
-                if (auto* alias = type_decl->As<ast::Alias>()) {
+                if (auto* alias = type_decl->As<Alias>()) {
                     if (ty == ctx.src->Sem().Get(alias)) {
                         // Alias found. Use the alias name to ensure types compare equal.
                         return ctx.dst->ty(ctx.Clone(alias->name->symbol));
@@ -184,7 +184,7 @@
     }
     TINT_UNREACHABLE(Transform, ctx.dst->Diagnostics())
         << "Unhandled type: " << ty->TypeInfo().name;
-    return ast::Type{};
+    return Type{};
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/transform.h b/src/tint/ast/transform/transform.h
similarity index 92%
rename from src/tint/transform/transform.h
rename to src/tint/ast/transform/transform.h
index b498e82..82cadce 100644
--- a/src/tint/transform/transform.h
+++ b/src/tint/ast/transform/transform.h
@@ -12,8 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_TRANSFORM_H_
-#define SRC_TINT_TRANSFORM_TRANSFORM_H_
+#ifndef SRC_TINT_AST_TRANSFORM_TRANSFORM_H_
+#define SRC_TINT_AST_TRANSFORM_TRANSFORM_H_
 
 #include <memory>
 #include <unordered_map>
@@ -22,7 +22,7 @@
 #include "src/tint/program.h"
 #include "src/tint/utils/castable.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// Data is the base class for transforms that accept extra input or emit extra
 /// output information along with a Program.
@@ -181,11 +181,11 @@
                               const DataMap& inputs,
                               DataMap& outputs) const = 0;
 
-    /// CreateASTTypeFor constructs new ast::Type that reconstructs the semantic type `ty`.
+    /// CreateASTTypeFor constructs new Type that reconstructs the semantic type `ty`.
     /// @param ctx the clone context
     /// @param ty the semantic type to reconstruct
-    /// @returns an ast::Type that when resolved, will produce the semantic type `ty`.
-    static ast::Type CreateASTTypeFor(CloneContext& ctx, const type::Type* ty);
+    /// @returns an Type that when resolved, will produce the semantic type `ty`.
+    static Type CreateASTTypeFor(CloneContext& ctx, const type::Type* ty);
 
   protected:
     /// Removes the statement `stmt` from the transformed program.
@@ -193,9 +193,9 @@
     /// continuing of for-loops.
     /// @param ctx the clone context
     /// @param stmt the statement to remove when the program is cloned
-    static void RemoveStatement(CloneContext& ctx, const ast::Statement* stmt);
+    static void RemoveStatement(CloneContext& ctx, const Statement* stmt);
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_TRANSFORM_H_
+#endif  // SRC_TINT_AST_TRANSFORM_TRANSFORM_H_
diff --git a/src/tint/transform/transform_test.cc b/src/tint/ast/transform/transform_test.cc
similarity index 79%
rename from src/tint/transform/transform_test.cc
rename to src/tint/ast/transform/transform_test.cc
index 2da1ec5..c61a321 100644
--- a/src/tint/transform/transform_test.cc
+++ b/src/tint/ast/transform/transform_test.cc
@@ -15,13 +15,13 @@
 #include <string>
 
 #include "src/tint/ast/test_helper.h"
+#include "src/tint/ast/transform/transform.h"
 #include "src/tint/clone_context.h"
 #include "src/tint/program_builder.h"
-#include "src/tint/transform/transform.h"
 
 #include "gtest/gtest.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using namespace tint::number_suffixes;  // NOLINT
@@ -32,7 +32,7 @@
         return SkipTransform;
     }
 
-    ast::Type create(std::function<type::Type*(ProgramBuilder&)> create_sem_type) {
+    Type create(std::function<type::Type*(ProgramBuilder&)> create_sem_type) {
         ProgramBuilder sem_type_builder;
         auto* sem_type = create_sem_type(sem_type_builder);
         Program program(std::move(sem_type_builder));
@@ -44,9 +44,7 @@
 };
 
 TEST_F(CreateASTTypeForTest, Basic) {
-    auto check = [&](ast::Type ty, const char* expect) {
-        ast::CheckIdentifier(ty->identifier, expect);
-    };
+    auto check = [&](Type ty, const char* expect) { CheckIdentifier(ty->identifier, expect); };
 
     check(create([](ProgramBuilder& b) { return b.create<type::I32>(); }), "i32");
     check(create([](ProgramBuilder& b) { return b.create<type::U32>(); }), "u32");
@@ -61,14 +59,14 @@
         return b.create<type::Matrix>(column_type, 3u);
     });
 
-    ast::CheckIdentifier(mat, ast::Template("mat3x2", "f32"));
+    CheckIdentifier(mat, Template("mat3x2", "f32"));
 }
 
 TEST_F(CreateASTTypeForTest, Vector) {
     auto vec =
         create([](ProgramBuilder& b) { return b.create<type::Vector>(b.create<type::F32>(), 2u); });
 
-    ast::CheckIdentifier(vec, ast::Template("vec2", "f32"));
+    CheckIdentifier(vec, Template("vec2", "f32"));
 }
 
 TEST_F(CreateASTTypeForTest, ArrayImplicitStride) {
@@ -77,8 +75,8 @@
                                      4u, 4u, 32u, 32u);
     });
 
-    ast::CheckIdentifier(arr, ast::Template("array", "f32", 2_u));
-    auto* tmpl_attr = arr->identifier->As<ast::TemplatedIdentifier>();
+    CheckIdentifier(arr, Template("array", "f32", 2_u));
+    auto* tmpl_attr = arr->identifier->As<TemplatedIdentifier>();
     ASSERT_NE(tmpl_attr, nullptr);
     EXPECT_TRUE(tmpl_attr->attributes.IsEmpty());
 }
@@ -88,12 +86,12 @@
         return b.create<type::Array>(b.create<type::F32>(), b.create<type::ConstantArrayCount>(2u),
                                      4u, 4u, 64u, 32u);
     });
-    ast::CheckIdentifier(arr, ast::Template("array", "f32", 2_u));
-    auto* tmpl_attr = arr->identifier->As<ast::TemplatedIdentifier>();
+    CheckIdentifier(arr, Template("array", "f32", 2_u));
+    auto* tmpl_attr = arr->identifier->As<TemplatedIdentifier>();
     ASSERT_NE(tmpl_attr, nullptr);
     ASSERT_EQ(tmpl_attr->attributes.Length(), 1u);
-    ASSERT_TRUE(tmpl_attr->attributes[0]->Is<ast::StrideAttribute>());
-    ASSERT_EQ(tmpl_attr->attributes[0]->As<ast::StrideAttribute>()->stride, 64u);
+    ASSERT_TRUE(tmpl_attr->attributes[0]->Is<StrideAttribute>());
+    ASSERT_EQ(tmpl_attr->attributes[0]->As<StrideAttribute>()->stride, 64u);
 }
 
 // crbug.com/tint/1764
@@ -114,7 +112,7 @@
 
     CloneContext ctx(&ast_type_builder, &program, false);
     auto ast_ty = CreateASTTypeFor(ctx, arr_ty);
-    ast::CheckIdentifier(ast_ty, "A");
+    CheckIdentifier(ast_ty, "A");
 }
 
 TEST_F(CreateASTTypeForTest, Struct) {
@@ -124,7 +122,7 @@
                                      4u /* size */, 4u /* size_no_padding */);
     });
 
-    ast::CheckIdentifier(str, "S");
+    CheckIdentifier(str, "S");
 }
 
 TEST_F(CreateASTTypeForTest, PrivatePointer) {
@@ -133,7 +131,7 @@
                                        builtin::Access::kReadWrite);
     });
 
-    ast::CheckIdentifier(ptr, ast::Template("ptr", "private", "i32"));
+    CheckIdentifier(ptr, Template("ptr", "private", "i32"));
 }
 
 TEST_F(CreateASTTypeForTest, StorageReadWritePointer) {
@@ -142,8 +140,8 @@
                                        builtin::Access::kReadWrite);
     });
 
-    ast::CheckIdentifier(ptr, ast::Template("ptr", "storage", "i32", "read_write"));
+    CheckIdentifier(ptr, Template("ptr", "storage", "i32", "read_write"));
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/truncate_interstage_variables.cc b/src/tint/ast/transform/truncate_interstage_variables.cc
similarity index 88%
rename from src/tint/transform/truncate_interstage_variables.cc
rename to src/tint/ast/transform/truncate_interstage_variables.cc
index 1fc0050..157c544 100644
--- a/src/tint/transform/truncate_interstage_variables.cc
+++ b/src/tint/ast/transform/truncate_interstage_variables.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/truncate_interstage_variables.h"
+#include "src/tint/ast/transform/truncate_interstage_variables.h"
 
 #include <memory>
 #include <string>
@@ -26,10 +26,10 @@
 #include "src/tint/sem/variable.h"
 #include "src/tint/utils/unicode.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::TruncateInterstageVariables);
-TINT_INSTANTIATE_TYPEINFO(tint::transform::TruncateInterstageVariables::Config);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::TruncateInterstageVariables);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::TruncateInterstageVariables::Config);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 namespace {
 
@@ -74,7 +74,7 @@
             continue;
         }
 
-        if (func_ast->PipelineStage() != ast::PipelineStage::kVertex) {
+        if (func_ast->PipelineStage() != PipelineStage::kVertex) {
             // Currently only vertex stage could have interstage output variables that need
             // truncated.
             continue;
@@ -118,8 +118,8 @@
             old_shader_io_structs_to_new_struct_and_truncate_functions.GetOrCreate(str, [&] {
                 auto new_struct_sym = b.Symbols().New();
 
-                utils::Vector<const ast::StructMember*, 20> truncated_members;
-                utils::Vector<const ast::Expression*, 20> initializer_exprs;
+                utils::Vector<const StructMember*, 20> truncated_members;
+                utils::Vector<const Expression*, 20> initializer_exprs;
 
                 for (auto* member : str->Members()) {
                     if (omit_members.Contains(member)) {
@@ -155,7 +155,7 @@
 
     // Replace return statements with new truncated shader IO struct
     ctx.ReplaceAll(
-        [&](const ast::ReturnStatement* return_statement) -> const ast::ReturnStatement* {
+        [&](const ReturnStatement* return_statement) -> const ReturnStatement* {
             auto* return_sem = sem.Get(return_statement);
             if (auto mapping_fn_sym =
                     entry_point_functions_to_truncate_functions.Find(return_sem->Function())) {
@@ -168,11 +168,11 @@
     // Remove IO attributes from old shader IO struct which is not used as entry point output
     // anymore.
     for (auto it : old_shader_io_structs_to_new_struct_and_truncate_functions) {
-        const ast::Struct* struct_ty = it.key->Declaration();
+        const Struct* struct_ty = it.key->Declaration();
         for (auto* member : struct_ty->members) {
             for (auto* attr : member->attributes) {
-                if (attr->IsAnyOf<ast::BuiltinAttribute, ast::LocationAttribute,
-                                  ast::InterpolateAttribute, ast::InvariantAttribute>()) {
+                if (attr->IsAnyOf<BuiltinAttribute, LocationAttribute, InterpolateAttribute,
+                                  InvariantAttribute>()) {
                     ctx.Remove(member->attributes, attr);
                 }
             }
@@ -192,4 +192,4 @@
 TruncateInterstageVariables::Config& TruncateInterstageVariables::Config::operator=(const Config&) =
     default;
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/truncate_interstage_variables.h b/src/tint/ast/transform/truncate_interstage_variables.h
similarity index 92%
rename from src/tint/transform/truncate_interstage_variables.h
rename to src/tint/ast/transform/truncate_interstage_variables.h
index f279eb3..702c01b 100644
--- a/src/tint/transform/truncate_interstage_variables.h
+++ b/src/tint/ast/transform/truncate_interstage_variables.h
@@ -12,15 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_TRUNCATE_INTERSTAGE_VARIABLES_H_
-#define SRC_TINT_TRANSFORM_TRUNCATE_INTERSTAGE_VARIABLES_H_
+#ifndef SRC_TINT_AST_TRANSFORM_TRUNCATE_INTERSTAGE_VARIABLES_H_
+#define SRC_TINT_AST_TRANSFORM_TRUNCATE_INTERSTAGE_VARIABLES_H_
 
 #include <bitset>
 
+#include "src/tint/ast/transform/transform.h"
 #include "src/tint/sem/binding_point.h"
-#include "src/tint/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// TruncateInterstageVariables is a transform that truncate interstage variables.
 /// It must be run after CanonicalizeEntryPointIO which guarantees all interstage variables of
@@ -126,6 +126,6 @@
                       DataMap& outputs) const override;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_TRUNCATE_INTERSTAGE_VARIABLES_H_
+#endif  // SRC_TINT_AST_TRANSFORM_TRUNCATE_INTERSTAGE_VARIABLES_H_
diff --git a/src/tint/transform/truncate_interstage_variables_test.cc b/src/tint/ast/transform/truncate_interstage_variables_test.cc
similarity index 97%
rename from src/tint/transform/truncate_interstage_variables_test.cc
rename to src/tint/ast/transform/truncate_interstage_variables_test.cc
index 9ab8fa2..14e546c 100644
--- a/src/tint/transform/truncate_interstage_variables_test.cc
+++ b/src/tint/ast/transform/truncate_interstage_variables_test.cc
@@ -12,13 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/truncate_interstage_variables.h"
-#include "src/tint/transform/canonicalize_entry_point_io.h"
+#include "src/tint/ast/transform/truncate_interstage_variables.h"
+#include "src/tint/ast/transform/canonicalize_entry_point_io.h"
 
 #include "gmock/gmock.h"
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using ::testing::ContainerEq;
@@ -43,8 +43,7 @@
 
     {
         auto* expect =
-            "error: missing transform data for "
-            "tint::transform::TruncateInterstageVariables";
+            "error: missing transform data for tint::ast::transform::TruncateInterstageVariables";
         auto got = Run<TruncateInterstageVariables>(src);
         EXPECT_EQ(expect, str(got));
     }
@@ -596,4 +595,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/unshadow.cc b/src/tint/ast/transform/unshadow.cc
similarity index 77%
rename from src/tint/transform/unshadow.cc
rename to src/tint/ast/transform/unshadow.cc
index 19a1023..26cf00a 100644
--- a/src/tint/transform/unshadow.cc
+++ b/src/tint/ast/transform/unshadow.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/unshadow.h"
+#include "src/tint/ast/transform/unshadow.h"
 
 #include <memory>
 #include <unordered_map>
@@ -25,9 +25,9 @@
 #include "src/tint/sem/variable.h"
 #include "src/tint/switch.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::Unshadow);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::Unshadow);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// PIMPL state for the transform
 struct Unshadow::State {
@@ -50,29 +50,27 @@
         // Maps a variable to its new name.
         utils::Hashmap<const sem::Variable*, Symbol, 8> renamed_to;
 
-        auto rename = [&](const sem::Variable* v) -> const ast::Variable* {
+        auto rename = [&](const sem::Variable* v) -> const Variable* {
             auto* decl = v->Declaration();
             auto name = decl->name->symbol.Name();
             auto symbol = b.Symbols().New(name);
             renamed_to.Add(v, symbol);
 
             auto source = ctx.Clone(decl->source);
-            auto type = decl->type ? ctx.Clone(decl->type) : ast::Type{};
+            auto type = decl->type ? ctx.Clone(decl->type) : Type{};
             auto* initializer = ctx.Clone(decl->initializer);
             auto attributes = ctx.Clone(decl->attributes);
             return Switch(
                 decl,  //
-                [&](const ast::Var* var) {
+                [&](const Var* var) {
                     return b.Var(source, symbol, type, var->declared_address_space,
                                  var->declared_access, initializer, attributes);
                 },
-                [&](const ast::Let*) {
-                    return b.Let(source, symbol, type, initializer, attributes);
-                },
-                [&](const ast::Const*) {
+                [&](const Let*) { return b.Let(source, symbol, type, initializer, attributes); },
+                [&](const Const*) {
                     return b.Const(source, symbol, type, initializer, attributes);
                 },
-                [&](const ast::Parameter*) {  //
+                [&](const Parameter*) {  //
                     return b.Param(source, symbol, type, attributes);
                 },
                 [&](Default) {
@@ -105,17 +103,16 @@
             return SkipTransform;
         }
 
-        ctx.ReplaceAll(
-            [&](const ast::IdentifierExpression* ident) -> const tint::ast::IdentifierExpression* {
-                if (auto* sem_ident = sem.GetVal(ident)) {
-                    if (auto* user = sem_ident->Unwrap()->As<sem::VariableUser>()) {
-                        if (auto renamed = renamed_to.Find(user->Variable())) {
-                            return b.Expr(*renamed);
-                        }
+        ctx.ReplaceAll([&](const IdentifierExpression* ident) -> const IdentifierExpression* {
+            if (auto* sem_ident = sem.GetVal(ident)) {
+                if (auto* user = sem_ident->Unwrap()->As<sem::VariableUser>()) {
+                    if (auto renamed = renamed_to.Find(user->Variable())) {
+                        return b.Expr(*renamed);
                     }
                 }
-                return nullptr;
-            });
+            }
+            return nullptr;
+        });
 
         ctx.Clone();
         return Program(std::move(b));
@@ -130,4 +127,4 @@
     return State(src).Run();
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/unshadow.h b/src/tint/ast/transform/unshadow.h
similarity index 80%
rename from src/tint/transform/unshadow.h
rename to src/tint/ast/transform/unshadow.h
index 313e556..a231258 100644
--- a/src/tint/transform/unshadow.h
+++ b/src/tint/ast/transform/unshadow.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_UNSHADOW_H_
-#define SRC_TINT_TRANSFORM_UNSHADOW_H_
+#ifndef SRC_TINT_AST_TRANSFORM_UNSHADOW_H_
+#define SRC_TINT_AST_TRANSFORM_UNSHADOW_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// Unshadow is a Transform that renames any variables that shadow another variable.
 class Unshadow final : public utils::Castable<Unshadow, Transform> {
@@ -37,6 +37,6 @@
     struct State;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_UNSHADOW_H_
+#endif  // SRC_TINT_AST_TRANSFORM_UNSHADOW_H_
diff --git a/src/tint/transform/unshadow_test.cc b/src/tint/ast/transform/unshadow_test.cc
similarity index 98%
rename from src/tint/transform/unshadow_test.cc
rename to src/tint/ast/transform/unshadow_test.cc
index e60db42..e0246b7 100644
--- a/src/tint/transform/unshadow_test.cc
+++ b/src/tint/ast/transform/unshadow_test.cc
@@ -12,11 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/unshadow.h"
+#include "src/tint/ast/transform/unshadow.h"
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using UnshadowTest = TransformTest;
@@ -800,4 +800,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/utils/get_insertion_point.cc b/src/tint/ast/transform/utils/get_insertion_point.cc
similarity index 89%
rename from src/tint/transform/utils/get_insertion_point.cc
rename to src/tint/ast/transform/utils/get_insertion_point.cc
index bce7a7e..64f12f8 100644
--- a/src/tint/transform/utils/get_insertion_point.cc
+++ b/src/tint/ast/transform/utils/get_insertion_point.cc
@@ -12,18 +12,18 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/utils/get_insertion_point.h"
+#include "src/tint/ast/transform/utils/get_insertion_point.h"
 #include "src/tint/debug.h"
 #include "src/tint/diagnostic/diagnostic.h"
 #include "src/tint/sem/for_loop_statement.h"
 #include "src/tint/switch.h"
 
-namespace tint::transform::utils {
+namespace tint::ast::transform::utils {
 
-InsertionPoint GetInsertionPoint(CloneContext& ctx, const ast::Statement* stmt) {
+InsertionPoint GetInsertionPoint(CloneContext& ctx, const Statement* stmt) {
     auto& sem = ctx.src->Sem();
     auto& diag = ctx.dst->Diagnostics();
-    using RetType = std::pair<const sem::BlockStatement*, const ast::Statement*>;
+    using RetType = std::pair<const sem::BlockStatement*, const Statement*>;
 
     if (auto* sem_stmt = sem.Get(stmt)) {
         auto* parent = sem_stmt->Parent();
@@ -55,4 +55,4 @@
     return {};
 }
 
-}  // namespace tint::transform::utils
+}  // namespace tint::ast::transform::utils
diff --git a/src/tint/transform/utils/get_insertion_point.h b/src/tint/ast/transform/utils/get_insertion_point.h
similarity index 77%
rename from src/tint/transform/utils/get_insertion_point.h
rename to src/tint/ast/transform/utils/get_insertion_point.h
index 14e867c..10fab59 100644
--- a/src/tint/transform/utils/get_insertion_point.h
+++ b/src/tint/ast/transform/utils/get_insertion_point.h
@@ -12,19 +12,19 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_UTILS_GET_INSERTION_POINT_H_
-#define SRC_TINT_TRANSFORM_UTILS_GET_INSERTION_POINT_H_
+#ifndef SRC_TINT_AST_TRANSFORM_UTILS_GET_INSERTION_POINT_H_
+#define SRC_TINT_AST_TRANSFORM_UTILS_GET_INSERTION_POINT_H_
 
 #include <utility>
 
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/block_statement.h"
 
-namespace tint::transform::utils {
+namespace tint::ast::transform::utils {
 
 /// InsertionPoint is a pair of the block (`first`) within which, and the
 /// statement (`second`) before or after which to insert.
-using InsertionPoint = std::pair<const sem::BlockStatement*, const ast::Statement*>;
+using InsertionPoint = std::pair<const sem::BlockStatement*, const Statement*>;
 
 /// For the input statement, returns the block and statement within that
 /// block to insert before/after. If `stmt` is a for-loop continue statement,
@@ -32,8 +32,8 @@
 /// @param ctx the clone context
 /// @param stmt the statement to insert before or after
 /// @return the insertion point
-InsertionPoint GetInsertionPoint(CloneContext& ctx, const ast::Statement* stmt);
+InsertionPoint GetInsertionPoint(CloneContext& ctx, const Statement* stmt);
 
-}  // namespace tint::transform::utils
+}  // namespace tint::ast::transform::utils
 
-#endif  // SRC_TINT_TRANSFORM_UTILS_GET_INSERTION_POINT_H_
+#endif  // SRC_TINT_AST_TRANSFORM_UTILS_GET_INSERTION_POINT_H_
diff --git a/src/tint/transform/utils/get_insertion_point_test.cc b/src/tint/ast/transform/utils/get_insertion_point_test.cc
similarity index 93%
rename from src/tint/transform/utils/get_insertion_point_test.cc
rename to src/tint/ast/transform/utils/get_insertion_point_test.cc
index d910858..9a85f1f 100644
--- a/src/tint/transform/utils/get_insertion_point_test.cc
+++ b/src/tint/ast/transform/utils/get_insertion_point_test.cc
@@ -15,14 +15,14 @@
 #include <utility>
 
 #include "gtest/gtest-spi.h"
+#include "src/tint/ast/transform/test_helper.h"
+#include "src/tint/ast/transform/utils/get_insertion_point.h"
 #include "src/tint/debug.h"
 #include "src/tint/program_builder.h"
-#include "src/tint/transform/test_helper.h"
-#include "src/tint/transform/utils/get_insertion_point.h"
 
 using namespace tint::number_suffixes;  // NOLINT
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using GetInsertionPointTest = ::testing::Test;
@@ -93,4 +93,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/utils/hoist_to_decl_before.cc b/src/tint/ast/transform/utils/hoist_to_decl_before.cc
similarity index 93%
rename from src/tint/transform/utils/hoist_to_decl_before.cc
rename to src/tint/ast/transform/utils/hoist_to_decl_before.cc
index 5fa00c4..09dce2b 100644
--- a/src/tint/transform/utils/hoist_to_decl_before.cc
+++ b/src/tint/ast/transform/utils/hoist_to_decl_before.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/utils/hoist_to_decl_before.h"
+#include "src/tint/ast/transform/utils/hoist_to_decl_before.h"
 
 #include <utility>
 
@@ -27,7 +27,7 @@
 #include "src/tint/utils/reverse.h"
 #include "src/tint/utils/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// Private implementation of HoistToDeclBefore transform
 struct HoistToDeclBefore::State {
@@ -37,7 +37,7 @@
 
     /// @copydoc HoistToDeclBefore::Add()
     bool Add(const sem::ValueExpression* before_expr,
-             const ast::Expression* expr,
+             const Expression* expr,
              VariableKind kind,
              const char* decl_name) {
         auto name = b.Symbols().New(decl_name);
@@ -85,8 +85,8 @@
         return true;
     }
 
-    /// @copydoc HoistToDeclBefore::InsertBefore(const sem::Statement*, const ast::Statement*)
-    bool InsertBefore(const sem::Statement* before_stmt, const ast::Statement* stmt) {
+    /// @copydoc HoistToDeclBefore::InsertBefore(const sem::Statement*, const Statement*)
+    bool InsertBefore(const sem::Statement* before_stmt, const Statement* stmt) {
         if (stmt) {
             auto builder = [stmt] { return stmt; };
             return InsertBeforeImpl(before_stmt, std::move(builder));
@@ -99,8 +99,8 @@
         return InsertBeforeImpl(before_stmt, std::move(builder));
     }
 
-    /// @copydoc HoistToDeclBefore::Replace(const sem::Statement* what, const ast::Statement* with)
-    bool Replace(const sem::Statement* what, const ast::Statement* with) {
+    /// @copydoc HoistToDeclBefore::Replace(const sem::Statement* what, const Statement* with)
+    bool Replace(const sem::Statement* what, const Statement* with) {
         auto builder = [with] { return with; };
         return Replace(what, std::move(builder));
     }
@@ -145,7 +145,7 @@
     utils::Hashmap<const sem::WhileStatement*, LoopInfo, 4> while_loops;
 
     /// 'else if' statements that need to be decomposed to 'else {if}'
-    utils::Hashmap<const ast::IfStatement*, ElseIfInfo, 4> else_ifs;
+    utils::Hashmap<const IfStatement*, ElseIfInfo, 4> else_ifs;
 
     template <size_t N>
     static auto Build(const utils::Vector<StmtBuilder, N>& builders) {
@@ -181,7 +181,7 @@
     /// automatically called.
     /// @warning the returned reference is invalid if this is called a second time, or the
     /// #else_ifs map is mutated.
-    auto ElseIf(const ast::IfStatement* else_if) {
+    auto ElseIf(const IfStatement* else_if) {
         if (else_ifs.IsEmpty()) {
             RegisterElseIfTransform();
         }
@@ -190,7 +190,7 @@
 
     /// Registers the handler for transforming for-loops based on the content of the #for_loops map.
     void RegisterForLoopTransform() const {
-        ctx.ReplaceAll([&](const ast::ForLoopStatement* stmt) -> const ast::Statement* {
+        ctx.ReplaceAll([&](const ForLoopStatement* stmt) -> const Statement* {
             auto& sem = ctx.src->Sem();
 
             if (auto* fl = sem.Get(stmt)) {
@@ -205,9 +205,9 @@
                     if (auto* cond = for_loop->condition) {
                         // !condition
                         auto* not_cond =
-                            b.create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, ctx.Clone(cond));
+                            b.create<UnaryOpExpression>(UnaryOp::kNot, ctx.Clone(cond));
                         // { break; }
-                        auto* break_body = b.Block(b.create<ast::BreakStatement>());
+                        auto* break_body = b.Block(b.create<BreakStatement>());
                         // if (!condition) { break; }
                         body_stmts.Push(b.If(not_cond, break_body));
                     }
@@ -215,7 +215,7 @@
                     body_stmts.Push(ctx.Clone(for_loop->body));
 
                     // Create the continuing block if there was one.
-                    const ast::BlockStatement* continuing = nullptr;
+                    const BlockStatement* continuing = nullptr;
                     if (auto* cont = for_loop->continuing) {
                         // Continuing block starts with any let declarations used by
                         // the continuing.
@@ -249,7 +249,7 @@
     /// map.
     void RegisterWhileLoopTransform() const {
         // At least one while needs to be transformed into a loop.
-        ctx.ReplaceAll([&](const ast::WhileStatement* stmt) -> const ast::Statement* {
+        ctx.ReplaceAll([&](const WhileStatement* stmt) -> const Statement* {
             auto& sem = ctx.src->Sem();
 
             if (auto* w = sem.Get(stmt)) {
@@ -274,7 +274,7 @@
                     // Next emit the body
                     body_stmts.Push(ctx.Clone(while_loop->body));
 
-                    const ast::BlockStatement* continuing = nullptr;
+                    const BlockStatement* continuing = nullptr;
 
                     auto* body = b.Block(body_stmts);
                     auto* loop = b.Loop(body, continuing);
@@ -289,7 +289,7 @@
     /// map.
     void RegisterElseIfTransform() const {
         // Decompose 'else-if' statements into 'else { if }' blocks.
-        ctx.ReplaceAll([&](const ast::IfStatement* stmt) -> const ast::Statement* {
+        ctx.ReplaceAll([&](const IfStatement* stmt) -> const Statement* {
             if (auto info = else_ifs.Find(stmt)) {
                 // Build the else block's body statements, starting with let decls for the
                 // conditional expression.
@@ -412,14 +412,13 @@
 HoistToDeclBefore::~HoistToDeclBefore() {}
 
 bool HoistToDeclBefore::Add(const sem::ValueExpression* before_expr,
-                            const ast::Expression* expr,
+                            const Expression* expr,
                             VariableKind kind,
                             const char* decl_name) {
     return state_->Add(before_expr, expr, kind, decl_name);
 }
 
-bool HoistToDeclBefore::InsertBefore(const sem::Statement* before_stmt,
-                                     const ast::Statement* stmt) {
+bool HoistToDeclBefore::InsertBefore(const sem::Statement* before_stmt, const Statement* stmt) {
     return state_->InsertBefore(before_stmt, stmt);
 }
 
@@ -428,7 +427,7 @@
     return state_->InsertBefore(before_stmt, builder);
 }
 
-bool HoistToDeclBefore::Replace(const sem::Statement* what, const ast::Statement* with) {
+bool HoistToDeclBefore::Replace(const sem::Statement* what, const Statement* with) {
     return state_->Replace(what, with);
 }
 
@@ -440,4 +439,4 @@
     return state_->Prepare(before_expr);
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/utils/hoist_to_decl_before.h b/src/tint/ast/transform/utils/hoist_to_decl_before.h
similarity index 86%
rename from src/tint/transform/utils/hoist_to_decl_before.h
rename to src/tint/ast/transform/utils/hoist_to_decl_before.h
index c662b1e..5d09c02 100644
--- a/src/tint/transform/utils/hoist_to_decl_before.h
+++ b/src/tint/ast/transform/utils/hoist_to_decl_before.h
@@ -12,16 +12,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_UTILS_HOIST_TO_DECL_BEFORE_H_
-#define SRC_TINT_TRANSFORM_UTILS_HOIST_TO_DECL_BEFORE_H_
+#ifndef SRC_TINT_AST_TRANSFORM_UTILS_HOIST_TO_DECL_BEFORE_H_
+#define SRC_TINT_AST_TRANSFORM_UTILS_HOIST_TO_DECL_BEFORE_H_
 
 #include <functional>
 #include <memory>
 
+#include "src/tint/ast/transform/transform.h"
 #include "src/tint/sem/value_expression.h"
-#include "src/tint/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// Utility class that can be used to hoist expressions before other
 /// expressions, possibly converting 'for-loop's to 'loop's and 'else-if's to
@@ -36,7 +36,7 @@
     ~HoistToDeclBefore();
 
     /// StmtBuilder is a builder of an AST statement
-    using StmtBuilder = std::function<const ast::Statement*()>;
+    using StmtBuilder = std::function<const Statement*()>;
 
     /// VariableKind is either a var, let or const
     enum class VariableKind {
@@ -53,7 +53,7 @@
     /// @param decl_name optional name to use for the variable/constant name
     /// @return true on success
     bool Add(const sem::ValueExpression* before_expr,
-             const ast::Expression* expr,
+             const Expression* expr,
              VariableKind kind,
              const char* decl_name = "");
 
@@ -64,7 +64,7 @@
     /// @param before_stmt statement to insert @p stmt before
     /// @param stmt statement to insert
     /// @return true on success
-    bool InsertBefore(const sem::Statement* before_stmt, const ast::Statement* stmt);
+    bool InsertBefore(const sem::Statement* before_stmt, const Statement* stmt);
 
     /// Inserts the returned statement of @p builder before @p before_stmt, possibly converting
     /// 'for-loop's to 'loop's if necessary.
@@ -81,7 +81,7 @@
     /// @param what the statement to replace
     /// @param with the replacement statement
     /// @return true on success
-    bool Replace(const sem::Statement* what, const ast::Statement* with);
+    bool Replace(const sem::Statement* what, const Statement* with);
 
     /// Replaces the statement @p what with the statement returned by @p stmt, possibly converting
     /// 'for-loop's to 'loop's if necessary.
@@ -102,6 +102,6 @@
     std::unique_ptr<State> state_;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_UTILS_HOIST_TO_DECL_BEFORE_H_
+#endif  // SRC_TINT_AST_TRANSFORM_UTILS_HOIST_TO_DECL_BEFORE_H_
diff --git a/src/tint/transform/utils/hoist_to_decl_before_test.cc b/src/tint/ast/transform/utils/hoist_to_decl_before_test.cc
similarity index 96%
rename from src/tint/transform/utils/hoist_to_decl_before_test.cc
rename to src/tint/ast/transform/utils/hoist_to_decl_before_test.cc
index 0abb809..89b137c 100644
--- a/src/tint/transform/utils/hoist_to_decl_before_test.cc
+++ b/src/tint/ast/transform/utils/hoist_to_decl_before_test.cc
@@ -15,16 +15,16 @@
 #include <utility>
 
 #include "gtest/gtest-spi.h"
+#include "src/tint/ast/transform/test_helper.h"
+#include "src/tint/ast/transform/utils/hoist_to_decl_before.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/if_statement.h"
 #include "src/tint/sem/index_accessor_expression.h"
 #include "src/tint/sem/statement.h"
-#include "src/tint/transform/test_helper.h"
-#include "src/tint/transform/utils/hoist_to_decl_before.h"
 
 using namespace tint::number_suffixes;  // NOLINT
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using HoistToDeclBeforeTest = ::testing::Test;
@@ -628,7 +628,7 @@
     ProgramBuilder b;
     b.Func("foo", utils::Empty, b.ty.void_(), utils::Empty);
     auto* var = b.Decl(b.Var("a", b.Expr(1_i)));
-    auto* cont = b.CompoundAssign("a", b.Expr(1_i), ast::BinaryOp::kAdd);
+    auto* cont = b.CompoundAssign("a", b.Expr(1_i), BinaryOp::kAdd);
     auto* s = b.For(nullptr, b.Expr(true), cont, b.Block());
     b.Func("f", utils::Empty, b.ty.void_(), utils::Vector{var, s});
 
@@ -637,7 +637,7 @@
     CloneContext ctx(&cloned_b, &original);
 
     HoistToDeclBefore hoistToDeclBefore(ctx);
-    auto* before_stmt = ctx.src->Sem().Get(cont->As<ast::Statement>());
+    auto* before_stmt = ctx.src->Sem().Get(cont->As<Statement>());
     auto* new_stmt = ctx.dst->CallStmt(ctx.dst->Call("foo"));
     hoistToDeclBefore.InsertBefore(before_stmt, new_stmt);
 
@@ -679,7 +679,7 @@
     ProgramBuilder b;
     b.Func("foo", utils::Empty, b.ty.void_(), utils::Empty);
     auto* var = b.Decl(b.Var("a", b.Expr(1_i)));
-    auto* cont = b.CompoundAssign("a", b.Expr(1_i), ast::BinaryOp::kAdd);
+    auto* cont = b.CompoundAssign("a", b.Expr(1_i), BinaryOp::kAdd);
     auto* s = b.For(nullptr, b.Expr(true), cont, b.Block());
     b.Func("f", utils::Empty, b.ty.void_(), utils::Vector{var, s});
 
@@ -688,7 +688,7 @@
     CloneContext ctx(&cloned_b, &original);
 
     HoistToDeclBefore hoistToDeclBefore(ctx);
-    auto* before_stmt = ctx.src->Sem().Get(cont->As<ast::Statement>());
+    auto* before_stmt = ctx.src->Sem().Get(cont->As<Statement>());
     hoistToDeclBefore.InsertBefore(before_stmt,
                                    [&] { return ctx.dst->CallStmt(ctx.dst->Call("foo")); });
 
@@ -1048,7 +1048,7 @@
     ProgramBuilder b;
     b.Func("foo", utils::Empty, b.ty.void_(), utils::Empty);
     auto* var = b.Decl(b.Var("a", b.Expr(1_i)));
-    auto* cont = b.CompoundAssign("a", b.Expr(1_i), ast::BinaryOp::kAdd);
+    auto* cont = b.CompoundAssign("a", b.Expr(1_i), BinaryOp::kAdd);
     auto* s = b.For(nullptr, b.Expr(true), cont, b.Block());
     b.Func("f", utils::Empty, b.ty.void_(), utils::Vector{var, s});
 
@@ -1057,7 +1057,7 @@
     CloneContext ctx(&cloned_b, &original);
 
     HoistToDeclBefore hoistToDeclBefore(ctx);
-    auto* target_stmt = ctx.src->Sem().Get(cont->As<ast::Statement>());
+    auto* target_stmt = ctx.src->Sem().Get(cont->As<Statement>());
     auto* new_stmt = ctx.dst->CallStmt(ctx.dst->Call("foo"));
     hoistToDeclBefore.Replace(target_stmt, new_stmt);
 
@@ -1098,7 +1098,7 @@
     ProgramBuilder b;
     b.Func("foo", utils::Empty, b.ty.void_(), utils::Empty);
     auto* var = b.Decl(b.Var("a", b.Expr(1_i)));
-    auto* cont = b.CompoundAssign("a", b.Expr(1_i), ast::BinaryOp::kAdd);
+    auto* cont = b.CompoundAssign("a", b.Expr(1_i), BinaryOp::kAdd);
     auto* s = b.For(nullptr, b.Expr(true), cont, b.Block());
     b.Func("f", utils::Empty, b.ty.void_(), utils::Vector{var, s});
 
@@ -1107,7 +1107,7 @@
     CloneContext ctx(&cloned_b, &original);
 
     HoistToDeclBefore hoistToDeclBefore(ctx);
-    auto* target_stmt = ctx.src->Sem().Get(cont->As<ast::Statement>());
+    auto* target_stmt = ctx.src->Sem().Get(cont->As<Statement>());
     hoistToDeclBefore.Replace(target_stmt, [&] { return ctx.dst->CallStmt(ctx.dst->Call("foo")); });
 
     ctx.Clone();
@@ -1137,4 +1137,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/var_for_dynamic_index.cc b/src/tint/ast/transform/var_for_dynamic_index.cc
similarity index 85%
rename from src/tint/transform/var_for_dynamic_index.cc
rename to src/tint/ast/transform/var_for_dynamic_index.cc
index 18f71bb..0224eb2 100644
--- a/src/tint/transform/var_for_dynamic_index.cc
+++ b/src/tint/ast/transform/var_for_dynamic_index.cc
@@ -12,14 +12,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/var_for_dynamic_index.h"
+#include "src/tint/ast/transform/var_for_dynamic_index.h"
 
 #include <utility>
 
+#include "src/tint/ast/transform/utils/hoist_to_decl_before.h"
 #include "src/tint/program_builder.h"
-#include "src/tint/transform/utils/hoist_to_decl_before.h"
 
-namespace tint::transform {
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::VarForDynamicIndex);
+
+namespace tint::ast::transform {
 
 VarForDynamicIndex::VarForDynamicIndex() = default;
 
@@ -35,7 +37,7 @@
 
     // Extracts array and matrix values that are dynamically indexed to a
     // temporary `var` local that is then indexed.
-    auto dynamic_index_to_var = [&](const ast::IndexAccessorExpression* access_expr) {
+    auto dynamic_index_to_var = [&](const IndexAccessorExpression* access_expr) {
         auto* index_expr = access_expr->index;
         auto* object_expr = access_expr->object;
         auto& sem = src->Sem();
@@ -60,7 +62,7 @@
 
     bool index_accessor_found = false;
     for (auto* node : src->ASTNodes().Objects()) {
-        if (auto* access_expr = node->As<ast::IndexAccessorExpression>()) {
+        if (auto* access_expr = node->As<IndexAccessorExpression>()) {
             if (!dynamic_index_to_var(access_expr)) {
                 return Program(std::move(b));
             }
@@ -75,4 +77,4 @@
     return Program(std::move(b));
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/var_for_dynamic_index.h b/src/tint/ast/transform/var_for_dynamic_index.h
similarity index 75%
rename from src/tint/transform/var_for_dynamic_index.h
rename to src/tint/ast/transform/var_for_dynamic_index.h
index 070a2cd..986698c 100644
--- a/src/tint/transform/var_for_dynamic_index.h
+++ b/src/tint/ast/transform/var_for_dynamic_index.h
@@ -12,18 +12,18 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_VAR_FOR_DYNAMIC_INDEX_H_
-#define SRC_TINT_TRANSFORM_VAR_FOR_DYNAMIC_INDEX_H_
+#ifndef SRC_TINT_AST_TRANSFORM_VAR_FOR_DYNAMIC_INDEX_H_
+#define SRC_TINT_AST_TRANSFORM_VAR_FOR_DYNAMIC_INDEX_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// A transform that extracts array and matrix values that are dynamically
 /// indexed to a temporary `var` local before performing the index. This
 /// transform is used by the SPIR-V writer as there is no SPIR-V instruction
 /// that can dynamically index a non-pointer composite.
-class VarForDynamicIndex : public Transform {
+class VarForDynamicIndex final : public utils::Castable<VarForDynamicIndex, Transform> {
   public:
     /// Constructor
     VarForDynamicIndex();
@@ -37,6 +37,6 @@
                       DataMap& outputs) const override;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_VAR_FOR_DYNAMIC_INDEX_H_
+#endif  // SRC_TINT_AST_TRANSFORM_VAR_FOR_DYNAMIC_INDEX_H_
diff --git a/src/tint/transform/var_for_dynamic_index_test.cc b/src/tint/ast/transform/var_for_dynamic_index_test.cc
similarity index 97%
rename from src/tint/transform/var_for_dynamic_index_test.cc
rename to src/tint/ast/transform/var_for_dynamic_index_test.cc
index 2130ae1..4cfb15e 100644
--- a/src/tint/transform/var_for_dynamic_index_test.cc
+++ b/src/tint/ast/transform/var_for_dynamic_index_test.cc
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/var_for_dynamic_index.h"
-#include "src/tint/transform/for_loop_to_loop.h"
+#include "src/tint/ast/transform/var_for_dynamic_index.h"
+#include "src/tint/ast/transform/for_loop_to_loop.h"
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using VarForDynamicIndexTest = TransformTest;
@@ -560,4 +560,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/vectorize_matrix_conversions.cc b/src/tint/ast/transform/vectorize_matrix_conversions.cc
similarity index 93%
rename from src/tint/transform/vectorize_matrix_conversions.cc
rename to src/tint/ast/transform/vectorize_matrix_conversions.cc
index 97e4d3c..66c8251 100644
--- a/src/tint/transform/vectorize_matrix_conversions.cc
+++ b/src/tint/ast/transform/vectorize_matrix_conversions.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/vectorize_matrix_conversions.h"
+#include "src/tint/ast/transform/vectorize_matrix_conversions.h"
 
 #include <tuple>
 #include <unordered_map>
@@ -26,9 +26,9 @@
 #include "src/tint/utils/hash.h"
 #include "src/tint/utils/map.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::VectorizeMatrixConversions);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::VectorizeMatrixConversions);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 namespace {
 
@@ -70,7 +70,7 @@
 
     std::unordered_map<HelperFunctionKey, Symbol> matrix_convs;
 
-    ctx.ReplaceAll([&](const ast::CallExpression* expr) -> const ast::CallExpression* {
+    ctx.ReplaceAll([&](const CallExpression* expr) -> const CallExpression* {
         auto* call = src->Sem().Get(expr)->UnwrapMaterialize()->As<sem::Call>();
         auto* ty_conv = call->Target()->As<sem::ValueConversion>();
         if (!ty_conv) {
@@ -102,7 +102,7 @@
         }
 
         auto build_vectorized_conversion_expression = [&](auto&& src_expression_builder) {
-            utils::Vector<const ast::Expression*, 4> columns;
+            utils::Vector<const Expression*, 4> columns;
             for (uint32_t c = 0; c < dst_type->columns(); c++) {
                 auto* src_matrix_expr = src_expression_builder();
                 auto* src_column_expr = b.IndexAccessor(src_matrix_expr, b.Expr(tint::AInt(c)));
@@ -146,4 +146,4 @@
     return Program(std::move(b));
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/vectorize_matrix_conversions.h b/src/tint/ast/transform/vectorize_matrix_conversions.h
similarity index 78%
rename from src/tint/transform/vectorize_matrix_conversions.h
rename to src/tint/ast/transform/vectorize_matrix_conversions.h
index 2308eb1..108b073 100644
--- a/src/tint/transform/vectorize_matrix_conversions.h
+++ b/src/tint/ast/transform/vectorize_matrix_conversions.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_VECTORIZE_MATRIX_CONVERSIONS_H_
-#define SRC_TINT_TRANSFORM_VECTORIZE_MATRIX_CONVERSIONS_H_
+#ifndef SRC_TINT_AST_TRANSFORM_VECTORIZE_MATRIX_CONVERSIONS_H_
+#define SRC_TINT_AST_TRANSFORM_VECTORIZE_MATRIX_CONVERSIONS_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// A transform that converts matrix conversions (between f32 and f16 matrices) to the vector form.
 class VectorizeMatrixConversions final
@@ -35,6 +35,6 @@
                       DataMap& outputs) const override;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_VECTORIZE_MATRIX_CONVERSIONS_H_
+#endif  // SRC_TINT_AST_TRANSFORM_VECTORIZE_MATRIX_CONVERSIONS_H_
diff --git a/src/tint/transform/vectorize_matrix_conversions_test.cc b/src/tint/ast/transform/vectorize_matrix_conversions_test.cc
similarity index 98%
rename from src/tint/transform/vectorize_matrix_conversions_test.cc
rename to src/tint/ast/transform/vectorize_matrix_conversions_test.cc
index 5e42f08..52d08cb 100644
--- a/src/tint/transform/vectorize_matrix_conversions_test.cc
+++ b/src/tint/ast/transform/vectorize_matrix_conversions_test.cc
@@ -12,15 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/vectorize_matrix_conversions.h"
+#include "src/tint/ast/transform/vectorize_matrix_conversions.h"
 
 #include <string>
 #include <utility>
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 #include "src/tint/utils/string.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using VectorizeMatrixConversionsTest = TransformTestWithParam<std::pair<uint32_t, uint32_t>>;
@@ -408,4 +408,4 @@
                                          std::make_pair(4, 4)));
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/vectorize_scalar_matrix_initializers.cc b/src/tint/ast/transform/vectorize_scalar_matrix_initializers.cc
similarity index 92%
rename from src/tint/transform/vectorize_scalar_matrix_initializers.cc
rename to src/tint/ast/transform/vectorize_scalar_matrix_initializers.cc
index e35cfb3..840f368 100644
--- a/src/tint/transform/vectorize_scalar_matrix_initializers.cc
+++ b/src/tint/ast/transform/vectorize_scalar_matrix_initializers.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/vectorize_scalar_matrix_initializers.h"
+#include "src/tint/ast/transform/vectorize_scalar_matrix_initializers.h"
 
 #include <unordered_map>
 #include <utility>
@@ -24,9 +24,9 @@
 #include "src/tint/type/abstract_numeric.h"
 #include "src/tint/utils/map.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::VectorizeScalarMatrixInitializers);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::VectorizeScalarMatrixInitializers);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 bool ShouldRun(const Program* program) {
@@ -61,7 +61,7 @@
 
     std::unordered_map<const type::Matrix*, Symbol> scalar_inits;
 
-    ctx.ReplaceAll([&](const ast::CallExpression* expr) -> const ast::CallExpression* {
+    ctx.ReplaceAll([&](const CallExpression* expr) -> const CallExpression* {
         auto* call = src->Sem().Get(expr)->UnwrapMaterialize()->As<sem::Call>();
         auto* ty_init = call->Target()->As<sem::ValueConstructor>();
         if (!ty_init) {
@@ -91,9 +91,9 @@
         // Constructs a matrix using vector columns, with the elements constructed using the
         // 'element(uint32_t c, uint32_t r)' callback.
         auto build_mat = [&](auto&& element) {
-            utils::Vector<const ast::Expression*, 4> columns;
+            utils::Vector<const Expression*, 4> columns;
             for (uint32_t c = 0; c < mat_type->columns(); c++) {
-                utils::Vector<const ast::Expression*, 4> row_values;
+                utils::Vector<const Expression*, 4> row_values;
                 for (uint32_t r = 0; r < mat_type->rows(); r++) {
                     row_values.Push(element(c, r));
                 }
@@ -143,4 +143,4 @@
     return Program(std::move(b));
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/vectorize_scalar_matrix_initializers.h b/src/tint/ast/transform/vectorize_scalar_matrix_initializers.h
similarity index 77%
rename from src/tint/transform/vectorize_scalar_matrix_initializers.h
rename to src/tint/ast/transform/vectorize_scalar_matrix_initializers.h
index f0aba6e..55f736c 100644
--- a/src/tint/transform/vectorize_scalar_matrix_initializers.h
+++ b/src/tint/ast/transform/vectorize_scalar_matrix_initializers.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_VECTORIZE_SCALAR_MATRIX_INITIALIZERS_H_
-#define SRC_TINT_TRANSFORM_VECTORIZE_SCALAR_MATRIX_INITIALIZERS_H_
+#ifndef SRC_TINT_AST_TRANSFORM_VECTORIZE_SCALAR_MATRIX_INITIALIZERS_H_
+#define SRC_TINT_AST_TRANSFORM_VECTORIZE_SCALAR_MATRIX_INITIALIZERS_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// A transform that converts scalar matrix initializers to the vector form.
 class VectorizeScalarMatrixInitializers final
@@ -35,6 +35,6 @@
                       DataMap& outputs) const override;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_VECTORIZE_SCALAR_MATRIX_INITIALIZERS_H_
+#endif  // SRC_TINT_AST_TRANSFORM_VECTORIZE_SCALAR_MATRIX_INITIALIZERS_H_
diff --git a/src/tint/transform/vectorize_scalar_matrix_initializers_test.cc b/src/tint/ast/transform/vectorize_scalar_matrix_initializers_test.cc
similarity index 96%
rename from src/tint/transform/vectorize_scalar_matrix_initializers_test.cc
rename to src/tint/ast/transform/vectorize_scalar_matrix_initializers_test.cc
index 4218b99..ea9bfbb 100644
--- a/src/tint/transform/vectorize_scalar_matrix_initializers_test.cc
+++ b/src/tint/ast/transform/vectorize_scalar_matrix_initializers_test.cc
@@ -12,15 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/vectorize_scalar_matrix_initializers.h"
+#include "src/tint/ast/transform/vectorize_scalar_matrix_initializers.h"
 
 #include <string>
 #include <utility>
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 #include "src/tint/utils/string.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using VectorizeScalarMatrixInitializersTest = TransformTestWithParam<std::pair<uint32_t, uint32_t>>;
@@ -159,4 +159,4 @@
                                          std::make_pair(4, 4)));
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/vertex_pulling.cc b/src/tint/ast/transform/vertex_pulling.cc
similarity index 92%
rename from src/tint/transform/vertex_pulling.cc
rename to src/tint/ast/transform/vertex_pulling.cc
index 5f704de..c2a543e 100644
--- a/src/tint/transform/vertex_pulling.cc
+++ b/src/tint/ast/transform/vertex_pulling.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/vertex_pulling.h"
+#include "src/tint/ast/transform/vertex_pulling.h"
 
 #include <algorithm>
 #include <utility>
@@ -29,12 +29,12 @@
 #include "src/tint/utils/math.h"
 #include "src/tint/utils/string_stream.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::VertexPulling);
-TINT_INSTANTIATE_TYPEINFO(tint::transform::VertexPulling::Config);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::VertexPulling);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::VertexPulling::Config);
 
 using namespace tint::number_suffixes;  // NOLINT
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 namespace {
 
@@ -238,9 +238,9 @@
     /// @returns the new program or SkipTransform if the transform is not required
     ApplyResult Run() {
         // Find entry point
-        const ast::Function* func = nullptr;
+        const Function* func = nullptr;
         for (auto* fn : src->AST().Functions()) {
-            if (fn->PipelineStage() == ast::PipelineStage::kVertex) {
+            if (fn->PipelineStage() == PipelineStage::kVertex) {
                 if (func != nullptr) {
                     b.Diagnostics().add_error(
                         diag::System::Transform,
@@ -264,18 +264,18 @@
     }
 
   private:
-    /// LocationReplacement describes an ast::Variable replacement for a location input.
+    /// LocationReplacement describes an Variable replacement for a location input.
     struct LocationReplacement {
         /// The variable to replace in the source Program
-        ast::Variable* from;
+        Variable* from;
         /// The replacement to use in the target ProgramBuilder
-        ast::Variable* to;
+        Variable* to;
     };
 
     /// LocationInfo describes an input location
     struct LocationInfo {
         /// A builder that builds the expression that resolves to the (transformed) input location
-        std::function<const ast::Expression*()> expr;
+        std::function<const Expression*()> expr;
         /// The store type of the location variable
         const type::Type* type;
     };
@@ -289,12 +289,12 @@
     /// The clone context
     CloneContext ctx = {&b, src, /* auto_clone_symbols */ true};
     std::unordered_map<uint32_t, LocationInfo> location_info;
-    std::function<const ast::Expression*()> vertex_index_expr = nullptr;
-    std::function<const ast::Expression*()> instance_index_expr = nullptr;
+    std::function<const Expression*()> vertex_index_expr = nullptr;
+    std::function<const Expression*()> instance_index_expr = nullptr;
     Symbol pulling_position_name;
     Symbol struct_buffer_name;
     std::unordered_map<uint32_t, Symbol> vertex_buffer_names;
-    utils::Vector<const ast::Parameter*, 8> new_function_parameters;
+    utils::Vector<const Parameter*, 8> new_function_parameters;
 
     /// Generate the vertex buffer binding name
     /// @param index index to append to buffer name
@@ -331,11 +331,11 @@
     }
 
     /// Creates and returns the assignment to the variables from the buffers
-    const ast::BlockStatement* CreateVertexPullingPreamble() {
+    const BlockStatement* CreateVertexPullingPreamble() {
         // Assign by looking at the vertex descriptor to find attributes with
         // matching location.
 
-        utils::Vector<const ast::Statement*, 8> stmts;
+        utils::Vector<const Statement*, 8> stmts;
 
         for (uint32_t buffer_idx = 0; buffer_idx < cfg.vertex_state.size(); ++buffer_idx) {
             const VertexBufferLayoutDescriptor& buffer_layout = cfg.vertex_state[buffer_idx];
@@ -399,7 +399,7 @@
                 // Convert the fetched scalar/vector if WGSL variable is of `f16` types
                 if (var_dt.base_type == BaseWGSLType::kF16) {
                     // The type of the same element number of base type of target WGSL variable
-                    ast::Type loaded_data_target_type;
+                    Type loaded_data_target_type;
                     if (fmt_dt.width == 1) {
                         loaded_data_target_type = b.ty.f16();
                     } else {
@@ -433,7 +433,7 @@
 
                     // The components of result vector variable, initialized with type-converted
                     // loaded data vector.
-                    utils::Vector<const ast::Expression*, 8> values{fetch};
+                    utils::Vector<const Expression*, 8> values{fetch};
 
                     // Add padding elements. The result must be of vector types of signed/unsigned
                     // integer or float, so use the abstract integer or abstract float value to do
@@ -470,10 +470,10 @@
     /// @param offset the byte offset of the data from `buffer_base`
     /// @param buffer the index of the vertex buffer
     /// @param format the vertex format to read
-    const ast::Expression* Fetch(Symbol array_base,
-                                 uint32_t offset,
-                                 uint32_t buffer,
-                                 VertexFormat format) {
+    const Expression* Fetch(Symbol array_base,
+                            uint32_t offset,
+                            uint32_t buffer,
+                            VertexFormat format) {
         // Returns a u32 loaded from buffer_base + offset.
         auto load_u32 = [&] {
             return LoadPrimitive(array_base, offset, buffer, VertexFormat::kUint32);
@@ -679,11 +679,11 @@
     /// @param buffer the index of the vertex buffer
     /// @param format VertexFormat::kUint32, VertexFormat::kSint32 or
     /// VertexFormat::kFloat32
-    const ast::Expression* LoadPrimitive(Symbol array_base,
-                                         uint32_t offset,
-                                         uint32_t buffer,
-                                         VertexFormat format) {
-        const ast::Expression* u = nullptr;
+    const Expression* LoadPrimitive(Symbol array_base,
+                                    uint32_t offset,
+                                    uint32_t buffer,
+                                    VertexFormat format) {
+        const Expression* u = nullptr;
         if ((offset & 3) == 0) {
             // Aligned load.
 
@@ -734,14 +734,14 @@
     /// @param base_type underlying AST type
     /// @param base_format underlying vertex format
     /// @param count how many elements the vector has
-    const ast::Expression* LoadVec(Symbol array_base,
-                                   uint32_t offset,
-                                   uint32_t buffer,
-                                   uint32_t element_stride,
-                                   ast::Type base_type,
-                                   VertexFormat base_format,
-                                   uint32_t count) {
-        utils::Vector<const ast::Expression*, 8> expr_list;
+    const Expression* LoadVec(Symbol array_base,
+                              uint32_t offset,
+                              uint32_t buffer,
+                              uint32_t element_stride,
+                              Type base_type,
+                              VertexFormat base_format,
+                              uint32_t count) {
+        utils::Vector<const Expression*, 8> expr_list;
         for (uint32_t i = 0; i < count; ++i) {
             // Offset read position by element_stride for each component
             uint32_t primitive_offset = offset + element_stride * i;
@@ -756,8 +756,8 @@
     /// vertex_index and instance_index builtins if present.
     /// @param func the entry point function
     /// @param param the parameter to process
-    void ProcessNonStructParameter(const ast::Function* func, const ast::Parameter* param) {
-        if (ast::HasAttribute<ast::LocationAttribute>(param->attributes)) {
+    void ProcessNonStructParameter(const Function* func, const Parameter* param) {
+        if (HasAttribute<LocationAttribute>(param->attributes)) {
             // Create a function-scope variable to replace the parameter.
             auto func_var_sym = ctx.Clone(param->name->symbol);
             auto func_var_type = ctx.Clone(param->type);
@@ -776,7 +776,7 @@
             }
             location_info[sem->Location().value()] = info;
         } else {
-            auto* builtin_attr = ast::GetAttribute<ast::BuiltinAttribute>(param->attributes);
+            auto* builtin_attr = GetAttribute<BuiltinAttribute>(param->attributes);
             if (TINT_UNLIKELY(!builtin_attr)) {
                 TINT_ICE(Transform, b.Diagnostics()) << "Invalid entry point parameter";
                 return;
@@ -804,21 +804,21 @@
     /// @param func the entry point function
     /// @param param the parameter to process
     /// @param struct_ty the structure type
-    void ProcessStructParameter(const ast::Function* func,
-                                const ast::Parameter* param,
-                                const ast::Struct* struct_ty) {
+    void ProcessStructParameter(const Function* func,
+                                const Parameter* param,
+                                const Struct* struct_ty) {
         auto param_sym = ctx.Clone(param->name->symbol);
 
         // Process the struct members.
         bool has_locations = false;
-        utils::Vector<const ast::StructMember*, 8> members_to_clone;
+        utils::Vector<const StructMember*, 8> members_to_clone;
         for (auto* member : struct_ty->members) {
             auto member_sym = ctx.Clone(member->name->symbol);
-            std::function<const ast::Expression*()> member_expr = [this, param_sym, member_sym]() {
+            std::function<const Expression*()> member_expr = [this, param_sym, member_sym]() {
                 return b.MemberAccessor(param_sym, member_sym);
             };
 
-            if (ast::HasAttribute<ast::LocationAttribute>(member->attributes)) {
+            if (HasAttribute<LocationAttribute>(member->attributes)) {
                 // Capture mapping from location to struct member.
                 LocationInfo info;
                 info.expr = member_expr;
@@ -830,7 +830,7 @@
                 location_info[sem->Attributes().location.value()] = info;
                 has_locations = true;
             } else {
-                auto* builtin_attr = ast::GetAttribute<ast::BuiltinAttribute>(member->attributes);
+                auto* builtin_attr = GetAttribute<BuiltinAttribute>(member->attributes);
                 if (TINT_UNLIKELY(!builtin_attr)) {
                     TINT_ICE(Transform, b.Diagnostics()) << "Invalid entry point parameter";
                     return;
@@ -858,7 +858,7 @@
 
         if (!members_to_clone.IsEmpty()) {
             // Create a new struct without the location attributes.
-            utils::Vector<const ast::StructMember*, 8> new_members;
+            utils::Vector<const StructMember*, 8> new_members;
             for (auto* member : members_to_clone) {
                 auto member_name = ctx.Clone(member->name);
                 auto member_type = ctx.Clone(member->type);
@@ -883,7 +883,7 @@
 
     /// Process an entry point function.
     /// @param func the entry point function
-    void Process(const ast::Function* func) {
+    void Process(const Function* func) {
         if (func->body->Empty()) {
             return;
         }
@@ -936,8 +936,8 @@
         auto attrs = ctx.Clone(func->attributes);
         auto ret_attrs = ctx.Clone(func->return_type_attributes);
         auto* new_func =
-            b.create<ast::Function>(func->source, b.Ident(func_sym), new_function_parameters,
-                                    ret_type, body, std::move(attrs), std::move(ret_attrs));
+            b.create<Function>(func->source, b.Ident(func_sym), new_function_parameters, ret_type,
+                               body, std::move(attrs), std::move(ret_attrs));
         ctx.Replace(func, new_func);
     }
 };
@@ -979,4 +979,4 @@
 
 VertexBufferLayoutDescriptor::~VertexBufferLayoutDescriptor() = default;
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/vertex_pulling.h b/src/tint/ast/transform/vertex_pulling.h
similarity index 95%
rename from src/tint/transform/vertex_pulling.h
rename to src/tint/ast/transform/vertex_pulling.h
index d3849f7..1327fc9 100644
--- a/src/tint/transform/vertex_pulling.h
+++ b/src/tint/ast/transform/vertex_pulling.h
@@ -12,18 +12,18 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_VERTEX_PULLING_H_
-#define SRC_TINT_TRANSFORM_VERTEX_PULLING_H_
+#ifndef SRC_TINT_AST_TRANSFORM_VERTEX_PULLING_H_
+#define SRC_TINT_AST_TRANSFORM_VERTEX_PULLING_H_
 
 #include <memory>
 #include <string>
 #include <unordered_map>
 #include <vector>
 
+#include "src/tint/ast/transform/transform.h"
 #include "src/tint/reflection.h"
-#include "src/tint/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// Describes the format of data in a vertex buffer
 enum class VertexFormat {
@@ -182,6 +182,6 @@
     Config cfg_;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_VERTEX_PULLING_H_
+#endif  // SRC_TINT_AST_TRANSFORM_VERTEX_PULLING_H_
diff --git a/src/tint/transform/vertex_pulling_test.cc b/src/tint/ast/transform/vertex_pulling_test.cc
similarity index 99%
rename from src/tint/transform/vertex_pulling_test.cc
rename to src/tint/ast/transform/vertex_pulling_test.cc
index a6dc2d2..eb46dd5 100644
--- a/src/tint/transform/vertex_pulling_test.cc
+++ b/src/tint/ast/transform/vertex_pulling_test.cc
@@ -12,13 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/vertex_pulling.h"
+#include "src/tint/ast/transform/vertex_pulling.h"
 
 #include <utility>
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using VertexPullingTest = TransformTest;
@@ -2323,4 +2323,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/while_to_loop.cc b/src/tint/ast/transform/while_to_loop.cc
similarity index 81%
rename from src/tint/transform/while_to_loop.cc
rename to src/tint/ast/transform/while_to_loop.cc
index d359d2e..a38711d 100644
--- a/src/tint/transform/while_to_loop.cc
+++ b/src/tint/ast/transform/while_to_loop.cc
@@ -12,21 +12,21 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/while_to_loop.h"
+#include "src/tint/ast/transform/while_to_loop.h"
 
 #include <utility>
 
 #include "src/tint/ast/break_statement.h"
 #include "src/tint/program_builder.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::WhileToLoop);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::WhileToLoop);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 bool ShouldRun(const Program* program) {
     for (auto* node : program->ASTNodes().Objects()) {
-        if (node->Is<ast::WhileStatement>()) {
+        if (node->Is<WhileStatement>()) {
             return true;
         }
     }
@@ -47,8 +47,8 @@
     ProgramBuilder b;
     CloneContext ctx{&b, src, /* auto_clone_symbols */ true};
 
-    ctx.ReplaceAll([&](const ast::WhileStatement* w) -> const ast::Statement* {
-        utils::Vector<const ast::Statement*, 16> stmts;
+    ctx.ReplaceAll([&](const WhileStatement* w) -> const Statement* {
+        utils::Vector<const Statement*, 16> stmts;
         auto* cond = w->condition;
 
         // !condition
@@ -64,7 +64,7 @@
             stmts.Push(ctx.Clone(stmt));
         }
 
-        const ast::BlockStatement* continuing = nullptr;
+        const BlockStatement* continuing = nullptr;
 
         auto* body = b.Block(stmts);
         auto* loop = b.Loop(body, continuing);
@@ -76,4 +76,4 @@
     return Program(std::move(b));
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/while_to_loop.h b/src/tint/ast/transform/while_to_loop.h
similarity index 80%
rename from src/tint/transform/while_to_loop.h
rename to src/tint/ast/transform/while_to_loop.h
index 91e5b0c..dc24471 100644
--- a/src/tint/transform/while_to_loop.h
+++ b/src/tint/ast/transform/while_to_loop.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_WHILE_TO_LOOP_H_
-#define SRC_TINT_TRANSFORM_WHILE_TO_LOOP_H_
+#ifndef SRC_TINT_AST_TRANSFORM_WHILE_TO_LOOP_H_
+#define SRC_TINT_AST_TRANSFORM_WHILE_TO_LOOP_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// WhileToLoop is a Transform that converts a while statement into a loop
 /// statement. This is required by the SPIR-V writer.
@@ -35,6 +35,6 @@
                       DataMap& outputs) const override;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_WHILE_TO_LOOP_H_
+#endif  // SRC_TINT_AST_TRANSFORM_WHILE_TO_LOOP_H_
diff --git a/src/tint/transform/while_to_loop_test.cc b/src/tint/ast/transform/while_to_loop_test.cc
similarity index 92%
rename from src/tint/transform/while_to_loop_test.cc
rename to src/tint/ast/transform/while_to_loop_test.cc
index 6e5699d..82af0a6 100644
--- a/src/tint/transform/while_to_loop_test.cc
+++ b/src/tint/ast/transform/while_to_loop_test.cc
@@ -12,11 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/while_to_loop.h"
+#include "src/tint/ast/transform/while_to_loop.h"
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using WhileToLoopTest = TransformTest;
@@ -126,4 +126,4 @@
 
 }  // namespace
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/zero_init_workgroup_memory.cc b/src/tint/ast/transform/zero_init_workgroup_memory.cc
similarity index 93%
rename from src/tint/transform/zero_init_workgroup_memory.cc
rename to src/tint/ast/transform/zero_init_workgroup_memory.cc
index ec4a869..bd39599 100644
--- a/src/tint/transform/zero_init_workgroup_memory.cc
+++ b/src/tint/ast/transform/zero_init_workgroup_memory.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/zero_init_workgroup_memory.h"
+#include "src/tint/ast/transform/zero_init_workgroup_memory.h"
 
 #include <algorithm>
 #include <map>
@@ -29,14 +29,14 @@
 #include "src/tint/utils/map.h"
 #include "src/tint/utils/unique_vector.h"
 
-TINT_INSTANTIATE_TYPEINFO(tint::transform::ZeroInitWorkgroupMemory);
+TINT_INSTANTIATE_TYPEINFO(tint::ast::transform::ZeroInitWorkgroupMemory);
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 bool ShouldRun(const Program* program) {
     for (auto* global : program->AST().GlobalVariables()) {
-        if (auto* var = global->As<ast::Var>()) {
+        if (auto* var = global->As<Var>()) {
             auto* v = program->Sem().Get(var);
             if (v->AddressSpace() == builtin::AddressSpace::kWorkgroup) {
                 return true;
@@ -48,7 +48,7 @@
 
 }  // namespace
 
-using StatementList = utils::Vector<const ast::Statement*, 8>;
+using StatementList = utils::Vector<const Statement*, 8>;
 
 /// PIMPL state for the transform
 struct ZeroInitWorkgroupMemory::State {
@@ -132,10 +132,10 @@
     /// Run inserts the workgroup memory zero-initialization logic at the top of
     /// the given function
     /// @param fn a compute shader entry point function
-    void Run(const ast::Function* fn) {
+    void Run(const Function* fn) {
         auto& sem = ctx.src->Sem();
 
-        CalculateWorkgroupSize(ast::GetAttribute<ast::WorkgroupAttribute>(fn->attributes));
+        CalculateWorkgroupSize(GetAttribute<WorkgroupAttribute>(fn->attributes));
 
         // Generate a list of statements to zero initialize each of the
         // workgroup storage variables used by `fn`. This will populate #statements.
@@ -160,7 +160,7 @@
         // parameter
         std::function<const ast::Expression*()> local_index;
         for (auto* param : fn->params) {
-            if (auto* builtin_attr = ast::GetAttribute<ast::BuiltinAttribute>(param->attributes)) {
+            if (auto* builtin_attr = GetAttribute<BuiltinAttribute>(param->attributes)) {
                 auto builtin = sem.Get(builtin_attr)->Value();
                 if (builtin == builtin::BuiltinValue::kLocalInvocationIndex) {
                     local_index = [=] { return b.Expr(ctx.Clone(param->name->symbol)); };
@@ -231,8 +231,8 @@
                 //  }
                 auto idx = b.Symbols().New("idx");
                 auto* init = b.Decl(b.Var(idx, b.ty.u32(), local_index()));
-                auto* cond = b.create<ast::BinaryExpression>(ast::BinaryOp::kLessThan, b.Expr(idx),
-                                                             b.Expr(u32(num_iterations)));
+                auto* cond = b.create<BinaryExpression>(BinaryOp::kLessThan, b.Expr(idx),
+                                                        b.Expr(u32(num_iterations)));
                 auto* cont = b.Assign(
                     idx, b.Add(idx, workgroup_size_const ? b.Expr(u32(workgroup_size_const))
                                                          : workgroup_size_expr()));
@@ -251,8 +251,8 @@
                 //  if (local_index < num_iterations) {
                 //    ...
                 //  }
-                auto* cond = b.create<ast::BinaryExpression>(
-                    ast::BinaryOp::kLessThan, local_index(), b.Expr(u32(num_iterations)));
+                auto* cond = b.create<BinaryExpression>(BinaryOp::kLessThan, local_index(),
+                                                        b.Expr(u32(num_iterations)));
                 auto block = DeclareArrayIndices(num_iterations, array_indices,
                                                  [&] { return b.Expr(local_index()); });
                 for (auto& s : stmts) {
@@ -382,8 +382,8 @@
         for (auto index : array_indices) {
             auto name = array_index_names.at(index);
             auto* mod = (num_iterations > index.modulo)
-                            ? b.create<ast::BinaryExpression>(ast::BinaryOp::kModulo, iteration(),
-                                                              b.Expr(u32(index.modulo)))
+                            ? b.create<BinaryExpression>(BinaryOp::kModulo, iteration(),
+                                                         b.Expr(u32(index.modulo)))
                             : iteration();
             auto* div = (index.division != 1u) ? b.Div(mod, u32(index.division)) : mod;
             auto* decl = b.Decl(b.Let(name, b.ty.u32(), div));
@@ -395,7 +395,7 @@
     /// CalculateWorkgroupSize initializes the members #workgroup_size_const and
     /// #workgroup_size_expr with the linear workgroup size.
     /// @param attr the workgroup attribute applied to the entry point function
-    void CalculateWorkgroupSize(const ast::WorkgroupAttribute* attr) {
+    void CalculateWorkgroupSize(const WorkgroupAttribute* attr) {
         bool is_signed = false;
         workgroup_size_const = 1u;
         workgroup_size_expr = nullptr;
@@ -471,7 +471,7 @@
     CloneContext ctx{&b, src, /* auto_clone_symbols */ true};
 
     for (auto* fn : src->AST().Functions()) {
-        if (fn->PipelineStage() == ast::PipelineStage::kCompute) {
+        if (fn->PipelineStage() == PipelineStage::kCompute) {
             State{ctx}.Run(fn);
         }
     }
@@ -480,4 +480,4 @@
     return Program(std::move(b));
 }
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/transform/zero_init_workgroup_memory.h b/src/tint/ast/transform/zero_init_workgroup_memory.h
similarity index 80%
rename from src/tint/transform/zero_init_workgroup_memory.h
rename to src/tint/ast/transform/zero_init_workgroup_memory.h
index 24ba226..9fc8c08 100644
--- a/src/tint/transform/zero_init_workgroup_memory.h
+++ b/src/tint/ast/transform/zero_init_workgroup_memory.h
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_TRANSFORM_ZERO_INIT_WORKGROUP_MEMORY_H_
-#define SRC_TINT_TRANSFORM_ZERO_INIT_WORKGROUP_MEMORY_H_
+#ifndef SRC_TINT_AST_TRANSFORM_ZERO_INIT_WORKGROUP_MEMORY_H_
+#define SRC_TINT_AST_TRANSFORM_ZERO_INIT_WORKGROUP_MEMORY_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 
 /// ZeroInitWorkgroupMemory is a transform that injects code at the top of entry
 /// points to zero-initialize workgroup memory used by that entry point (and all
@@ -39,6 +39,6 @@
     struct State;
 };
 
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
 
-#endif  // SRC_TINT_TRANSFORM_ZERO_INIT_WORKGROUP_MEMORY_H_
+#endif  // SRC_TINT_AST_TRANSFORM_ZERO_INIT_WORKGROUP_MEMORY_H_
diff --git a/src/tint/transform/zero_init_workgroup_memory_test.cc b/src/tint/ast/transform/zero_init_workgroup_memory_test.cc
similarity index 99%
rename from src/tint/transform/zero_init_workgroup_memory_test.cc
rename to src/tint/ast/transform/zero_init_workgroup_memory_test.cc
index fbd7538..046a49c 100644
--- a/src/tint/transform/zero_init_workgroup_memory_test.cc
+++ b/src/tint/ast/transform/zero_init_workgroup_memory_test.cc
@@ -12,13 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/transform/zero_init_workgroup_memory.h"
+#include "src/tint/ast/transform/zero_init_workgroup_memory.h"
 
 #include <utility>
 
-#include "src/tint/transform/test_helper.h"
+#include "src/tint/ast/transform/test_helper.h"
 
-namespace tint::transform {
+namespace tint::ast::transform {
 namespace {
 
 using ZeroInitWorkgroupMemoryTest = TransformTest;
@@ -1387,4 +1387,4 @@
 }
 
 }  // namespace
-}  // namespace tint::transform
+}  // namespace tint::ast::transform
diff --git a/src/tint/cmd/main.cc b/src/tint/cmd/main.cc
index e7f596a..9f7fa36 100644
--- a/src/tint/cmd/main.cc
+++ b/src/tint/cmd/main.cc
@@ -947,31 +947,33 @@
         /// Returns true on success, false on error (program will immediately exit)
         std::function<bool(tint::inspector::Inspector& inspector,
                            tint::transform::Manager& manager,
-                           tint::transform::DataMap& inputs)>
+                           tint::ast::transform::DataMap& inputs)>
             make;
     };
     std::vector<TransformFactory> transforms = {
         {"first_index_offset",
-         [](tint::inspector::Inspector&, tint::transform::Manager& m, tint::transform::DataMap& i) {
-             i.Add<tint::transform::FirstIndexOffset::BindingPoint>(0, 0);
-             m.Add<tint::transform::FirstIndexOffset>();
+         [](tint::inspector::Inspector&, tint::transform::Manager& m,
+            tint::ast::transform::DataMap& i) {
+             i.Add<tint::ast::transform::FirstIndexOffset::BindingPoint>(0, 0);
+             m.Add<tint::ast::transform::FirstIndexOffset>();
              return true;
          }},
         {"renamer",
-         [](tint::inspector::Inspector&, tint::transform::Manager& m, tint::transform::DataMap&) {
-             m.Add<tint::transform::Renamer>();
+         [](tint::inspector::Inspector&, tint::transform::Manager& m,
+            tint::ast::transform::DataMap&) {
+             m.Add<tint::ast::transform::Renamer>();
              return true;
          }},
         {"robustness",
          [&](tint::inspector::Inspector&, tint::transform::Manager&,
-             tint::transform::DataMap&) {  // enabled via writer option
+             tint::ast::transform::DataMap&) {  // enabled via writer option
              options.enable_robustness = true;
              return true;
          }},
         {"substitute_override",
          [&](tint::inspector::Inspector& inspector, tint::transform::Manager& m,
-             tint::transform::DataMap& i) {
-             tint::transform::SubstituteOverride::Config cfg;
+             tint::ast::transform::DataMap& i) {
+             tint::ast::transform::SubstituteOverride::Config cfg;
 
              std::unordered_map<tint::OverrideId, double> values;
              values.reserve(options.overrides.size());
@@ -998,8 +1000,8 @@
 
              cfg.map = std::move(values);
 
-             i.Add<tint::transform::SubstituteOverride::Config>(cfg);
-             m.Add<tint::transform::SubstituteOverride>();
+             i.Add<tint::ast::transform::SubstituteOverride::Config>(cfg);
+             m.Add<tint::ast::transform::SubstituteOverride>();
              return true;
          }},
     };
@@ -1096,43 +1098,43 @@
     }
 
     tint::transform::Manager transform_manager;
-    tint::transform::DataMap transform_inputs;
+    tint::ast::transform::DataMap transform_inputs;
 
     // Renaming must always come first
     switch (options.format) {
         case Format::kMsl: {
 #if TINT_BUILD_MSL_WRITER
-            transform_inputs.Add<tint::transform::Renamer::Config>(
-                options.rename_all ? tint::transform::Renamer::Target::kAll
-                                   : tint::transform::Renamer::Target::kMslKeywords,
+            transform_inputs.Add<tint::ast::transform::Renamer::Config>(
+                options.rename_all ? tint::ast::transform::Renamer::Target::kAll
+                                   : tint::ast::transform::Renamer::Target::kMslKeywords,
                 /* preserve_unicode */ false);
-            transform_manager.Add<tint::transform::Renamer>();
+            transform_manager.Add<tint::ast::transform::Renamer>();
 #endif  // TINT_BUILD_MSL_WRITER
             break;
         }
 #if TINT_BUILD_GLSL_WRITER
         case Format::kGlsl: {
-            transform_inputs.Add<tint::transform::Renamer::Config>(
-                options.rename_all ? tint::transform::Renamer::Target::kAll
-                                   : tint::transform::Renamer::Target::kGlslKeywords,
+            transform_inputs.Add<tint::ast::transform::Renamer::Config>(
+                options.rename_all ? tint::ast::transform::Renamer::Target::kAll
+                                   : tint::ast::transform::Renamer::Target::kGlslKeywords,
                 /* preserve_unicode */ false);
-            transform_manager.Add<tint::transform::Renamer>();
+            transform_manager.Add<tint::ast::transform::Renamer>();
             break;
         }
 #endif  // TINT_BUILD_GLSL_WRITER
         case Format::kHlsl: {
 #if TINT_BUILD_HLSL_WRITER
-            transform_inputs.Add<tint::transform::Renamer::Config>(
-                options.rename_all ? tint::transform::Renamer::Target::kAll
-                                   : tint::transform::Renamer::Target::kHlslKeywords,
+            transform_inputs.Add<tint::ast::transform::Renamer::Config>(
+                options.rename_all ? tint::ast::transform::Renamer::Target::kAll
+                                   : tint::ast::transform::Renamer::Target::kHlslKeywords,
                 /* preserve_unicode */ false);
-            transform_manager.Add<tint::transform::Renamer>();
+            transform_manager.Add<tint::ast::transform::Renamer>();
 #endif  // TINT_BUILD_HLSL_WRITER
             break;
         }
         default: {
             if (options.rename_all) {
-                transform_manager.Add<tint::transform::Renamer>();
+                transform_manager.Add<tint::ast::transform::Renamer>();
             }
             break;
         }
@@ -1167,8 +1169,8 @@
     }
 
     if (options.emit_single_entry_point) {
-        transform_manager.append(std::make_unique<tint::transform::SingleEntryPoint>());
-        transform_inputs.Add<tint::transform::SingleEntryPoint::Config>(options.ep_name);
+        transform_manager.append(std::make_unique<tint::ast::transform::SingleEntryPoint>());
+        transform_inputs.Add<tint::ast::transform::SingleEntryPoint::Config>(options.ep_name);
     }
 
     auto out = transform_manager.Run(program.get(), std::move(transform_inputs));
diff --git a/src/tint/fuzzers/shuffle_transform.cc b/src/tint/fuzzers/shuffle_transform.cc
index 6ae405a..9a075c2 100644
--- a/src/tint/fuzzers/shuffle_transform.cc
+++ b/src/tint/fuzzers/shuffle_transform.cc
@@ -23,9 +23,9 @@
 
 ShuffleTransform::ShuffleTransform(size_t seed) : seed_(seed) {}
 
-transform::Transform::ApplyResult ShuffleTransform::Apply(const Program* src,
-                                                          const transform::DataMap&,
-                                                          transform::DataMap&) const {
+ast::transform::Transform::ApplyResult ShuffleTransform::Apply(const Program* src,
+                                                               const ast::transform::DataMap&,
+                                                               ast::transform::DataMap&) const {
     ProgramBuilder b;
     CloneContext ctx{&b, src, /* auto_clone_symbols */ true};
 
diff --git a/src/tint/fuzzers/shuffle_transform.h b/src/tint/fuzzers/shuffle_transform.h
index ee54f97..6edbfd7 100644
--- a/src/tint/fuzzers/shuffle_transform.h
+++ b/src/tint/fuzzers/shuffle_transform.h
@@ -15,21 +15,21 @@
 #ifndef SRC_TINT_FUZZERS_SHUFFLE_TRANSFORM_H_
 #define SRC_TINT_FUZZERS_SHUFFLE_TRANSFORM_H_
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
 namespace tint::fuzzers {
 
 /// ShuffleTransform reorders the module scope declarations into a random order
-class ShuffleTransform : public transform::Transform {
+class ShuffleTransform : public ast::transform::Transform {
   public:
     /// Constructor
     /// @param seed the random seed to use for the shuffling
     explicit ShuffleTransform(size_t seed);
 
-    /// @copydoc transform::Transform::Apply
+    /// @copydoc ast::transform::Transform::Apply
     ApplyResult Apply(const Program* program,
-                      const transform::DataMap& inputs,
-                      transform::DataMap& outputs) const override;
+                      const ast::transform::DataMap& inputs,
+                      ast::transform::DataMap& outputs) const override;
 
   private:
     size_t seed_;
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/fuzzer.cc b/src/tint/fuzzers/tint_ast_fuzzer/fuzzer.cc
index 383135d..8e7d397 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/fuzzer.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/fuzzer.cc
@@ -107,7 +107,7 @@
         }
 
         TransformBuilder tb(data, size);
-        tb.AddTransform<tint::transform::Robustness>();
+        tb.AddTransform<tint::ast::transform::Robustness>();
 
         CommonFuzzer fuzzer(InputFormat::kWGSL, target.output_format);
         fuzzer.SetTransformManager(tb.manager(), tb.data_map());
diff --git a/src/tint/fuzzers/tint_binding_remapper_fuzzer.cc b/src/tint/fuzzers/tint_binding_remapper_fuzzer.cc
index 2e62194..767832e 100644
--- a/src/tint/fuzzers/tint_binding_remapper_fuzzer.cc
+++ b/src/tint/fuzzers/tint_binding_remapper_fuzzer.cc
@@ -20,7 +20,7 @@
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
     TransformBuilder tb(data, size);
-    tb.AddTransform<transform::BindingRemapper>();
+    tb.AddTransform<ast::transform::BindingRemapper>();
 
     fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
     fuzzer.SetTransformManager(tb.manager(), tb.data_map());
diff --git a/src/tint/fuzzers/tint_common_fuzzer.cc b/src/tint/fuzzers/tint_common_fuzzer.cc
index 7cbc8bf..122ab87 100644
--- a/src/tint/fuzzers/tint_common_fuzzer.cc
+++ b/src/tint/fuzzers/tint_common_fuzzer.cc
@@ -234,7 +234,7 @@
     {
         // Run SubstituteOverride if required
 
-        transform::SubstituteOverride::Config cfg;
+        ast::transform::SubstituteOverride::Config cfg;
         inspector::Inspector inspector(&program);
         auto default_values = inspector.GetOverrideDefaultValues();
         for (const auto& [override_id, scalar] : default_values) {
@@ -248,11 +248,11 @@
         }
 
         if (!cfg.map.empty()) {
-            transform::DataMap override_data;
-            override_data.Add<transform::SubstituteOverride::Config>(cfg);
+            ast::transform::DataMap override_data;
+            override_data.Add<ast::transform::SubstituteOverride::Config>(cfg);
 
             transform::Manager mgr;
-            mgr.append(std::make_unique<transform::SubstituteOverride>());
+            mgr.append(std::make_unique<ast::transform::SubstituteOverride>());
 
             auto out = mgr.Run(&program, override_data);
             if (!validate_program(out)) {
diff --git a/src/tint/fuzzers/tint_common_fuzzer.h b/src/tint/fuzzers/tint_common_fuzzer.h
index c1cb656..fdf50d5 100644
--- a/src/tint/fuzzers/tint_common_fuzzer.h
+++ b/src/tint/fuzzers/tint_common_fuzzer.h
@@ -63,7 +63,7 @@
 
     /// @param tm manager for transforms to run
     /// @param inputs data for transforms to run
-    void SetTransformManager(transform::Manager* tm, transform::DataMap* inputs) {
+    void SetTransformManager(transform::Manager* tm, ast::transform::DataMap* inputs) {
         assert((!tm || inputs) && "DataMap must be !nullptr if Manager !nullptr");
         transform_manager_ = tm;
         transform_inputs_ = inputs;
@@ -121,7 +121,7 @@
     InputFormat input_;
     OutputFormat output_;
     transform::Manager* transform_manager_ = nullptr;
-    transform::DataMap* transform_inputs_ = nullptr;
+    ast::transform::DataMap* transform_inputs_ = nullptr;
     bool dump_input_ = false;
     tint::diag::List diagnostics_;
     bool enforce_validity = false;
diff --git a/src/tint/fuzzers/tint_first_index_offset_fuzzer.cc b/src/tint/fuzzers/tint_first_index_offset_fuzzer.cc
index 9721798..1946f94 100644
--- a/src/tint/fuzzers/tint_first_index_offset_fuzzer.cc
+++ b/src/tint/fuzzers/tint_first_index_offset_fuzzer.cc
@@ -20,7 +20,7 @@
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
     TransformBuilder tb(data, size);
-    tb.AddTransform<transform::FirstIndexOffset>();
+    tb.AddTransform<ast::transform::FirstIndexOffset>();
 
     fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
     fuzzer.SetTransformManager(tb.manager(), tb.data_map());
diff --git a/src/tint/fuzzers/tint_reader_writer_fuzzer.h b/src/tint/fuzzers/tint_reader_writer_fuzzer.h
index b5d0a95..94c4fc4 100644
--- a/src/tint/fuzzers/tint_reader_writer_fuzzer.h
+++ b/src/tint/fuzzers/tint_reader_writer_fuzzer.h
@@ -38,7 +38,7 @@
     /// invoked.
     /// @param tm manager for transforms to run
     /// @param inputs data for transforms to run
-    void SetTransformManager(transform::Manager* tm, transform::DataMap* inputs) {
+    void SetTransformManager(transform::Manager* tm, ast::transform::DataMap* inputs) {
         tm_set_ = true;
         CommonFuzzer::SetTransformManager(tm, inputs);
     }
diff --git a/src/tint/fuzzers/tint_regex_fuzzer/fuzzer.cc b/src/tint/fuzzers/tint_regex_fuzzer/fuzzer.cc
index f17987d..2c2fd0e 100644
--- a/src/tint/fuzzers/tint_regex_fuzzer/fuzzer.cc
+++ b/src/tint/fuzzers/tint_regex_fuzzer/fuzzer.cc
@@ -163,7 +163,7 @@
         }
 
         TransformBuilder tb(data, size);
-        tb.AddTransform<tint::transform::Robustness>();
+        tb.AddTransform<tint::ast::transform::Robustness>();
 
         CommonFuzzer fuzzer(InputFormat::kWGSL, target.output_format);
         fuzzer.SetTransformManager(tb.manager(), tb.data_map());
diff --git a/src/tint/fuzzers/tint_renamer_fuzzer.cc b/src/tint/fuzzers/tint_renamer_fuzzer.cc
index 467eb68..fa82c63 100644
--- a/src/tint/fuzzers/tint_renamer_fuzzer.cc
+++ b/src/tint/fuzzers/tint_renamer_fuzzer.cc
@@ -20,7 +20,7 @@
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
     TransformBuilder tb(data, size);
-    tb.AddTransform<transform::Renamer>();
+    tb.AddTransform<ast::transform::Renamer>();
 
     fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
     fuzzer.SetTransformManager(tb.manager(), tb.data_map());
diff --git a/src/tint/fuzzers/tint_robustness_fuzzer.cc b/src/tint/fuzzers/tint_robustness_fuzzer.cc
index 4b5eaa6..f82bb53 100644
--- a/src/tint/fuzzers/tint_robustness_fuzzer.cc
+++ b/src/tint/fuzzers/tint_robustness_fuzzer.cc
@@ -12,16 +12,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "src/tint/ast/transform/robustness.h"
 #include "src/tint/fuzzers/fuzzer_init.h"
 #include "src/tint/fuzzers/tint_common_fuzzer.h"
 #include "src/tint/fuzzers/transform_builder.h"
-#include "src/tint/transform/robustness.h"
 
 namespace tint::fuzzers {
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
     TransformBuilder tb(data, size);
-    tb.AddTransform<tint::transform::Robustness>();
+    tb.AddTransform<tint::ast::transform::Robustness>();
 
     tint::fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
     fuzzer.SetTransformManager(tb.manager(), tb.data_map());
diff --git a/src/tint/fuzzers/tint_single_entry_point_fuzzer.cc b/src/tint/fuzzers/tint_single_entry_point_fuzzer.cc
index c0f076a..8f52308 100644
--- a/src/tint/fuzzers/tint_single_entry_point_fuzzer.cc
+++ b/src/tint/fuzzers/tint_single_entry_point_fuzzer.cc
@@ -20,7 +20,7 @@
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
     TransformBuilder tb(data, size);
-    tb.AddTransform<transform::SingleEntryPoint>();
+    tb.AddTransform<ast::transform::SingleEntryPoint>();
 
     fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
     fuzzer.SetTransformManager(tb.manager(), tb.data_map());
diff --git a/src/tint/fuzzers/tint_vertex_pulling_fuzzer.cc b/src/tint/fuzzers/tint_vertex_pulling_fuzzer.cc
index ab0fcf9..c75e854 100644
--- a/src/tint/fuzzers/tint_vertex_pulling_fuzzer.cc
+++ b/src/tint/fuzzers/tint_vertex_pulling_fuzzer.cc
@@ -20,7 +20,7 @@
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
     TransformBuilder tb(data, size);
-    tb.AddTransform<transform::VertexPulling>();
+    tb.AddTransform<ast::transform::VertexPulling>();
 
     tint::fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
     fuzzer.SetTransformManager(tb.manager(), tb.data_map());
diff --git a/src/tint/fuzzers/transform_builder.h b/src/tint/fuzzers/transform_builder.h
index 4dcf604..037568f 100644
--- a/src/tint/fuzzers/transform_builder.h
+++ b/src/tint/fuzzers/transform_builder.h
@@ -20,10 +20,10 @@
 
 #include "include/tint/tint.h"
 
+#include "src/tint/ast/transform/binding_remapper.h"
+#include "src/tint/ast/transform/robustness.h"
 #include "src/tint/fuzzers/data_builder.h"
 #include "src/tint/fuzzers/shuffle_transform.h"
-#include "src/tint/transform/binding_remapper.h"
-#include "src/tint/transform/robustness.h"
 
 namespace tint::fuzzers {
 
@@ -48,32 +48,32 @@
     transform::Manager* manager() { return &manager_; }
 
     /// @returns data for transforms
-    transform::DataMap* data_map() { return &data_map_; }
+    ast::transform::DataMap* data_map() { return &data_map_; }
 
     /// Adds a transform and needed data to |manager_| and |data_map_|.
-    /// @tparam T - A class that inherits from transform::Transform and has an
+    /// @tparam T - A class that inherits from ast::transform::Transform and has an
     ///             explicit specialization in AddTransformImpl.
     template <typename T>
     void AddTransform() {
-        static_assert(std::is_base_of<transform::Transform, T>::value,
-                      "T is not a transform::Transform");
+        static_assert(std::is_base_of<ast::transform::Transform, T>::value,
+                      "T is not a ast::transform::Transform");
         AddTransformImpl<T>::impl(this);
     }
 
     /// Helper that invokes Add*Transform for all of the platform independent
     /// passes.
     void AddPlatformIndependentPasses() {
-        AddTransform<transform::FirstIndexOffset>();
-        AddTransform<transform::BindingRemapper>();
-        AddTransform<transform::Renamer>();
-        AddTransform<transform::SingleEntryPoint>();
-        AddTransform<transform::VertexPulling>();
+        AddTransform<ast::transform::FirstIndexOffset>();
+        AddTransform<ast::transform::BindingRemapper>();
+        AddTransform<ast::transform::Renamer>();
+        AddTransform<ast::transform::SingleEntryPoint>();
+        AddTransform<ast::transform::VertexPulling>();
     }
 
   private:
     DataBuilder builder_;
     transform::Manager manager_;
-    transform::DataMap data_map_;
+    ast::transform::DataMap data_map_;
 
     DataBuilder* builder() { return &builder_; }
 
@@ -94,18 +94,18 @@
         }
     };
 
-    /// Implementation of AddTransform for transform::Robustness
+    /// Implementation of AddTransform for ast::transform::Robustness
     template <>
-    struct AddTransformImpl<transform::Robustness> {
-        /// Add instance of transform::Robustness to TransformBuilder
+    struct AddTransformImpl<ast::transform::Robustness> {
+        /// Add instance of ast::transform::Robustness to TransformBuilder
         /// @param tb - TransformBuilder to add transform to
-        static void impl(TransformBuilder* tb) { tb->manager()->Add<transform::Robustness>(); }
+        static void impl(TransformBuilder* tb) { tb->manager()->Add<ast::transform::Robustness>(); }
     };
 
-    /// Implementation of AddTransform for transform::FirstIndexOffset
+    /// Implementation of AddTransform for ast::transform::FirstIndexOffset
     template <>
-    struct AddTransformImpl<transform::FirstIndexOffset> {
-        /// Add instance of transform::FirstIndexOffset to TransformBuilder
+    struct AddTransformImpl<ast::transform::FirstIndexOffset> {
+        /// Add instance of ast::transform::FirstIndexOffset to TransformBuilder
         /// @param tb - TransformBuilder to add transform to
         static void impl(TransformBuilder* tb) {
             struct Config {
@@ -115,16 +115,16 @@
 
             Config config = tb->builder()->build<Config>();
 
-            tb->data_map()->Add<tint::transform::FirstIndexOffset::BindingPoint>(config.binding,
-                                                                                 config.group);
-            tb->manager()->Add<transform::FirstIndexOffset>();
+            tb->data_map()->Add<tint::ast::transform::FirstIndexOffset::BindingPoint>(
+                config.binding, config.group);
+            tb->manager()->Add<ast::transform::FirstIndexOffset>();
         }
     };
 
-    /// Implementation of AddTransform for transform::BindingRemapper
+    /// Implementation of AddTransform for ast::transform::BindingRemapper
     template <>
-    struct AddTransformImpl<transform::BindingRemapper> {
-        /// Add instance of transform::BindingRemapper to TransformBuilder
+    struct AddTransformImpl<ast::transform::BindingRemapper> {
+        /// Add instance of ast::transform::BindingRemapper to TransformBuilder
         /// @param tb - TransformBuilder to add transform to
         static void impl(TransformBuilder* tb) {
             struct Config {
@@ -136,65 +136,65 @@
             };
 
             std::vector<Config> configs = tb->builder()->vector<Config>();
-            transform::BindingRemapper::BindingPoints binding_points;
-            transform::BindingRemapper::AccessControls accesses;
+            ast::transform::BindingRemapper::BindingPoints binding_points;
+            ast::transform::BindingRemapper::AccessControls accesses;
             for (const auto& config : configs) {
                 binding_points[{config.old_binding, config.old_group}] = {config.new_binding,
                                                                           config.new_group};
                 accesses[{config.old_binding, config.old_group}] = config.new_access;
             }
 
-            tb->data_map()->Add<transform::BindingRemapper::Remappings>(
+            tb->data_map()->Add<ast::transform::BindingRemapper::Remappings>(
                 binding_points, accesses, tb->builder()->build<bool>());
-            tb->manager()->Add<transform::BindingRemapper>();
+            tb->manager()->Add<ast::transform::BindingRemapper>();
         }
     };
 
-    /// Implementation of AddTransform for transform::Renamer
+    /// Implementation of AddTransform for ast::transform::Renamer
     template <>
-    struct AddTransformImpl<transform::Renamer> {
-        /// Add instance of transform::Renamer to TransformBuilder
+    struct AddTransformImpl<ast::transform::Renamer> {
+        /// Add instance of ast::transform::Renamer to TransformBuilder
         /// @param tb - TransformBuilder to add transform to
-        static void impl(TransformBuilder* tb) { tb->manager()->Add<transform::Renamer>(); }
+        static void impl(TransformBuilder* tb) { tb->manager()->Add<ast::transform::Renamer>(); }
     };
 
-    /// Implementation of AddTransform for transform::SingleEntryPoint
+    /// Implementation of AddTransform for ast::transform::SingleEntryPoint
     template <>
-    struct AddTransformImpl<transform::SingleEntryPoint> {
-        /// Add instance of transform::SingleEntryPoint to TransformBuilder
+    struct AddTransformImpl<ast::transform::SingleEntryPoint> {
+        /// Add instance of ast::transform::SingleEntryPoint to TransformBuilder
         /// @param tb - TransformBuilder to add transform to
         static void impl(TransformBuilder* tb) {
             auto input = tb->builder()->build<std::string>();
-            transform::SingleEntryPoint::Config cfg(input);
+            ast::transform::SingleEntryPoint::Config cfg(input);
 
-            tb->data_map()->Add<transform::SingleEntryPoint::Config>(cfg);
-            tb->manager()->Add<transform::SingleEntryPoint>();
+            tb->data_map()->Add<ast::transform::SingleEntryPoint::Config>(cfg);
+            tb->manager()->Add<ast::transform::SingleEntryPoint>();
         }
-    };  // struct AddTransformImpl<transform::SingleEntryPoint>
+    };  // struct AddTransformImpl<ast::transform::SingleEntryPoint>
 
-    /// Implementation of AddTransform for transform::VertexPulling
+    /// Implementation of AddTransform for ast::transform::VertexPulling
     template <>
-    struct AddTransformImpl<transform::VertexPulling> {
-        /// Add instance of transform::VertexPulling to TransformBuilder
+    struct AddTransformImpl<ast::transform::VertexPulling> {
+        /// Add instance of ast::transform::VertexPulling to TransformBuilder
         /// @param tb - TransformBuilder to add transform to
         static void impl(TransformBuilder* tb) {
-            transform::VertexPulling::Config cfg;
-            cfg.vertex_state = tb->builder()->vector<transform::VertexBufferLayoutDescriptor>(
+            ast::transform::VertexPulling::Config cfg;
+            cfg.vertex_state = tb->builder()->vector<ast::transform::VertexBufferLayoutDescriptor>(
                 GenerateVertexBufferLayoutDescriptor);
             cfg.pulling_group = tb->builder()->build<uint32_t>();
 
-            tb->data_map()->Add<transform::VertexPulling::Config>(cfg);
-            tb->manager()->Add<transform::VertexPulling>();
+            tb->data_map()->Add<ast::transform::VertexPulling::Config>(cfg);
+            tb->manager()->Add<ast::transform::VertexPulling>();
         }
 
       private:
-        /// Generate an instance of transform::VertexAttributeDescriptor
+        /// Generate an instance of ast::transform::VertexAttributeDescriptor
         /// @param b - DataBuilder to use
-        static transform::VertexAttributeDescriptor GenerateVertexAttributeDescriptor(
+        static ast::transform::VertexAttributeDescriptor GenerateVertexAttributeDescriptor(
             DataBuilder* b) {
-            transform::VertexAttributeDescriptor desc{};
-            desc.format = b->enum_class<transform::VertexFormat>(
-                static_cast<uint8_t>(transform::VertexFormat::kLastEntry) + 1);
+            ast::transform::VertexAttributeDescriptor desc{};
+            desc.format = b->enum_class<ast::transform::VertexFormat>(
+                static_cast<uint8_t>(ast::transform::VertexFormat::kLastEntry) + 1);
             desc.offset = b->build<uint32_t>();
             desc.shader_location = b->build<uint32_t>();
             return desc;
@@ -202,14 +202,14 @@
 
         /// Generate an instance of VertexBufferLayoutDescriptor
         /// @param b - DataBuilder to use
-        static transform::VertexBufferLayoutDescriptor GenerateVertexBufferLayoutDescriptor(
+        static ast::transform::VertexBufferLayoutDescriptor GenerateVertexBufferLayoutDescriptor(
             DataBuilder* b) {
-            transform::VertexBufferLayoutDescriptor desc;
+            ast::transform::VertexBufferLayoutDescriptor desc;
             desc.array_stride = b->build<uint32_t>();
-            desc.step_mode = b->enum_class<transform::VertexStepMode>(
-                static_cast<uint8_t>(transform::VertexStepMode::kLastEntry) + 1);
-            desc.attributes =
-                b->vector<transform::VertexAttributeDescriptor>(GenerateVertexAttributeDescriptor);
+            desc.step_mode = b->enum_class<ast::transform::VertexStepMode>(
+                static_cast<uint8_t>(ast::transform::VertexStepMode::kLastEntry) + 1);
+            desc.attributes = b->vector<ast::transform::VertexAttributeDescriptor>(
+                GenerateVertexAttributeDescriptor);
             return desc;
         }
     };
diff --git a/src/tint/inspector/entry_point.h b/src/tint/inspector/entry_point.h
index 8fd003c..b26780e 100644
--- a/src/tint/inspector/entry_point.h
+++ b/src/tint/inspector/entry_point.h
@@ -136,7 +136,7 @@
     PipelineStage stage;
     /// The workgroup size. If PipelineStage is kCompute and this holds no value, then the workgroup
     /// size is derived from an override-expression. In this situation you first need to run the
-    /// tint::transform::SubstituteOverride transform before using the inspector.
+    /// tint::ast::transform::SubstituteOverride transform before using the inspector.
     std::optional<WorkgroupSize> workgroup_size;
     /// List of the input variable accessed via this entry point.
     std::vector<StageVariable> input_variables;
diff --git a/src/tint/reader/spirv/function.cc b/src/tint/reader/spirv/function.cc
index 6c1c9f0..bb5d222 100644
--- a/src/tint/reader/spirv/function.cc
+++ b/src/tint/reader/spirv/function.cc
@@ -29,12 +29,12 @@
 #include "src/tint/ast/return_statement.h"
 #include "src/tint/ast/stage_attribute.h"
 #include "src/tint/ast/switch_statement.h"
+#include "src/tint/ast/transform/spirv_atomic.h"
 #include "src/tint/ast/unary_op_expression.h"
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/builtin/builtin_value.h"
 #include "src/tint/builtin/function.h"
 #include "src/tint/switch.h"
-#include "src/tint/transform/spirv_atomic.h"
 #include "src/tint/type/depth_texture.h"
 #include "src/tint/type/sampled_texture.h"
 #include "src/tint/type/texture_dimension.h"
@@ -5821,7 +5821,7 @@
             std::move(params), ret_type,
             /* body */ nullptr,
             utils::Vector{
-                builder_.ASTNodes().Create<transform::SpirvAtomic::Stub>(
+                builder_.ASTNodes().Create<ast::transform::SpirvAtomic::Stub>(
                     builder_.ID(), builder_.AllocateNodeID(), builtin),
                 builder_.Disable(ast::DisabledValidation::kFunctionHasNoBody),
             });
diff --git a/src/tint/reader/spirv/parser.cc b/src/tint/reader/spirv/parser.cc
index 2a1ae18..bc0f258 100644
--- a/src/tint/reader/spirv/parser.cc
+++ b/src/tint/reader/spirv/parser.cc
@@ -16,14 +16,14 @@
 
 #include <utility>
 
+#include "src/tint/ast/transform/decompose_strided_array.h"
+#include "src/tint/ast/transform/decompose_strided_matrix.h"
+#include "src/tint/ast/transform/remove_unreachable_statements.h"
+#include "src/tint/ast/transform/simplify_pointers.h"
+#include "src/tint/ast/transform/spirv_atomic.h"
+#include "src/tint/ast/transform/unshadow.h"
 #include "src/tint/reader/spirv/parser_impl.h"
-#include "src/tint/transform/decompose_strided_array.h"
-#include "src/tint/transform/decompose_strided_matrix.h"
 #include "src/tint/transform/manager.h"
-#include "src/tint/transform/remove_unreachable_statements.h"
-#include "src/tint/transform/simplify_pointers.h"
-#include "src/tint/transform/spirv_atomic.h"
-#include "src/tint/transform/unshadow.h"
 
 namespace tint::reader::spirv {
 
@@ -57,12 +57,12 @@
     }
 
     transform::Manager manager;
-    manager.Add<transform::Unshadow>();
-    manager.Add<transform::SimplifyPointers>();
-    manager.Add<transform::DecomposeStridedMatrix>();
-    manager.Add<transform::DecomposeStridedArray>();
-    manager.Add<transform::RemoveUnreachableStatements>();
-    manager.Add<transform::SpirvAtomic>();
+    manager.Add<ast::transform::Unshadow>();
+    manager.Add<ast::transform::SimplifyPointers>();
+    manager.Add<ast::transform::DecomposeStridedMatrix>();
+    manager.Add<ast::transform::DecomposeStridedArray>();
+    manager.Add<ast::transform::RemoveUnreachableStatements>();
+    manager.Add<ast::transform::SpirvAtomic>();
     return manager.Run(&program).program;
 }
 
diff --git a/src/tint/resolver/attribute_validation_test.cc b/src/tint/resolver/attribute_validation_test.cc
index b9160ce..97af866 100644
--- a/src/tint/resolver/attribute_validation_test.cc
+++ b/src/tint/resolver/attribute_validation_test.cc
@@ -13,10 +13,10 @@
 // limitations under the License.
 
 #include "src/tint/ast/disable_validation_attribute.h"
+#include "src/tint/ast/transform/add_block_attribute.h"
 #include "src/tint/builtin/builtin_value.h"
 #include "src/tint/resolver/resolver.h"
 #include "src/tint/resolver/resolver_test_helper.h"
-#include "src/tint/transform/add_block_attribute.h"
 #include "src/tint/type/texture_dimension.h"
 #include "src/tint/utils/string_stream.h"
 
@@ -625,7 +625,7 @@
 
 namespace StructAndStructMemberTests {
 using StructAttributeTest = TestWithParams;
-using SpirvBlockAttribute = transform::AddBlockAttribute::BlockAttribute;
+using SpirvBlockAttribute = ast::transform::AddBlockAttribute::BlockAttribute;
 TEST_P(StructAttributeTest, IsValid) {
     auto& params = GetParam();
 
diff --git a/src/tint/resolver/builtin_test.cc b/src/tint/resolver/builtin_test.cc
index 60c01f7..5a23354 100644
--- a/src/tint/resolver/builtin_test.cc
+++ b/src/tint/resolver/builtin_test.cc
@@ -2182,11 +2182,11 @@
                                          TextureTestParams{type::TextureDimension::k2dArray},
                                          TextureTestParams{type::TextureDimension::k3d}));
 
-using ResolverBuiltinTest_Texture = ResolverTestWithParam<ast::builtin::test::TextureOverloadCase>;
+using ResolverBuiltinTest_Texture = ResolverTestWithParam<ast::test::TextureOverloadCase>;
 
 INSTANTIATE_TEST_SUITE_P(ResolverTest,
                          ResolverBuiltinTest_Texture,
-                         testing::ValuesIn(ast::builtin::test::TextureOverloadCase::ValidCases()));
+                         testing::ValuesIn(ast::test::TextureOverloadCase::ValidCases()));
 
 static std::string to_str(const std::string& function,
                           utils::VectorRef<const sem::Parameter*> params) {
@@ -2204,8 +2204,8 @@
     return out.str();
 }
 
-static const char* expected_texture_overload(ast::builtin::test::ValidTextureOverload overload) {
-    using ValidTextureOverload = ast::builtin::test::ValidTextureOverload;
+static const char* expected_texture_overload(ast::test::ValidTextureOverload overload) {
+    using ValidTextureOverload = ast::test::ValidTextureOverload;
     switch (overload) {
         case ValidTextureOverload::kDimensions1d:
         case ValidTextureOverload::kDimensions2d:
@@ -2491,13 +2491,13 @@
         ASSERT_NE(vec, nullptr);
         EXPECT_EQ(vec->Width(), 4u);
         switch (param.texture_data_type) {
-            case ast::builtin::test::TextureDataType::kF32:
+            case ast::test::TextureDataType::kF32:
                 EXPECT_TRUE(vec->type()->Is<type::F32>());
                 break;
-            case ast::builtin::test::TextureDataType::kU32:
+            case ast::test::TextureDataType::kU32:
                 EXPECT_TRUE(vec->type()->Is<type::U32>());
                 break;
-            case ast::builtin::test::TextureDataType::kI32:
+            case ast::test::TextureDataType::kI32:
                 EXPECT_TRUE(vec->type()->Is<type::I32>());
                 break;
         }
@@ -2508,26 +2508,26 @@
         EXPECT_TRUE(vec->type()->Is<type::F32>());
     } else {
         switch (param.texture_kind) {
-            case ast::builtin::test::TextureKind::kRegular:
-            case ast::builtin::test::TextureKind::kMultisampled:
-            case ast::builtin::test::TextureKind::kStorage: {
+            case ast::test::TextureKind::kRegular:
+            case ast::test::TextureKind::kMultisampled:
+            case ast::test::TextureKind::kStorage: {
                 auto* vec = TypeOf(call)->As<type::Vector>();
                 ASSERT_NE(vec, nullptr);
                 switch (param.texture_data_type) {
-                    case ast::builtin::test::TextureDataType::kF32:
+                    case ast::test::TextureDataType::kF32:
                         EXPECT_TRUE(vec->type()->Is<type::F32>());
                         break;
-                    case ast::builtin::test::TextureDataType::kU32:
+                    case ast::test::TextureDataType::kU32:
                         EXPECT_TRUE(vec->type()->Is<type::U32>());
                         break;
-                    case ast::builtin::test::TextureDataType::kI32:
+                    case ast::test::TextureDataType::kI32:
                         EXPECT_TRUE(vec->type()->Is<type::I32>());
                         break;
                 }
                 break;
             }
-            case ast::builtin::test::TextureKind::kDepth:
-            case ast::builtin::test::TextureKind::kDepthMultisampled: {
+            case ast::test::TextureKind::kDepth:
+            case ast::test::TextureKind::kDepthMultisampled: {
                 EXPECT_TRUE(TypeOf(call)->Is<type::F32>());
                 break;
             }
diff --git a/src/tint/resolver/builtin_validation_test.cc b/src/tint/resolver/builtin_validation_test.cc
index d074703..fbe5a5f 100644
--- a/src/tint/resolver/builtin_validation_test.cc
+++ b/src/tint/resolver/builtin_validation_test.cc
@@ -196,10 +196,10 @@
 
 namespace texture_constexpr_args {
 
-using TextureOverloadCase = ast::builtin::test::TextureOverloadCase;
-using ValidTextureOverload = ast::builtin::test::ValidTextureOverload;
-using TextureKind = ast::builtin::test::TextureKind;
-using TextureDataType = ast::builtin::test::TextureDataType;
+using TextureOverloadCase = ast::test::TextureOverloadCase;
+using ValidTextureOverload = ast::test::ValidTextureOverload;
+using TextureKind = ast::test::TextureKind;
+using TextureDataType = ast::test::TextureDataType;
 
 static std::vector<TextureOverloadCase> TextureCases(
     std::unordered_set<ValidTextureOverload> overloads) {
diff --git a/src/tint/transform/manager.cc b/src/tint/transform/manager.cc
index ca23a40..b2e6c80 100644
--- a/src/tint/transform/manager.cc
+++ b/src/tint/transform/manager.cc
@@ -32,9 +32,9 @@
 Manager::Manager() = default;
 Manager::~Manager() = default;
 
-Transform::ApplyResult Manager::Apply(const Program* program,
-                                      const DataMap& inputs,
-                                      DataMap& outputs) const {
+ast::transform::Transform::ApplyResult Manager::Apply(const Program* program,
+                                                      const ast::transform::DataMap& inputs,
+                                                      ast::transform::DataMap& outputs) const {
 #if TINT_PRINT_PROGRAM_FOR_EACH_TRANSFORM
     auto print_program = [&](const char* msg, const Transform* transform) {
         auto wgsl = Program::printer(program);
diff --git a/src/tint/transform/manager.h b/src/tint/transform/manager.h
index a364c1a..c7b9286 100644
--- a/src/tint/transform/manager.h
+++ b/src/tint/transform/manager.h
@@ -19,7 +19,7 @@
 #include <utility>
 #include <vector>
 
-#include "src/tint/transform/transform.h"
+#include "src/tint/ast/transform/transform.h"
 
 namespace tint::transform {
 
@@ -27,7 +27,7 @@
 /// The inner transforms will execute in the appended order.
 /// If any inner transform fails the manager will return immediately and
 /// the error can be retrieved with the Output's diagnostics.
-class Manager final : public utils::Castable<Manager, Transform> {
+class Manager final : public tint::utils::Castable<Manager, ast::transform::Transform> {
   public:
     /// Constructor
     Manager();
@@ -47,10 +47,10 @@
         transforms_.emplace_back(std::make_unique<T>(std::forward<ARGS>(args)...));
     }
 
-    /// @copydoc Transform::Apply
+    /// @copydoc ast::transform::Transform::Apply
     ApplyResult Apply(const Program* program,
-                      const DataMap& inputs,
-                      DataMap& outputs) const override;
+                      const ast::transform::DataMap& inputs,
+                      ast::transform::DataMap& outputs) const override;
 
   private:
     std::vector<std::unique_ptr<Transform>> transforms_;
diff --git a/src/tint/writer/flatten_bindings.cc b/src/tint/writer/flatten_bindings.cc
index 3b5b2ad..3aa659d 100644
--- a/src/tint/writer/flatten_bindings.cc
+++ b/src/tint/writer/flatten_bindings.cc
@@ -16,8 +16,8 @@
 
 #include <utility>
 
+#include "src/tint/ast/transform/binding_remapper.h"
 #include "src/tint/inspector/inspector.h"
-#include "src/tint/transform/binding_remapper.h"
 #include "src/tint/transform/manager.h"
 #include "src/tint/writer/binding_point.h"
 
@@ -25,7 +25,7 @@
 
 std::optional<Program> FlattenBindings(const Program* program) {
     // TODO(crbug.com/tint/1101): Make this more robust for multiple entry points.
-    tint::transform::BindingRemapper::BindingPoints binding_points;
+    tint::ast::transform::BindingRemapper::BindingPoints binding_points;
     uint32_t next_buffer_idx = 0;
     uint32_t next_sampler_idx = 0;
     uint32_t next_texture_idx = 0;
@@ -63,14 +63,14 @@
     }
 
     // Run the binding remapper transform.
-    tint::transform::Output transform_output;
+    tint::ast::transform::Output transform_output;
     if (!binding_points.empty()) {
         tint::transform::Manager manager;
-        tint::transform::DataMap inputs;
-        inputs.Add<tint::transform::BindingRemapper::Remappings>(
-            std::move(binding_points), tint::transform::BindingRemapper::AccessControls{},
+        tint::ast::transform::DataMap inputs;
+        inputs.Add<tint::ast::transform::BindingRemapper::Remappings>(
+            std::move(binding_points), tint::ast::transform::BindingRemapper::AccessControls{},
             /* mayCollide */ true);
-        manager.Add<tint::transform::BindingRemapper>();
+        manager.Add<tint::ast::transform::BindingRemapper>();
         transform_output = manager.Run(program, inputs);
         return std::move(transform_output.program);
     }
diff --git a/src/tint/writer/glsl/generator.cc b/src/tint/writer/glsl/generator.cc
index fa2e0e8..24b7597 100644
--- a/src/tint/writer/glsl/generator.cc
+++ b/src/tint/writer/glsl/generator.cc
@@ -14,8 +14,8 @@
 
 #include "src/tint/writer/glsl/generator.h"
 
-#include "src/tint/transform/binding_remapper.h"
-#include "src/tint/transform/combine_samplers.h"
+#include "src/tint/ast/transform/binding_remapper.h"
+#include "src/tint/ast/transform/combine_samplers.h"
 #include "src/tint/writer/glsl/generator_impl.h"
 
 namespace tint::writer::glsl {
diff --git a/src/tint/writer/glsl/generator_impl.cc b/src/tint/writer/glsl/generator_impl.cc
index 9e1fbd8..d3d8130 100644
--- a/src/tint/writer/glsl/generator_impl.cc
+++ b/src/tint/writer/glsl/generator_impl.cc
@@ -26,6 +26,31 @@
 #include "src/tint/ast/id_attribute.h"
 #include "src/tint/ast/internal_attribute.h"
 #include "src/tint/ast/interpolate_attribute.h"
+#include "src/tint/ast/transform/add_block_attribute.h"
+#include "src/tint/ast/transform/add_empty_entry_point.h"
+#include "src/tint/ast/transform/binding_remapper.h"
+#include "src/tint/ast/transform/builtin_polyfill.h"
+#include "src/tint/ast/transform/canonicalize_entry_point_io.h"
+#include "src/tint/ast/transform/combine_samplers.h"
+#include "src/tint/ast/transform/decompose_memory_access.h"
+#include "src/tint/ast/transform/demote_to_helper.h"
+#include "src/tint/ast/transform/direct_variable_access.h"
+#include "src/tint/ast/transform/disable_uniformity_analysis.h"
+#include "src/tint/ast/transform/expand_compound_assignment.h"
+#include "src/tint/ast/transform/multiplanar_external_texture.h"
+#include "src/tint/ast/transform/pad_structs.h"
+#include "src/tint/ast/transform/preserve_padding.h"
+#include "src/tint/ast/transform/promote_initializers_to_let.h"
+#include "src/tint/ast/transform/promote_side_effects_to_decl.h"
+#include "src/tint/ast/transform/remove_phonies.h"
+#include "src/tint/ast/transform/renamer.h"
+#include "src/tint/ast/transform/robustness.h"
+#include "src/tint/ast/transform/simplify_pointers.h"
+#include "src/tint/ast/transform/single_entry_point.h"
+#include "src/tint/ast/transform/std140.h"
+#include "src/tint/ast/transform/texture_1d_to_2d.h"
+#include "src/tint/ast/transform/unshadow.h"
+#include "src/tint/ast/transform/zero_init_workgroup_memory.h"
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/constant/value.h"
 #include "src/tint/debug.h"
@@ -41,32 +66,7 @@
 #include "src/tint/sem/value_conversion.h"
 #include "src/tint/sem/variable.h"
 #include "src/tint/switch.h"
-#include "src/tint/transform/add_block_attribute.h"
-#include "src/tint/transform/add_empty_entry_point.h"
-#include "src/tint/transform/binding_remapper.h"
-#include "src/tint/transform/builtin_polyfill.h"
-#include "src/tint/transform/canonicalize_entry_point_io.h"
-#include "src/tint/transform/combine_samplers.h"
-#include "src/tint/transform/decompose_memory_access.h"
-#include "src/tint/transform/demote_to_helper.h"
-#include "src/tint/transform/direct_variable_access.h"
-#include "src/tint/transform/disable_uniformity_analysis.h"
-#include "src/tint/transform/expand_compound_assignment.h"
 #include "src/tint/transform/manager.h"
-#include "src/tint/transform/multiplanar_external_texture.h"
-#include "src/tint/transform/pad_structs.h"
-#include "src/tint/transform/preserve_padding.h"
-#include "src/tint/transform/promote_initializers_to_let.h"
-#include "src/tint/transform/promote_side_effects_to_decl.h"
-#include "src/tint/transform/remove_phonies.h"
-#include "src/tint/transform/renamer.h"
-#include "src/tint/transform/robustness.h"
-#include "src/tint/transform/simplify_pointers.h"
-#include "src/tint/transform/single_entry_point.h"
-#include "src/tint/transform/std140.h"
-#include "src/tint/transform/texture_1d_to_2d.h"
-#include "src/tint/transform/unshadow.h"
-#include "src/tint/transform/zero_init_workgroup_memory.h"
 #include "src/tint/type/array.h"
 #include "src/tint/type/atomic.h"
 #include "src/tint/type/depth_multisampled_texture.h"
@@ -152,99 +152,99 @@
                          const Options& options,
                          const std::string& entry_point) {
     transform::Manager manager;
-    transform::DataMap data;
+    ast::transform::DataMap data;
 
-    manager.Add<transform::DisableUniformityAnalysis>();
+    manager.Add<ast::transform::DisableUniformityAnalysis>();
 
     // ExpandCompoundAssignment must come before BuiltinPolyfill
-    manager.Add<transform::ExpandCompoundAssignment>();
+    manager.Add<ast::transform::ExpandCompoundAssignment>();
 
     if (!entry_point.empty()) {
-        manager.Add<transform::SingleEntryPoint>();
-        data.Add<transform::SingleEntryPoint::Config>(entry_point);
+        manager.Add<ast::transform::SingleEntryPoint>();
+        data.Add<ast::transform::SingleEntryPoint::Config>(entry_point);
     }
-    manager.Add<transform::Renamer>();
-    data.Add<transform::Renamer::Config>(transform::Renamer::Target::kGlslKeywords,
-                                         /* preserve_unicode */ false);
+    manager.Add<ast::transform::Renamer>();
+    data.Add<ast::transform::Renamer::Config>(ast::transform::Renamer::Target::kGlslKeywords,
+                                              /* preserve_unicode */ false);
 
-    manager.Add<transform::PreservePadding>();  // Must come before DirectVariableAccess
+    manager.Add<ast::transform::PreservePadding>();  // Must come before DirectVariableAccess
 
-    manager.Add<transform::Unshadow>();  // Must come before DirectVariableAccess
+    manager.Add<ast::transform::Unshadow>();  // Must come before DirectVariableAccess
 
-    manager.Add<transform::PromoteSideEffectsToDecl>();
+    manager.Add<ast::transform::PromoteSideEffectsToDecl>();
 
     if (!options.disable_robustness) {
         // Robustness must come after PromoteSideEffectsToDecl
         // Robustness must come before BuiltinPolyfill and CanonicalizeEntryPointIO
-        manager.Add<transform::Robustness>();
+        manager.Add<ast::transform::Robustness>();
     }
 
     // Note: it is more efficient for MultiplanarExternalTexture to come after Robustness
-    data.Add<transform::MultiplanarExternalTexture::NewBindingPoints>(
+    data.Add<ast::transform::MultiplanarExternalTexture::NewBindingPoints>(
         options.external_texture_options.bindings_map);
-    manager.Add<transform::MultiplanarExternalTexture>();
+    manager.Add<ast::transform::MultiplanarExternalTexture>();
 
     {  // Builtin polyfills
-        transform::BuiltinPolyfill::Builtins polyfills;
-        polyfills.acosh = transform::BuiltinPolyfill::Level::kRangeCheck;
-        polyfills.atanh = transform::BuiltinPolyfill::Level::kRangeCheck;
+        ast::transform::BuiltinPolyfill::Builtins polyfills;
+        polyfills.acosh = ast::transform::BuiltinPolyfill::Level::kRangeCheck;
+        polyfills.atanh = ast::transform::BuiltinPolyfill::Level::kRangeCheck;
         polyfills.bgra8unorm = true;
         polyfills.bitshift_modulo = true;
         polyfills.conv_f32_to_iu32 = true;
         polyfills.count_leading_zeros = true;
         polyfills.count_trailing_zeros = true;
-        polyfills.extract_bits = transform::BuiltinPolyfill::Level::kClampParameters;
+        polyfills.extract_bits = ast::transform::BuiltinPolyfill::Level::kClampParameters;
         polyfills.first_leading_bit = true;
         polyfills.first_trailing_bit = true;
-        polyfills.insert_bits = transform::BuiltinPolyfill::Level::kClampParameters;
+        polyfills.insert_bits = ast::transform::BuiltinPolyfill::Level::kClampParameters;
         polyfills.int_div_mod = true;
         polyfills.saturate = true;
         polyfills.texture_sample_base_clamp_to_edge_2d_f32 = true;
         polyfills.workgroup_uniform_load = true;
-        data.Add<transform::BuiltinPolyfill::Config>(polyfills);
-        manager.Add<transform::BuiltinPolyfill>();  // Must come before DirectVariableAccess
+        data.Add<ast::transform::BuiltinPolyfill::Config>(polyfills);
+        manager.Add<ast::transform::BuiltinPolyfill>();  // Must come before DirectVariableAccess
     }
 
-    manager.Add<transform::DirectVariableAccess>();
+    manager.Add<ast::transform::DirectVariableAccess>();
 
     if (!options.disable_workgroup_init) {
         // ZeroInitWorkgroupMemory must come before CanonicalizeEntryPointIO as
         // ZeroInitWorkgroupMemory may inject new builtin parameters.
-        manager.Add<transform::ZeroInitWorkgroupMemory>();
+        manager.Add<ast::transform::ZeroInitWorkgroupMemory>();
     }
 
     // CanonicalizeEntryPointIO must come after Robustness
-    manager.Add<transform::CanonicalizeEntryPointIO>();
+    manager.Add<ast::transform::CanonicalizeEntryPointIO>();
 
     // PadStructs must come after CanonicalizeEntryPointIO
-    manager.Add<transform::PadStructs>();
+    manager.Add<ast::transform::PadStructs>();
 
     // DemoteToHelper must come after PromoteSideEffectsToDecl and ExpandCompoundAssignment.
-    manager.Add<transform::DemoteToHelper>();
+    manager.Add<ast::transform::DemoteToHelper>();
 
-    manager.Add<transform::RemovePhonies>();
+    manager.Add<ast::transform::RemovePhonies>();
 
-    data.Add<transform::CombineSamplers::BindingInfo>(options.binding_map,
-                                                      options.placeholder_binding_point);
-    manager.Add<transform::CombineSamplers>();
+    data.Add<ast::transform::CombineSamplers::BindingInfo>(options.binding_map,
+                                                           options.placeholder_binding_point);
+    manager.Add<ast::transform::CombineSamplers>();
 
-    data.Add<transform::BindingRemapper::Remappings>(
+    data.Add<ast::transform::BindingRemapper::Remappings>(
         options.binding_points, options.access_controls, options.allow_collisions);
-    manager.Add<transform::BindingRemapper>();
+    manager.Add<ast::transform::BindingRemapper>();
 
-    manager.Add<transform::PromoteInitializersToLet>();
-    manager.Add<transform::AddEmptyEntryPoint>();
-    manager.Add<transform::AddBlockAttribute>();
+    manager.Add<ast::transform::PromoteInitializersToLet>();
+    manager.Add<ast::transform::AddEmptyEntryPoint>();
+    manager.Add<ast::transform::AddBlockAttribute>();
 
     // Std140 must come after PromoteSideEffectsToDecl and before SimplifyPointers.
-    manager.Add<transform::Std140>();
+    manager.Add<ast::transform::Std140>();
 
-    manager.Add<transform::Texture1DTo2D>();
+    manager.Add<ast::transform::Texture1DTo2D>();
 
-    manager.Add<transform::SimplifyPointers>();
+    manager.Add<ast::transform::SimplifyPointers>();
 
-    data.Add<transform::CanonicalizeEntryPointIO::Config>(
-        transform::CanonicalizeEntryPointIO::ShaderStyle::kGlsl);
+    data.Add<ast::transform::CanonicalizeEntryPointIO::Config>(
+        ast::transform::CanonicalizeEntryPointIO::ShaderStyle::kGlsl);
 
     auto out = manager.Run(in, data);
 
@@ -286,8 +286,9 @@
                 if (auto* arr = sem->Members().Back()->Type()->As<type::Array>()) {
                     has_rt_arr = arr->Count()->Is<type::RuntimeArrayCount>();
                 }
-                bool is_block = ast::HasAttribute<transform::AddBlockAttribute::BlockAttribute>(
-                    str->attributes);
+                bool is_block =
+                    ast::HasAttribute<ast::transform::AddBlockAttribute::BlockAttribute>(
+                        str->attributes);
                 if (!has_rt_arr && !is_block) {
                     EmitStructType(current_buffer_, sem);
                 }
diff --git a/src/tint/writer/glsl/generator_impl.h b/src/tint/writer/glsl/generator_impl.h
index 5d74e37..7f9e31c 100644
--- a/src/tint/writer/glsl/generator_impl.h
+++ b/src/tint/writer/glsl/generator_impl.h
@@ -31,11 +31,11 @@
 #include "src/tint/ast/loop_statement.h"
 #include "src/tint/ast/return_statement.h"
 #include "src/tint/ast/switch_statement.h"
+#include "src/tint/ast/transform/decompose_memory_access.h"
 #include "src/tint/ast/unary_op_expression.h"
 #include "src/tint/builtin/builtin_value.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/scope_stack.h"
-#include "src/tint/transform/decompose_memory_access.h"
 #include "src/tint/utils/hash.h"
 #include "src/tint/utils/string_stream.h"
 #include "src/tint/writer/glsl/generator.h"
diff --git a/src/tint/writer/glsl/generator_impl_builtin_texture_test.cc b/src/tint/writer/glsl/generator_impl_builtin_texture_test.cc
index ca8abe4..fbfb8ec 100644
--- a/src/tint/writer/glsl/generator_impl_builtin_texture_test.cc
+++ b/src/tint/writer/glsl/generator_impl_builtin_texture_test.cc
@@ -30,8 +30,8 @@
     std::string out;
 };
 
-ExpectedResult expected_texture_overload(ast::builtin::test::ValidTextureOverload overload) {
-    using ValidTextureOverload = ast::builtin::test::ValidTextureOverload;
+ExpectedResult expected_texture_overload(ast::test::ValidTextureOverload overload) {
+    using ValidTextureOverload = ast::test::ValidTextureOverload;
     switch (overload) {
         case ValidTextureOverload::kDimensions1d:
         case ValidTextureOverload::kDimensions2d:
@@ -271,8 +271,7 @@
     return "<unmatched texture overload>";
 }  // NOLINT - Ignore the length of this function
 
-class GlslGeneratorBuiltinTextureTest
-    : public TestParamHelper<ast::builtin::test::TextureOverloadCase> {};
+class GlslGeneratorBuiltinTextureTest : public TestParamHelper<ast::test::TextureOverloadCase> {};
 
 TEST_P(GlslGeneratorBuiltinTextureTest, Call) {
     auto param = GetParam();
@@ -300,7 +299,7 @@
 
 INSTANTIATE_TEST_SUITE_P(GlslGeneratorBuiltinTextureTest,
                          GlslGeneratorBuiltinTextureTest,
-                         testing::ValuesIn(ast::builtin::test::TextureOverloadCase::ValidCases()));
+                         testing::ValuesIn(ast::test::TextureOverloadCase::ValidCases()));
 
 }  // namespace
 }  // namespace tint::writer::glsl
diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc
index 81a07d2..c9ebddd 100644
--- a/src/tint/writer/hlsl/generator_impl.cc
+++ b/src/tint/writer/hlsl/generator_impl.cc
@@ -26,6 +26,30 @@
 #include "src/tint/ast/id_attribute.h"
 #include "src/tint/ast/internal_attribute.h"
 #include "src/tint/ast/interpolate_attribute.h"
+#include "src/tint/ast/transform/add_empty_entry_point.h"
+#include "src/tint/ast/transform/array_length_from_uniform.h"
+#include "src/tint/ast/transform/binding_remapper.h"
+#include "src/tint/ast/transform/builtin_polyfill.h"
+#include "src/tint/ast/transform/calculate_array_length.h"
+#include "src/tint/ast/transform/canonicalize_entry_point_io.h"
+#include "src/tint/ast/transform/decompose_memory_access.h"
+#include "src/tint/ast/transform/demote_to_helper.h"
+#include "src/tint/ast/transform/direct_variable_access.h"
+#include "src/tint/ast/transform/disable_uniformity_analysis.h"
+#include "src/tint/ast/transform/expand_compound_assignment.h"
+#include "src/tint/ast/transform/localize_struct_array_assignment.h"
+#include "src/tint/ast/transform/multiplanar_external_texture.h"
+#include "src/tint/ast/transform/num_workgroups_from_uniform.h"
+#include "src/tint/ast/transform/promote_initializers_to_let.h"
+#include "src/tint/ast/transform/promote_side_effects_to_decl.h"
+#include "src/tint/ast/transform/remove_continue_in_switch.h"
+#include "src/tint/ast/transform/remove_phonies.h"
+#include "src/tint/ast/transform/robustness.h"
+#include "src/tint/ast/transform/simplify_pointers.h"
+#include "src/tint/ast/transform/truncate_interstage_variables.h"
+#include "src/tint/ast/transform/unshadow.h"
+#include "src/tint/ast/transform/vectorize_scalar_matrix_initializers.h"
+#include "src/tint/ast/transform/zero_init_workgroup_memory.h"
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/constant/value.h"
 #include "src/tint/debug.h"
@@ -41,31 +65,7 @@
 #include "src/tint/sem/value_conversion.h"
 #include "src/tint/sem/variable.h"
 #include "src/tint/switch.h"
-#include "src/tint/transform/add_empty_entry_point.h"
-#include "src/tint/transform/array_length_from_uniform.h"
-#include "src/tint/transform/binding_remapper.h"
-#include "src/tint/transform/builtin_polyfill.h"
-#include "src/tint/transform/calculate_array_length.h"
-#include "src/tint/transform/canonicalize_entry_point_io.h"
-#include "src/tint/transform/decompose_memory_access.h"
-#include "src/tint/transform/demote_to_helper.h"
-#include "src/tint/transform/direct_variable_access.h"
-#include "src/tint/transform/disable_uniformity_analysis.h"
-#include "src/tint/transform/expand_compound_assignment.h"
-#include "src/tint/transform/localize_struct_array_assignment.h"
 #include "src/tint/transform/manager.h"
-#include "src/tint/transform/multiplanar_external_texture.h"
-#include "src/tint/transform/num_workgroups_from_uniform.h"
-#include "src/tint/transform/promote_initializers_to_let.h"
-#include "src/tint/transform/promote_side_effects_to_decl.h"
-#include "src/tint/transform/remove_continue_in_switch.h"
-#include "src/tint/transform/remove_phonies.h"
-#include "src/tint/transform/robustness.h"
-#include "src/tint/transform/simplify_pointers.h"
-#include "src/tint/transform/truncate_interstage_variables.h"
-#include "src/tint/transform/unshadow.h"
-#include "src/tint/transform/vectorize_scalar_matrix_initializers.h"
-#include "src/tint/transform/zero_init_workgroup_memory.h"
 #include "src/tint/type/array.h"
 #include "src/tint/type/atomic.h"
 #include "src/tint/type/depth_multisampled_texture.h"
@@ -167,14 +167,14 @@
 
 SanitizedResult Sanitize(const Program* in, const Options& options) {
     transform::Manager manager;
-    transform::DataMap data;
+    ast::transform::DataMap data;
 
-    manager.Add<transform::DisableUniformityAnalysis>();
+    manager.Add<ast::transform::DisableUniformityAnalysis>();
 
     // ExpandCompoundAssignment must come before BuiltinPolyfill
-    manager.Add<transform::ExpandCompoundAssignment>();
+    manager.Add<ast::transform::ExpandCompoundAssignment>();
 
-    manager.Add<transform::Unshadow>();  // Must come before DirectVariableAccess
+    manager.Add<ast::transform::Unshadow>();  // Must come before DirectVariableAccess
 
     // LocalizeStructArrayAssignment must come after:
     // * SimplifyPointers, because it assumes assignment to arrays in structs are
@@ -182,34 +182,34 @@
     // TODO(crbug.com/tint/1340): See if we can get rid of the duplicate
     // SimplifyPointers transform. Can't do it right now because
     // LocalizeStructArrayAssignment introduces pointers.
-    manager.Add<transform::SimplifyPointers>();
-    manager.Add<transform::LocalizeStructArrayAssignment>();
+    manager.Add<ast::transform::SimplifyPointers>();
+    manager.Add<ast::transform::LocalizeStructArrayAssignment>();
 
-    manager.Add<transform::PromoteSideEffectsToDecl>();
+    manager.Add<ast::transform::PromoteSideEffectsToDecl>();
 
     if (!options.disable_robustness) {
         // Robustness must come after PromoteSideEffectsToDecl
         // Robustness must come before BuiltinPolyfill and CanonicalizeEntryPointIO
-        manager.Add<transform::Robustness>();
+        manager.Add<ast::transform::Robustness>();
     }
 
     // Note: it is more efficient for MultiplanarExternalTexture to come after Robustness
-    data.Add<transform::MultiplanarExternalTexture::NewBindingPoints>(
+    data.Add<ast::transform::MultiplanarExternalTexture::NewBindingPoints>(
         options.external_texture_options.bindings_map);
-    manager.Add<transform::MultiplanarExternalTexture>();
+    manager.Add<ast::transform::MultiplanarExternalTexture>();
 
     // BindingRemapper must come after MultiplanarExternalTexture
-    manager.Add<transform::BindingRemapper>();
-    data.Add<transform::BindingRemapper::Remappings>(
+    manager.Add<ast::transform::BindingRemapper>();
+    data.Add<ast::transform::BindingRemapper::Remappings>(
         options.binding_remapper_options.binding_points,
         options.binding_remapper_options.access_controls,
         options.binding_remapper_options.allow_collisions);
 
     {  // Builtin polyfills
-        transform::BuiltinPolyfill::Builtins polyfills;
-        polyfills.acosh = transform::BuiltinPolyfill::Level::kFull;
+        ast::transform::BuiltinPolyfill::Builtins polyfills;
+        polyfills.acosh = ast::transform::BuiltinPolyfill::Level::kFull;
         polyfills.asinh = true;
-        polyfills.atanh = transform::BuiltinPolyfill::Level::kFull;
+        polyfills.atanh = ast::transform::BuiltinPolyfill::Level::kFull;
         polyfills.bitshift_modulo = true;
         polyfills.clamp_int = true;
         // TODO(crbug.com/tint/1449): Some of these can map to HLSL's `firstbitlow`
@@ -217,29 +217,29 @@
         polyfills.conv_f32_to_iu32 = true;
         polyfills.count_leading_zeros = true;
         polyfills.count_trailing_zeros = true;
-        polyfills.extract_bits = transform::BuiltinPolyfill::Level::kFull;
+        polyfills.extract_bits = ast::transform::BuiltinPolyfill::Level::kFull;
         polyfills.first_leading_bit = true;
         polyfills.first_trailing_bit = true;
-        polyfills.insert_bits = transform::BuiltinPolyfill::Level::kFull;
+        polyfills.insert_bits = ast::transform::BuiltinPolyfill::Level::kFull;
         polyfills.int_div_mod = true;
         polyfills.precise_float_mod = true;
         polyfills.reflect_vec2_f32 = options.polyfill_reflect_vec2_f32;
         polyfills.texture_sample_base_clamp_to_edge_2d_f32 = true;
         polyfills.workgroup_uniform_load = true;
-        data.Add<transform::BuiltinPolyfill::Config>(polyfills);
-        manager.Add<transform::BuiltinPolyfill>();  // Must come before DirectVariableAccess
+        data.Add<ast::transform::BuiltinPolyfill::Config>(polyfills);
+        manager.Add<ast::transform::BuiltinPolyfill>();  // Must come before DirectVariableAccess
     }
 
-    manager.Add<transform::DirectVariableAccess>();
+    manager.Add<ast::transform::DirectVariableAccess>();
 
     if (!options.disable_workgroup_init) {
         // ZeroInitWorkgroupMemory must come before CanonicalizeEntryPointIO as
         // ZeroInitWorkgroupMemory may inject new builtin parameters.
-        manager.Add<transform::ZeroInitWorkgroupMemory>();
+        manager.Add<ast::transform::ZeroInitWorkgroupMemory>();
     }
 
     // CanonicalizeEntryPointIO must come after Robustness
-    manager.Add<transform::CanonicalizeEntryPointIO>();
+    manager.Add<ast::transform::CanonicalizeEntryPointIO>();
 
     if (options.truncate_interstage_variables) {
         // When interstage_locations is empty, it means there's no user-defined interstage variables
@@ -251,25 +251,25 @@
         // with the current stage output.
 
         // Build the config for internal TruncateInterstageVariables transform.
-        transform::TruncateInterstageVariables::Config truncate_interstage_variables_cfg;
+        ast::transform::TruncateInterstageVariables::Config truncate_interstage_variables_cfg;
         truncate_interstage_variables_cfg.interstage_locations =
             std::move(options.interstage_locations);
-        manager.Add<transform::TruncateInterstageVariables>();
-        data.Add<transform::TruncateInterstageVariables::Config>(
+        manager.Add<ast::transform::TruncateInterstageVariables>();
+        data.Add<ast::transform::TruncateInterstageVariables::Config>(
             std::move(truncate_interstage_variables_cfg));
     }
 
     // NumWorkgroupsFromUniform must come after CanonicalizeEntryPointIO, as it
     // assumes that num_workgroups builtins only appear as struct members and are
     // only accessed directly via member accessors.
-    manager.Add<transform::NumWorkgroupsFromUniform>();
-    manager.Add<transform::VectorizeScalarMatrixInitializers>();
-    manager.Add<transform::SimplifyPointers>();
-    manager.Add<transform::RemovePhonies>();
+    manager.Add<ast::transform::NumWorkgroupsFromUniform>();
+    manager.Add<ast::transform::VectorizeScalarMatrixInitializers>();
+    manager.Add<ast::transform::SimplifyPointers>();
+    manager.Add<ast::transform::RemovePhonies>();
 
     // Build the config for the internal ArrayLengthFromUniform transform.
     auto& array_length_from_uniform = options.array_length_from_uniform;
-    transform::ArrayLengthFromUniform::Config array_length_from_uniform_cfg(
+    ast::transform::ArrayLengthFromUniform::Config array_length_from_uniform_cfg(
         array_length_from_uniform.ubo_binding);
     array_length_from_uniform_cfg.bindpoint_to_size_index =
         array_length_from_uniform.bindpoint_to_size_index;
@@ -277,38 +277,39 @@
     // DemoteToHelper must come after CanonicalizeEntryPointIO, PromoteSideEffectsToDecl, and
     // ExpandCompoundAssignment.
     // TODO(crbug.com/tint/1752): This is only necessary when FXC is being used.
-    manager.Add<transform::DemoteToHelper>();
+    manager.Add<ast::transform::DemoteToHelper>();
 
     // ArrayLengthFromUniform must come after SimplifyPointers as it assumes that the form of the
     // array length argument is &var.array.
-    manager.Add<transform::ArrayLengthFromUniform>();
-    data.Add<transform::ArrayLengthFromUniform::Config>(std::move(array_length_from_uniform_cfg));
+    manager.Add<ast::transform::ArrayLengthFromUniform>();
+    data.Add<ast::transform::ArrayLengthFromUniform::Config>(
+        std::move(array_length_from_uniform_cfg));
     // DecomposeMemoryAccess must come after:
     // * SimplifyPointers, as we cannot take the address of calls to
     //   DecomposeMemoryAccess::Intrinsic and we need to fold away the address-of and dereferences
     //   of `*(&(intrinsic_load()))` expressions.
     // * RemovePhonies, as phonies can be assigned a pointer to a
     //   non-constructible buffer, or dynamic array, which DMA cannot cope with.
-    manager.Add<transform::DecomposeMemoryAccess>();
+    manager.Add<ast::transform::DecomposeMemoryAccess>();
     // CalculateArrayLength must come after DecomposeMemoryAccess, as
     // DecomposeMemoryAccess special-cases the arrayLength() intrinsic, which
     // will be transformed by CalculateArrayLength
-    manager.Add<transform::CalculateArrayLength>();
-    manager.Add<transform::PromoteInitializersToLet>();
+    manager.Add<ast::transform::CalculateArrayLength>();
+    manager.Add<ast::transform::PromoteInitializersToLet>();
 
-    manager.Add<transform::RemoveContinueInSwitch>();
+    manager.Add<ast::transform::RemoveContinueInSwitch>();
 
-    manager.Add<transform::AddEmptyEntryPoint>();
+    manager.Add<ast::transform::AddEmptyEntryPoint>();
 
-    data.Add<transform::CanonicalizeEntryPointIO::Config>(
-        transform::CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
-    data.Add<transform::NumWorkgroupsFromUniform::Config>(options.root_constant_binding_point);
+    data.Add<ast::transform::CanonicalizeEntryPointIO::Config>(
+        ast::transform::CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+    data.Add<ast::transform::NumWorkgroupsFromUniform::Config>(options.root_constant_binding_point);
 
     auto out = manager.Run(in, data);
 
     SanitizedResult result;
     result.program = std::move(out.program);
-    if (auto* res = out.data.Get<transform::ArrayLengthFromUniform::Result>()) {
+    if (auto* res = out.data.Get<ast::transform::ArrayLengthFromUniform::Result>()) {
         result.used_array_length_from_uniform_indices = std::move(res->used_size_indices);
     }
     return result;
@@ -917,7 +918,7 @@
                                      const sem::Function* func) {
     auto* expr = call->Declaration();
 
-    if (ast::HasAttribute<transform::CalculateArrayLength::BufferSizeIntrinsic>(
+    if (ast::HasAttribute<ast::transform::CalculateArrayLength::BufferSizeIntrinsic>(
             func->Declaration()->attributes)) {
         // Special function generated by the CalculateArrayLength transform for
         // calling X.GetDimensions(Y)
@@ -932,7 +933,7 @@
         return true;
     }
 
-    if (auto* intrinsic = ast::GetAttribute<transform::DecomposeMemoryAccess::Intrinsic>(
+    if (auto* intrinsic = ast::GetAttribute<ast::transform::DecomposeMemoryAccess::Intrinsic>(
             func->Declaration()->attributes)) {
         switch (intrinsic->address_space) {
             case builtin::AddressSpace::kUniform:
@@ -1139,7 +1140,7 @@
 bool GeneratorImpl::EmitUniformBufferAccess(
     utils::StringStream& out,
     const ast::CallExpression* expr,
-    const transform::DecomposeMemoryAccess::Intrinsic* intrinsic) {
+    const ast::transform::DecomposeMemoryAccess::Intrinsic* intrinsic) {
     auto const buffer = intrinsic->Buffer()->identifier->symbol.Name();
     auto* const offset = expr->args[0];
 
@@ -1168,7 +1169,7 @@
     // scalar_offset_index or scalar_offset_index_unified_expr. Currently only loading f16 scalar
     // require using offset in bytes.
     const bool need_offset_in_bytes =
-        intrinsic->type == transform::DecomposeMemoryAccess::Intrinsic::DataType::kF16;
+        intrinsic->type == ast::transform::DecomposeMemoryAccess::Intrinsic::DataType::kF16;
 
     if (!scalar_offset_constant) {
         // UBO offset not compile-time known.
@@ -1199,8 +1200,8 @@
 
     const char swizzle[] = {'x', 'y', 'z', 'w'};
 
-    using Op = transform::DecomposeMemoryAccess::Intrinsic::Op;
-    using DataType = transform::DecomposeMemoryAccess::Intrinsic::DataType;
+    using Op = ast::transform::DecomposeMemoryAccess::Intrinsic::Op;
+    using DataType = ast::transform::DecomposeMemoryAccess::Intrinsic::DataType;
     switch (intrinsic->op) {
         case Op::kLoad: {
             auto cast = [&](const char* to, auto&& load) {
@@ -1427,13 +1428,13 @@
 bool GeneratorImpl::EmitStorageBufferAccess(
     utils::StringStream& out,
     const ast::CallExpression* expr,
-    const transform::DecomposeMemoryAccess::Intrinsic* intrinsic) {
+    const ast::transform::DecomposeMemoryAccess::Intrinsic* intrinsic) {
     auto const buffer = intrinsic->Buffer()->identifier->symbol.Name();
     auto* const offset = expr->args[0];
     auto* const value = expr->args[1];
 
-    using Op = transform::DecomposeMemoryAccess::Intrinsic::Op;
-    using DataType = transform::DecomposeMemoryAccess::Intrinsic::DataType;
+    using Op = ast::transform::DecomposeMemoryAccess::Intrinsic::Op;
+    using DataType = ast::transform::DecomposeMemoryAccess::Intrinsic::DataType;
     switch (intrinsic->op) {
         case Op::kLoad: {
             auto load = [&](const char* cast, int n) {
@@ -1588,8 +1589,8 @@
 
 bool GeneratorImpl::EmitStorageAtomicIntrinsic(
     const ast::Function* func,
-    const transform::DecomposeMemoryAccess::Intrinsic* intrinsic) {
-    using Op = transform::DecomposeMemoryAccess::Intrinsic::Op;
+    const ast::transform::DecomposeMemoryAccess::Intrinsic* intrinsic) {
+    using Op = ast::transform::DecomposeMemoryAccess::Intrinsic::Op;
 
     const sem::Function* sem_func = builder_.Sem().Get(func);
     auto* result_ty = sem_func->ReturnType();
@@ -2887,7 +2888,7 @@
 
     // Emit storage atomic helpers
     if (auto* intrinsic =
-            ast::GetAttribute<transform::DecomposeMemoryAccess::Intrinsic>(func->attributes)) {
+            ast::GetAttribute<ast::transform::DecomposeMemoryAccess::Intrinsic>(func->attributes)) {
         if (intrinsic->address_space == builtin::AddressSpace::kStorage && intrinsic->IsAtomic()) {
             if (!EmitStorageAtomicIntrinsic(func, intrinsic)) {
                 return false;
diff --git a/src/tint/writer/hlsl/generator_impl.h b/src/tint/writer/hlsl/generator_impl.h
index f52d58f..2ae653c 100644
--- a/src/tint/writer/hlsl/generator_impl.h
+++ b/src/tint/writer/hlsl/generator_impl.h
@@ -30,12 +30,12 @@
 #include "src/tint/ast/loop_statement.h"
 #include "src/tint/ast/return_statement.h"
 #include "src/tint/ast/switch_statement.h"
+#include "src/tint/ast/transform/decompose_memory_access.h"
 #include "src/tint/ast/unary_op_expression.h"
 #include "src/tint/builtin/builtin_value.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/scope_stack.h"
 #include "src/tint/sem/binding_point.h"
-#include "src/tint/transform/decompose_memory_access.h"
 #include "src/tint/utils/hash.h"
 #include "src/tint/writer/array_length_from_uniform_options.h"
 #include "src/tint/writer/hlsl/generator.h"
@@ -161,23 +161,23 @@
                               const sem::Call* call,
                               const sem::ValueConstructor* ctor);
     /// Handles generating a call expression to a
-    /// transform::DecomposeMemoryAccess::Intrinsic for a uniform buffer
+    /// ast::transform::DecomposeMemoryAccess::Intrinsic for a uniform buffer
     /// @param out the output of the expression stream
     /// @param expr the call expression
-    /// @param intrinsic the transform::DecomposeMemoryAccess::Intrinsic
+    /// @param intrinsic the ast::transform::DecomposeMemoryAccess::Intrinsic
     /// @returns true if the call expression is emitted
     bool EmitUniformBufferAccess(utils::StringStream& out,
                                  const ast::CallExpression* expr,
-                                 const transform::DecomposeMemoryAccess::Intrinsic* intrinsic);
+                                 const ast::transform::DecomposeMemoryAccess::Intrinsic* intrinsic);
     /// Handles generating a call expression to a
-    /// transform::DecomposeMemoryAccess::Intrinsic for a storage buffer
+    /// ast::transform::DecomposeMemoryAccess::Intrinsic for a storage buffer
     /// @param out the output of the expression stream
     /// @param expr the call expression
-    /// @param intrinsic the transform::DecomposeMemoryAccess::Intrinsic
+    /// @param intrinsic the ast::transform::DecomposeMemoryAccess::Intrinsic
     /// @returns true if the call expression is emitted
     bool EmitStorageBufferAccess(utils::StringStream& out,
                                  const ast::CallExpression* expr,
-                                 const transform::DecomposeMemoryAccess::Intrinsic* intrinsic);
+                                 const ast::transform::DecomposeMemoryAccess::Intrinsic* intrinsic);
     /// Handles generating a barrier intrinsic call
     /// @param out the output of the expression stream
     /// @param builtin the semantic information for the barrier builtin
@@ -190,13 +190,14 @@
     /// @returns true if the call expression is emitted
     bool EmitStorageAtomicCall(utils::StringStream& out,
                                const ast::CallExpression* expr,
-                               const transform::DecomposeMemoryAccess::Intrinsic* intrinsic);
+                               const ast::transform::DecomposeMemoryAccess::Intrinsic* intrinsic);
     /// Handles generating the helper function for the atomic intrinsic function
     /// @param func the function
     /// @param intrinsic the atomic intrinsic
     /// @returns true if the function is emitted
-    bool EmitStorageAtomicIntrinsic(const ast::Function* func,
-                                    const transform::DecomposeMemoryAccess::Intrinsic* intrinsic);
+    bool EmitStorageAtomicIntrinsic(
+        const ast::Function* func,
+        const ast::transform::DecomposeMemoryAccess::Intrinsic* intrinsic);
     /// Handles generating an atomic intrinsic call for a workgroup variable
     /// @param out the output of the expression stream
     /// @param expr the call expression
@@ -528,8 +529,8 @@
     };
 
     struct DMAIntrinsic {
-        transform::DecomposeMemoryAccess::Intrinsic::Op op;
-        transform::DecomposeMemoryAccess::Intrinsic::DataType type;
+        ast::transform::DecomposeMemoryAccess::Intrinsic::Op op;
+        ast::transform::DecomposeMemoryAccess::Intrinsic::DataType type;
         bool operator==(const DMAIntrinsic& rhs) const { return op == rhs.op && type == rhs.type; }
         /// Hasher is a std::hash function for DMAIntrinsic
         struct Hasher {
diff --git a/src/tint/writer/hlsl/generator_impl_builtin_texture_test.cc b/src/tint/writer/hlsl/generator_impl_builtin_texture_test.cc
index 174c66c..8ddcc1c 100644
--- a/src/tint/writer/hlsl/generator_impl_builtin_texture_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_builtin_texture_test.cc
@@ -31,8 +31,8 @@
     std::string out;
 };
 
-ExpectedResult expected_texture_overload(ast::builtin::test::ValidTextureOverload overload) {
-    using ValidTextureOverload = ast::builtin::test::ValidTextureOverload;
+ExpectedResult expected_texture_overload(ast::test::ValidTextureOverload overload) {
+    using ValidTextureOverload = ast::test::ValidTextureOverload;
     switch (overload) {
         case ValidTextureOverload::kDimensions1d:
         case ValidTextureOverload::kDimensionsStorageWO1d:
@@ -363,8 +363,7 @@
     return "<unmatched texture overload>";
 }  // NOLINT - Ignore the length of this function
 
-class HlslGeneratorBuiltinTextureTest
-    : public TestParamHelper<ast::builtin::test::TextureOverloadCase> {};
+class HlslGeneratorBuiltinTextureTest : public TestParamHelper<ast::test::TextureOverloadCase> {};
 
 TEST_P(HlslGeneratorBuiltinTextureTest, Call) {
     auto param = GetParam();
@@ -391,7 +390,7 @@
 
 INSTANTIATE_TEST_SUITE_P(HlslGeneratorBuiltinTextureTest,
                          HlslGeneratorBuiltinTextureTest,
-                         testing::ValuesIn(ast::builtin::test::TextureOverloadCase::ValidCases()));
+                         testing::ValuesIn(ast::test::TextureOverloadCase::ValidCases()));
 
 }  // namespace
 }  // namespace tint::writer::hlsl
diff --git a/src/tint/writer/hlsl/test_helper.h b/src/tint/writer/hlsl/test_helper.h
index 24eb56a..e645346 100644
--- a/src/tint/writer/hlsl/test_helper.h
+++ b/src/tint/writer/hlsl/test_helper.h
@@ -20,8 +20,8 @@
 #include <utility>
 
 #include "gtest/gtest.h"
+#include "src/tint/ast/transform/renamer.h"
 #include "src/tint/transform/manager.h"
-#include "src/tint/transform/renamer.h"
 #include "src/tint/writer/hlsl/generator.h"
 #include "src/tint/writer/hlsl/generator_impl.h"
 
@@ -87,10 +87,11 @@
         }();
 
         transform::Manager transform_manager;
-        transform::DataMap transform_data;
-        transform_data.Add<transform::Renamer::Config>(transform::Renamer::Target::kHlslKeywords,
-                                                       /* preserve_unicode */ true);
-        transform_manager.Add<tint::transform::Renamer>();
+        ast::transform::DataMap transform_data;
+        transform_data.Add<ast::transform::Renamer::Config>(
+            ast::transform::Renamer::Target::kHlslKeywords,
+            /* preserve_unicode */ true);
+        transform_manager.Add<tint::ast::transform::Renamer>();
         auto result = transform_manager.Run(&sanitized_result.program, transform_data);
         [&]() {
             ASSERT_TRUE(result.program.IsValid()) << formatter.format(result.program.Diagnostics());
diff --git a/src/tint/writer/msl/generator_impl.cc b/src/tint/writer/msl/generator_impl.cc
index f3f660a..23c39f3 100644
--- a/src/tint/writer/msl/generator_impl.cc
+++ b/src/tint/writer/msl/generator_impl.cc
@@ -29,6 +29,25 @@
 #include "src/tint/ast/id_attribute.h"
 #include "src/tint/ast/interpolate_attribute.h"
 #include "src/tint/ast/module.h"
+#include "src/tint/ast/transform/array_length_from_uniform.h"
+#include "src/tint/ast/transform/binding_remapper.h"
+#include "src/tint/ast/transform/builtin_polyfill.h"
+#include "src/tint/ast/transform/canonicalize_entry_point_io.h"
+#include "src/tint/ast/transform/demote_to_helper.h"
+#include "src/tint/ast/transform/disable_uniformity_analysis.h"
+#include "src/tint/ast/transform/expand_compound_assignment.h"
+#include "src/tint/ast/transform/module_scope_var_to_entry_point_param.h"
+#include "src/tint/ast/transform/multiplanar_external_texture.h"
+#include "src/tint/ast/transform/packed_vec3.h"
+#include "src/tint/ast/transform/preserve_padding.h"
+#include "src/tint/ast/transform/promote_initializers_to_let.h"
+#include "src/tint/ast/transform/promote_side_effects_to_decl.h"
+#include "src/tint/ast/transform/remove_phonies.h"
+#include "src/tint/ast/transform/robustness.h"
+#include "src/tint/ast/transform/simplify_pointers.h"
+#include "src/tint/ast/transform/unshadow.h"
+#include "src/tint/ast/transform/vectorize_scalar_matrix_initializers.h"
+#include "src/tint/ast/transform/zero_init_workgroup_memory.h"
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/constant/value.h"
 #include "src/tint/sem/call.h"
@@ -41,26 +60,7 @@
 #include "src/tint/sem/value_conversion.h"
 #include "src/tint/sem/variable.h"
 #include "src/tint/switch.h"
-#include "src/tint/transform/array_length_from_uniform.h"
-#include "src/tint/transform/binding_remapper.h"
-#include "src/tint/transform/builtin_polyfill.h"
-#include "src/tint/transform/canonicalize_entry_point_io.h"
-#include "src/tint/transform/demote_to_helper.h"
-#include "src/tint/transform/disable_uniformity_analysis.h"
-#include "src/tint/transform/expand_compound_assignment.h"
 #include "src/tint/transform/manager.h"
-#include "src/tint/transform/module_scope_var_to_entry_point_param.h"
-#include "src/tint/transform/multiplanar_external_texture.h"
-#include "src/tint/transform/packed_vec3.h"
-#include "src/tint/transform/preserve_padding.h"
-#include "src/tint/transform/promote_initializers_to_let.h"
-#include "src/tint/transform/promote_side_effects_to_decl.h"
-#include "src/tint/transform/remove_phonies.h"
-#include "src/tint/transform/robustness.h"
-#include "src/tint/transform/simplify_pointers.h"
-#include "src/tint/transform/unshadow.h"
-#include "src/tint/transform/vectorize_scalar_matrix_initializers.h"
-#include "src/tint/transform/zero_init_workgroup_memory.h"
 #include "src/tint/type/array.h"
 #include "src/tint/type/atomic.h"
 #include "src/tint/type/bool.h"
@@ -167,58 +167,58 @@
 
 SanitizedResult Sanitize(const Program* in, const Options& options) {
     transform::Manager manager;
-    transform::DataMap data;
+    ast::transform::DataMap data;
 
-    manager.Add<transform::DisableUniformityAnalysis>();
+    manager.Add<ast::transform::DisableUniformityAnalysis>();
 
     // ExpandCompoundAssignment must come before BuiltinPolyfill
-    manager.Add<transform::ExpandCompoundAssignment>();
+    manager.Add<ast::transform::ExpandCompoundAssignment>();
 
     // Build the configs for the internal CanonicalizeEntryPointIO transform.
-    auto entry_point_io_cfg = transform::CanonicalizeEntryPointIO::Config(
-        transform::CanonicalizeEntryPointIO::ShaderStyle::kMsl, options.fixed_sample_mask,
+    auto entry_point_io_cfg = ast::transform::CanonicalizeEntryPointIO::Config(
+        ast::transform::CanonicalizeEntryPointIO::ShaderStyle::kMsl, options.fixed_sample_mask,
         options.emit_vertex_point_size);
 
-    manager.Add<transform::PreservePadding>();
+    manager.Add<ast::transform::PreservePadding>();
 
-    manager.Add<transform::Unshadow>();
+    manager.Add<ast::transform::Unshadow>();
 
-    manager.Add<transform::PromoteSideEffectsToDecl>();
+    manager.Add<ast::transform::PromoteSideEffectsToDecl>();
 
     if (!options.disable_robustness) {
         // Robustness must come after PromoteSideEffectsToDecl
         // Robustness must come before BuiltinPolyfill and CanonicalizeEntryPointIO
         // Robustness must come before ArrayLengthFromUniform
-        manager.Add<transform::Robustness>();
+        manager.Add<ast::transform::Robustness>();
     }
 
     {  // Builtin polyfills
-        transform::BuiltinPolyfill::Builtins polyfills;
-        polyfills.acosh = transform::BuiltinPolyfill::Level::kRangeCheck;
-        polyfills.atanh = transform::BuiltinPolyfill::Level::kRangeCheck;
+        ast::transform::BuiltinPolyfill::Builtins polyfills;
+        polyfills.acosh = ast::transform::BuiltinPolyfill::Level::kRangeCheck;
+        polyfills.atanh = ast::transform::BuiltinPolyfill::Level::kRangeCheck;
         polyfills.bitshift_modulo = true;  // crbug.com/tint/1543
         polyfills.clamp_int = true;
         polyfills.conv_f32_to_iu32 = true;
-        polyfills.extract_bits = transform::BuiltinPolyfill::Level::kClampParameters;
+        polyfills.extract_bits = ast::transform::BuiltinPolyfill::Level::kClampParameters;
         polyfills.first_leading_bit = true;
         polyfills.first_trailing_bit = true;
-        polyfills.insert_bits = transform::BuiltinPolyfill::Level::kClampParameters;
+        polyfills.insert_bits = ast::transform::BuiltinPolyfill::Level::kClampParameters;
         polyfills.int_div_mod = true;
         polyfills.sign_int = true;
         polyfills.texture_sample_base_clamp_to_edge_2d_f32 = true;
         polyfills.workgroup_uniform_load = true;
-        data.Add<transform::BuiltinPolyfill::Config>(polyfills);
-        manager.Add<transform::BuiltinPolyfill>();
+        data.Add<ast::transform::BuiltinPolyfill::Config>(polyfills);
+        manager.Add<ast::transform::BuiltinPolyfill>();
     }
 
     // Note: it is more efficient for MultiplanarExternalTexture to come after Robustness
-    data.Add<transform::MultiplanarExternalTexture::NewBindingPoints>(
+    data.Add<ast::transform::MultiplanarExternalTexture::NewBindingPoints>(
         options.external_texture_options.bindings_map);
-    manager.Add<transform::MultiplanarExternalTexture>();
+    manager.Add<ast::transform::MultiplanarExternalTexture>();
 
     // BindingRemapper must come after MultiplanarExternalTexture
-    manager.Add<transform::BindingRemapper>();
-    data.Add<transform::BindingRemapper::Remappings>(
+    manager.Add<ast::transform::BindingRemapper>();
+    data.Add<ast::transform::BindingRemapper::Remappings>(
         options.binding_remapper_options.binding_points,
         options.binding_remapper_options.access_controls,
         options.binding_remapper_options.allow_collisions);
@@ -226,36 +226,36 @@
     if (!options.disable_workgroup_init) {
         // ZeroInitWorkgroupMemory must come before CanonicalizeEntryPointIO as
         // ZeroInitWorkgroupMemory may inject new builtin parameters.
-        manager.Add<transform::ZeroInitWorkgroupMemory>();
+        manager.Add<ast::transform::ZeroInitWorkgroupMemory>();
     }
 
     // CanonicalizeEntryPointIO must come after Robustness
-    manager.Add<transform::CanonicalizeEntryPointIO>();
-    data.Add<transform::CanonicalizeEntryPointIO::Config>(std::move(entry_point_io_cfg));
+    manager.Add<ast::transform::CanonicalizeEntryPointIO>();
+    data.Add<ast::transform::CanonicalizeEntryPointIO::Config>(std::move(entry_point_io_cfg));
 
-    manager.Add<transform::PromoteInitializersToLet>();
+    manager.Add<ast::transform::PromoteInitializersToLet>();
 
     // DemoteToHelper must come after PromoteSideEffectsToDecl and ExpandCompoundAssignment.
     // TODO(crbug.com/tint/1752): This is only necessary for Metal versions older than 2.3.
-    manager.Add<transform::DemoteToHelper>();
+    manager.Add<ast::transform::DemoteToHelper>();
 
-    manager.Add<transform::VectorizeScalarMatrixInitializers>();
-    manager.Add<transform::RemovePhonies>();
-    manager.Add<transform::SimplifyPointers>();
+    manager.Add<ast::transform::VectorizeScalarMatrixInitializers>();
+    manager.Add<ast::transform::RemovePhonies>();
+    manager.Add<ast::transform::SimplifyPointers>();
 
     // ArrayLengthFromUniform must come after SimplifyPointers, as
     // it assumes that the form of the array length argument is &var.array.
-    manager.Add<transform::ArrayLengthFromUniform>();
+    manager.Add<ast::transform::ArrayLengthFromUniform>();
 
-    transform::ArrayLengthFromUniform::Config array_length_cfg(
+    ast::transform::ArrayLengthFromUniform::Config array_length_cfg(
         std::move(options.array_length_from_uniform.ubo_binding));
     array_length_cfg.bindpoint_to_size_index =
         std::move(options.array_length_from_uniform.bindpoint_to_size_index);
-    data.Add<transform::ArrayLengthFromUniform::Config>(array_length_cfg);
+    data.Add<ast::transform::ArrayLengthFromUniform::Config>(array_length_cfg);
 
     // PackedVec3 must come after ExpandCompoundAssignment.
-    manager.Add<transform::PackedVec3>();
-    manager.Add<transform::ModuleScopeVarToEntryPointParam>();
+    manager.Add<ast::transform::PackedVec3>();
+    manager.Add<ast::transform::ModuleScopeVarToEntryPointParam>();
 
     auto out = manager.Run(in, data);
 
@@ -264,7 +264,7 @@
     if (!result.program.IsValid()) {
         return result;
     }
-    if (auto* res = out.data.Get<transform::ArrayLengthFromUniform::Result>()) {
+    if (auto* res = out.data.Get<ast::transform::ArrayLengthFromUniform::Result>()) {
         result.used_array_length_from_uniform_indices = std::move(res->used_size_indices);
     }
     result.needs_storage_buffer_sizes = !result.used_array_length_from_uniform_indices.empty();
diff --git a/src/tint/writer/msl/generator_impl_builtin_texture_test.cc b/src/tint/writer/msl/generator_impl_builtin_texture_test.cc
index f6b9635..54f0113 100644
--- a/src/tint/writer/msl/generator_impl_builtin_texture_test.cc
+++ b/src/tint/writer/msl/generator_impl_builtin_texture_test.cc
@@ -20,8 +20,8 @@
 namespace tint::writer::msl {
 namespace {
 
-std::string expected_texture_overload(ast::builtin::test::ValidTextureOverload overload) {
-    using ValidTextureOverload = ast::builtin::test::ValidTextureOverload;
+std::string expected_texture_overload(ast::test::ValidTextureOverload overload) {
+    using ValidTextureOverload = ast::test::ValidTextureOverload;
     switch (overload) {
         case ValidTextureOverload::kDimensions1d:
         case ValidTextureOverload::kDimensionsStorageWO1d:
@@ -268,8 +268,7 @@
     return "<unmatched texture overload>";
 }  // NOLINT - Ignore the length of this function
 
-class MslGeneratorBuiltinTextureTest
-    : public TestParamHelper<ast::builtin::test::TextureOverloadCase> {};
+class MslGeneratorBuiltinTextureTest : public TestParamHelper<ast::test::TextureOverloadCase> {};
 
 TEST_P(MslGeneratorBuiltinTextureTest, Call) {
     auto param = GetParam();
@@ -295,7 +294,7 @@
 
 INSTANTIATE_TEST_SUITE_P(MslGeneratorBuiltinTextureTest,
                          MslGeneratorBuiltinTextureTest,
-                         testing::ValuesIn(ast::builtin::test::TextureOverloadCase::ValidCases()));
+                         testing::ValuesIn(ast::test::TextureOverloadCase::ValidCases()));
 
 }  // namespace
 }  // namespace tint::writer::msl
diff --git a/src/tint/writer/spirv/builder.cc b/src/tint/writer/spirv/builder.cc
index ff0dc3f..58bc069 100644
--- a/src/tint/writer/spirv/builder.cc
+++ b/src/tint/writer/spirv/builder.cc
@@ -21,6 +21,7 @@
 #include "src/tint/ast/call_statement.h"
 #include "src/tint/ast/id_attribute.h"
 #include "src/tint/ast/internal_attribute.h"
+#include "src/tint/ast/transform/add_block_attribute.h"
 #include "src/tint/ast/traverse_expressions.h"
 #include "src/tint/constant/value.h"
 #include "src/tint/sem/builtin.h"
@@ -36,7 +37,6 @@
 #include "src/tint/sem/value_constructor.h"
 #include "src/tint/sem/value_conversion.h"
 #include "src/tint/sem/variable.h"
-#include "src/tint/transform/add_block_attribute.h"
 #include "src/tint/type/array.h"
 #include "src/tint/type/atomic.h"
 #include "src/tint/type/depth_multisampled_texture.h"
@@ -3888,7 +3888,8 @@
 
     if (auto* sem_str = struct_type->As<sem::Struct>()) {
         auto* decl = sem_str->Declaration();
-        if (ast::HasAttribute<transform::AddBlockAttribute::BlockAttribute>(decl->attributes)) {
+        if (ast::HasAttribute<ast::transform::AddBlockAttribute::BlockAttribute>(
+                decl->attributes)) {
             module_.PushAnnot(spv::Op::OpDecorate,
                               {Operand(struct_id), U32Operand(SpvDecorationBlock)});
         }
diff --git a/src/tint/writer/spirv/builder_builtin_texture_test.cc b/src/tint/writer/spirv/builder_builtin_texture_test.cc
index cd17ec1..9d45519 100644
--- a/src/tint/writer/spirv/builder_builtin_texture_test.cc
+++ b/src/tint/writer/spirv/builder_builtin_texture_test.cc
@@ -29,8 +29,8 @@
 };
 
 expected_texture_overload_spirv expected_texture_overload(
-    ast::builtin::test::ValidTextureOverload overload) {
-    using ValidTextureOverload = ast::builtin::test::ValidTextureOverload;
+    ast::test::ValidTextureOverload overload) {
+    using ValidTextureOverload = ast::test::ValidTextureOverload;
     switch (overload) {
         case ValidTextureOverload::kDimensions1d:
             return {
@@ -3704,11 +3704,11 @@
             "<unmatched texture overload>"};
 }  // NOLINT - Ignore the length of this function
 
-using BuiltinTextureTest = TestParamHelper<ast::builtin::test::TextureOverloadCase>;
+using BuiltinTextureTest = TestParamHelper<ast::test::TextureOverloadCase>;
 
 INSTANTIATE_TEST_SUITE_P(BuiltinTextureTest,
                          BuiltinTextureTest,
-                         testing::ValuesIn(ast::builtin::test::TextureOverloadCase::ValidCases()));
+                         testing::ValuesIn(ast::test::TextureOverloadCase::ValidCases()));
 
 TEST_P(BuiltinTextureTest, Call) {
     auto param = GetParam();
diff --git a/src/tint/writer/spirv/generator_impl.cc b/src/tint/writer/spirv/generator_impl.cc
index 88bd39a..9df66ef 100644
--- a/src/tint/writer/spirv/generator_impl.cc
+++ b/src/tint/writer/spirv/generator_impl.cc
@@ -17,109 +17,109 @@
 #include <utility>
 #include <vector>
 
-#include "src/tint/transform/add_block_attribute.h"
-#include "src/tint/transform/add_empty_entry_point.h"
-#include "src/tint/transform/binding_remapper.h"
-#include "src/tint/transform/builtin_polyfill.h"
-#include "src/tint/transform/canonicalize_entry_point_io.h"
-#include "src/tint/transform/clamp_frag_depth.h"
-#include "src/tint/transform/demote_to_helper.h"
-#include "src/tint/transform/direct_variable_access.h"
-#include "src/tint/transform/disable_uniformity_analysis.h"
-#include "src/tint/transform/expand_compound_assignment.h"
-#include "src/tint/transform/for_loop_to_loop.h"
+#include "src/tint/ast/transform/add_block_attribute.h"
+#include "src/tint/ast/transform/add_empty_entry_point.h"
+#include "src/tint/ast/transform/binding_remapper.h"
+#include "src/tint/ast/transform/builtin_polyfill.h"
+#include "src/tint/ast/transform/canonicalize_entry_point_io.h"
+#include "src/tint/ast/transform/clamp_frag_depth.h"
+#include "src/tint/ast/transform/demote_to_helper.h"
+#include "src/tint/ast/transform/direct_variable_access.h"
+#include "src/tint/ast/transform/disable_uniformity_analysis.h"
+#include "src/tint/ast/transform/expand_compound_assignment.h"
+#include "src/tint/ast/transform/for_loop_to_loop.h"
+#include "src/tint/ast/transform/merge_return.h"
+#include "src/tint/ast/transform/multiplanar_external_texture.h"
+#include "src/tint/ast/transform/preserve_padding.h"
+#include "src/tint/ast/transform/promote_side_effects_to_decl.h"
+#include "src/tint/ast/transform/remove_phonies.h"
+#include "src/tint/ast/transform/remove_unreachable_statements.h"
+#include "src/tint/ast/transform/robustness.h"
+#include "src/tint/ast/transform/simplify_pointers.h"
+#include "src/tint/ast/transform/std140.h"
+#include "src/tint/ast/transform/unshadow.h"
+#include "src/tint/ast/transform/var_for_dynamic_index.h"
+#include "src/tint/ast/transform/vectorize_matrix_conversions.h"
+#include "src/tint/ast/transform/vectorize_scalar_matrix_initializers.h"
+#include "src/tint/ast/transform/while_to_loop.h"
+#include "src/tint/ast/transform/zero_init_workgroup_memory.h"
 #include "src/tint/transform/manager.h"
-#include "src/tint/transform/merge_return.h"
-#include "src/tint/transform/multiplanar_external_texture.h"
-#include "src/tint/transform/preserve_padding.h"
-#include "src/tint/transform/promote_side_effects_to_decl.h"
-#include "src/tint/transform/remove_phonies.h"
-#include "src/tint/transform/remove_unreachable_statements.h"
-#include "src/tint/transform/robustness.h"
-#include "src/tint/transform/simplify_pointers.h"
-#include "src/tint/transform/std140.h"
-#include "src/tint/transform/unshadow.h"
-#include "src/tint/transform/var_for_dynamic_index.h"
-#include "src/tint/transform/vectorize_matrix_conversions.h"
-#include "src/tint/transform/vectorize_scalar_matrix_initializers.h"
-#include "src/tint/transform/while_to_loop.h"
-#include "src/tint/transform/zero_init_workgroup_memory.h"
 
 namespace tint::writer::spirv {
 
 SanitizedResult Sanitize(const Program* in, const Options& options) {
     transform::Manager manager;
-    transform::DataMap data;
+    ast::transform::DataMap data;
 
     if (options.clamp_frag_depth) {
-        manager.Add<tint::transform::ClampFragDepth>();
+        manager.Add<tint::ast::transform::ClampFragDepth>();
     }
 
-    manager.Add<transform::DisableUniformityAnalysis>();
+    manager.Add<ast::transform::DisableUniformityAnalysis>();
 
     // ExpandCompoundAssignment must come before BuiltinPolyfill
-    manager.Add<transform::ExpandCompoundAssignment>();
+    manager.Add<ast::transform::ExpandCompoundAssignment>();
 
     // Must come before DirectVariableAccess
-    manager.Add<transform::PreservePadding>();
+    manager.Add<ast::transform::PreservePadding>();
 
     // Must come before DirectVariableAccess
-    manager.Add<transform::Unshadow>();
+    manager.Add<ast::transform::Unshadow>();
 
-    manager.Add<transform::RemoveUnreachableStatements>();
-    manager.Add<transform::PromoteSideEffectsToDecl>();
+    manager.Add<ast::transform::RemoveUnreachableStatements>();
+    manager.Add<ast::transform::PromoteSideEffectsToDecl>();
 
     // Required for arrayLength()
-    manager.Add<transform::SimplifyPointers>();
+    manager.Add<ast::transform::SimplifyPointers>();
 
-    manager.Add<transform::RemovePhonies>();
-    manager.Add<transform::VectorizeScalarMatrixInitializers>();
-    manager.Add<transform::VectorizeMatrixConversions>();
-    manager.Add<transform::WhileToLoop>();  // ZeroInitWorkgroupMemory
-    manager.Add<transform::MergeReturn>();
+    manager.Add<ast::transform::RemovePhonies>();
+    manager.Add<ast::transform::VectorizeScalarMatrixInitializers>();
+    manager.Add<ast::transform::VectorizeMatrixConversions>();
+    manager.Add<ast::transform::WhileToLoop>();  // ZeroInitWorkgroupMemory
+    manager.Add<ast::transform::MergeReturn>();
 
     if (!options.disable_robustness) {
         // Robustness must come after PromoteSideEffectsToDecl
         // Robustness must come before BuiltinPolyfill and CanonicalizeEntryPointIO
-        manager.Add<transform::Robustness>();
+        manager.Add<ast::transform::Robustness>();
     }
 
     // BindingRemapper must come before MultiplanarExternalTexture. Note, this is flipped to the
     // other generators which run Multiplanar first and then binding remapper.
-    manager.Add<transform::BindingRemapper>();
-    data.Add<transform::BindingRemapper::Remappings>(
+    manager.Add<ast::transform::BindingRemapper>();
+    data.Add<ast::transform::BindingRemapper::Remappings>(
         options.binding_remapper_options.binding_points,
         options.binding_remapper_options.access_controls,
         options.binding_remapper_options.allow_collisions);
 
     // Note: it is more efficient for MultiplanarExternalTexture to come after Robustness
-    data.Add<transform::MultiplanarExternalTexture::NewBindingPoints>(
+    data.Add<ast::transform::MultiplanarExternalTexture::NewBindingPoints>(
         options.external_texture_options.bindings_map);
-    manager.Add<transform::MultiplanarExternalTexture>();
+    manager.Add<ast::transform::MultiplanarExternalTexture>();
 
     {  // Builtin polyfills
         // BuiltinPolyfill must come before DirectVariableAccess, due to the use of pointer
         // parameter for workgroupUniformLoad()
-        transform::BuiltinPolyfill::Builtins polyfills;
-        polyfills.acosh = transform::BuiltinPolyfill::Level::kRangeCheck;
-        polyfills.atanh = transform::BuiltinPolyfill::Level::kRangeCheck;
+        ast::transform::BuiltinPolyfill::Builtins polyfills;
+        polyfills.acosh = ast::transform::BuiltinPolyfill::Level::kRangeCheck;
+        polyfills.atanh = ast::transform::BuiltinPolyfill::Level::kRangeCheck;
         polyfills.bgra8unorm = true;
         polyfills.bitshift_modulo = true;
         polyfills.clamp_int = true;
         polyfills.conv_f32_to_iu32 = true;
         polyfills.count_leading_zeros = true;
         polyfills.count_trailing_zeros = true;
-        polyfills.extract_bits = transform::BuiltinPolyfill::Level::kClampParameters;
+        polyfills.extract_bits = ast::transform::BuiltinPolyfill::Level::kClampParameters;
         polyfills.first_leading_bit = true;
         polyfills.first_trailing_bit = true;
-        polyfills.insert_bits = transform::BuiltinPolyfill::Level::kClampParameters;
+        polyfills.insert_bits = ast::transform::BuiltinPolyfill::Level::kClampParameters;
         polyfills.int_div_mod = true;
         polyfills.saturate = true;
         polyfills.texture_sample_base_clamp_to_edge_2d_f32 = true;
         polyfills.quantize_to_vec_f16 = true;  // crbug.com/tint/1741
         polyfills.workgroup_uniform_load = true;
-        data.Add<transform::BuiltinPolyfill::Config>(polyfills);
-        manager.Add<transform::BuiltinPolyfill>();  // Must come before DirectVariableAccess
+        data.Add<ast::transform::BuiltinPolyfill::Config>(polyfills);
+        manager.Add<ast::transform::BuiltinPolyfill>();  // Must come before DirectVariableAccess
     }
 
     bool disable_workgroup_init_in_sanitizer =
@@ -127,42 +127,42 @@
     if (!disable_workgroup_init_in_sanitizer) {
         // ZeroInitWorkgroupMemory must come before CanonicalizeEntryPointIO as
         // ZeroInitWorkgroupMemory may inject new builtin parameters.
-        manager.Add<transform::ZeroInitWorkgroupMemory>();
+        manager.Add<ast::transform::ZeroInitWorkgroupMemory>();
     }
 
     {
-        transform::DirectVariableAccess::Options opts;
+        ast::transform::DirectVariableAccess::Options opts;
         opts.transform_private = true;
         opts.transform_function = true;
-        data.Add<transform::DirectVariableAccess::Config>(opts);
-        manager.Add<transform::DirectVariableAccess>();
+        data.Add<ast::transform::DirectVariableAccess::Config>(opts);
+        manager.Add<ast::transform::DirectVariableAccess>();
     }
 
     // CanonicalizeEntryPointIO must come after Robustness
-    manager.Add<transform::CanonicalizeEntryPointIO>();
-    manager.Add<transform::AddEmptyEntryPoint>();
+    manager.Add<ast::transform::CanonicalizeEntryPointIO>();
+    manager.Add<ast::transform::AddEmptyEntryPoint>();
 
     // AddBlockAttribute must come after MultiplanarExternalTexture
-    manager.Add<transform::AddBlockAttribute>();
+    manager.Add<ast::transform::AddBlockAttribute>();
 
     // DemoteToHelper must come after CanonicalizeEntryPointIO, PromoteSideEffectsToDecl, and
     // ExpandCompoundAssignment.
     // TODO(crbug.com/tint/1752): Use SPV_EXT_demote_to_helper_invocation if available.
-    manager.Add<transform::DemoteToHelper>();
+    manager.Add<ast::transform::DemoteToHelper>();
 
     // Std140 must come after PromoteSideEffectsToDecl.
     // Std140 must come before VarForDynamicIndex and ForLoopToLoop.
-    manager.Add<transform::Std140>();
+    manager.Add<ast::transform::Std140>();
 
     // VarForDynamicIndex must come after Std140
-    manager.Add<transform::VarForDynamicIndex>();
+    manager.Add<ast::transform::VarForDynamicIndex>();
 
     // ForLoopToLoop must come after Std140, ZeroInitWorkgroupMemory
-    manager.Add<transform::ForLoopToLoop>();
+    manager.Add<ast::transform::ForLoopToLoop>();
 
-    data.Add<transform::CanonicalizeEntryPointIO::Config>(
-        transform::CanonicalizeEntryPointIO::Config(
-            transform::CanonicalizeEntryPointIO::ShaderStyle::kSpirv, 0xFFFFFFFF,
+    data.Add<ast::transform::CanonicalizeEntryPointIO::Config>(
+        ast::transform::CanonicalizeEntryPointIO::Config(
+            ast::transform::CanonicalizeEntryPointIO::ShaderStyle::kSpirv, 0xFFFFFFFF,
             options.emit_vertex_point_size));
 
     SanitizedResult result;
diff --git a/src/tint/writer/spirv/generator_impl_ir.cc b/src/tint/writer/spirv/generator_impl_ir.cc
index 7ff56be..202ccbe 100644
--- a/src/tint/writer/spirv/generator_impl_ir.cc
+++ b/src/tint/writer/spirv/generator_impl_ir.cc
@@ -45,12 +45,20 @@
 
     // TODO(crbug.com/tint/1906): Emit variables.
     (void)zero_init_workgroup_memory_;
+    if (ir_->root_block) {
+        TINT_ICE(Writer, diagnostics_) << "root block is unimplemented";
+        return false;
+    }
 
     // Emit functions.
     for (auto* func : ir_->functions) {
         EmitFunction(func);
     }
 
+    if (diagnostics_.contains_errors()) {
+        return false;
+    }
+
     // Serialize the module into binary SPIR-V.
     writer_.WriteHeader(module_.IdBound());
     writer_.WriteModule(&module_);
@@ -231,6 +239,9 @@
         block->branch.target,
         [&](const ir::FunctionTerminator*) {
             // TODO(jrprice): Handle the return value, which will be a branch argument.
+            if (!block->branch.args.IsEmpty()) {
+                TINT_ICE(Writer, diagnostics_) << "unimplemented return value";
+            }
             current_function_.push_inst(spv::Op::OpReturn, {});
         },
         [&](Default) { TINT_ICE(Writer, diagnostics_) << "unimplemented branch target"; });