writer/hlsl: Implement atomics

Storage buffers are emitted as `ByteAddressBuffer`s in HLSL, so we have to jump through hoops to support atomic ops on storage buffer atomics.
Workgroup atomics are far more conventional, but very little code can be shared between these two code paths.

Bug: tint:892
Change-Id: If10ea866e3b67a093e87aca689d34065fd49b705
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/54651
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: David Neto <dneto@google.com>
diff --git a/src/sem/intrinsic.cc b/src/sem/intrinsic.cc
index e18109d..be1a873 100644
--- a/src/sem/intrinsic.cc
+++ b/src/sem/intrinsic.cc
@@ -88,6 +88,19 @@
          i == IntrinsicType::kStorageBarrier;
 }
 
+bool IsAtomicIntrinsic(IntrinsicType i) {
+  return i == sem::IntrinsicType::kAtomicLoad ||
+         i == sem::IntrinsicType::kAtomicStore ||
+         i == sem::IntrinsicType::kAtomicAdd ||
+         i == sem::IntrinsicType::kAtomicMax ||
+         i == sem::IntrinsicType::kAtomicMin ||
+         i == sem::IntrinsicType::kAtomicAnd ||
+         i == sem::IntrinsicType::kAtomicOr ||
+         i == sem::IntrinsicType::kAtomicXor ||
+         i == sem::IntrinsicType::kAtomicExchange ||
+         i == sem::IntrinsicType::kAtomicCompareExchangeWeak;
+}
+
 Intrinsic::Intrinsic(IntrinsicType type,
                      sem::Type* return_type,
                      const ParameterList& parameters,
@@ -136,5 +149,9 @@
   return IsBarrierIntrinsic(type_);
 }
 
+bool Intrinsic::IsAtomic() const {
+  return IsAtomicIntrinsic(type_);
+}
+
 }  // namespace sem
 }  // namespace tint
diff --git a/src/sem/intrinsic.h b/src/sem/intrinsic.h
index 19ce31c..11cea7b 100644
--- a/src/sem/intrinsic.h
+++ b/src/sem/intrinsic.h
@@ -69,6 +69,11 @@
 /// @returns true if the given `i` is a barrier intrinsic
 bool IsBarrierIntrinsic(IntrinsicType i);
 
+/// Determines if the given `i` is a atomic intrinsic
+/// @param i the intrinsic
+/// @returns true if the given `i` is a atomic intrinsic
+bool IsAtomicIntrinsic(IntrinsicType i);
+
 /// Intrinsic holds the semantic information for an intrinsic function.
 class Intrinsic : public Castable<Intrinsic, CallTarget> {
  public:
@@ -129,6 +134,9 @@
   /// @returns true if intrinsic is a barrier intrinsic
   bool IsBarrier() const;
 
+  /// @returns true if intrinsic is a atomic intrinsic
+  bool IsAtomic() const;
+
  private:
   IntrinsicType const type_;
   PipelineStageSet const supported_stages_;
diff --git a/src/transform/decompose_storage_access.cc b/src/transform/decompose_storage_access.cc
index e2ea4c3..a32f15f 100644
--- a/src/transform/decompose_storage_access.cc
+++ b/src/transform/decompose_storage_access.cc
@@ -25,8 +25,10 @@
 #include "src/ast/disable_validation_decoration.h"
 #include "src/ast/scalar_constructor_expression.h"
 #include "src/ast/type_name.h"
+#include "src/ast/unary_op.h"
 #include "src/program_builder.h"
 #include "src/sem/array.h"
+#include "src/sem/atomic_type.h"
 #include "src/sem/call.h"
 #include "src/sem/member_accessor_expression.h"
 #include "src/sem/reference_type.h"
@@ -175,16 +177,31 @@
   return out;
 }
 
-/// TypePair is a pair of types that can be used as a unordered map or set key.
-struct TypePair {
-  sem::Type const* first;
-  sem::Type const* second;
-  bool operator==(const TypePair& rhs) const {
-    return first == rhs.first && second == rhs.second;
+/// LoadStoreKey is the unordered map key to a load or store intrinsic.
+struct LoadStoreKey {
+  sem::Type const* buf_ty;  // buffer type
+  sem::Type const* el_ty;   // element type
+  bool operator==(const LoadStoreKey& rhs) const {
+    return buf_ty == rhs.buf_ty && el_ty == rhs.el_ty;
   }
   struct Hasher {
-    inline std::size_t operator()(const TypePair& u) const {
-      return utils::Hash(u.first, u.second);
+    inline std::size_t operator()(const LoadStoreKey& u) const {
+      return utils::Hash(u.buf_ty, u.el_ty);
+    }
+  };
+};
+
+/// AtomicKey is the unordered map key to an atomic intrinsic.
+struct AtomicKey {
+  sem::Type const* buf_ty;      // buffer type
+  sem::Type const* el_ty;       // element type
+  sem::IntrinsicType const op;  // atomic op
+  bool operator==(const AtomicKey& rhs) const {
+    return buf_ty == rhs.buf_ty && el_ty == rhs.el_ty && op == rhs.op;
+  }
+  struct Hasher {
+    inline std::size_t operator()(const AtomicKey& u) const {
+      return utils::Hash(u.buf_ty, u.el_ty, u.op);
     }
   };
 };
@@ -200,122 +217,145 @@
   return ScalarSize(mat->type()) * ((mat->rows() == 2) ? 2 : 4);
 }
 
-/// @returns a DecomposeStorageAccess::Intrinsic decoration that can be applied
-/// to a stub function to load the type `ty`.
-DecomposeStorageAccess::Intrinsic* IntrinsicLoadFor(ProgramBuilder* builder,
-                                                    const sem::Type* ty) {
-  using Intrinsic = DecomposeStorageAccess::Intrinsic;
-
-  auto intrinsic = [builder](Intrinsic::Type type) {
-    return builder->ASTNodes().Create<Intrinsic>(builder->ID(), type);
-  };
-
+bool IntrinsicDataTypeFor(const sem::Type* ty,
+                          DecomposeStorageAccess::Intrinsic::DataType& out) {
   if (ty->Is<sem::I32>()) {
-    return intrinsic(Intrinsic::kLoadI32);
+    out = DecomposeStorageAccess::Intrinsic::DataType::kI32;
+    return true;
   }
   if (ty->Is<sem::U32>()) {
-    return intrinsic(Intrinsic::kLoadU32);
+    out = DecomposeStorageAccess::Intrinsic::DataType::kU32;
+    return true;
   }
   if (ty->Is<sem::F32>()) {
-    return intrinsic(Intrinsic::kLoadF32);
+    out = DecomposeStorageAccess::Intrinsic::DataType::kF32;
+    return true;
   }
   if (auto* vec = ty->As<sem::Vector>()) {
     switch (vec->size()) {
       case 2:
         if (vec->type()->Is<sem::I32>()) {
-          return intrinsic(Intrinsic::kLoadVec2I32);
+          out = DecomposeStorageAccess::Intrinsic::DataType::kVec2I32;
+          return true;
         }
         if (vec->type()->Is<sem::U32>()) {
-          return intrinsic(Intrinsic::kLoadVec2U32);
+          out = DecomposeStorageAccess::Intrinsic::DataType::kVec2U32;
+          return true;
         }
         if (vec->type()->Is<sem::F32>()) {
-          return intrinsic(Intrinsic::kLoadVec2F32);
+          out = DecomposeStorageAccess::Intrinsic::DataType::kVec2F32;
+          return true;
         }
         break;
       case 3:
         if (vec->type()->Is<sem::I32>()) {
-          return intrinsic(Intrinsic::kLoadVec3I32);
+          out = DecomposeStorageAccess::Intrinsic::DataType::kVec3I32;
+          return true;
         }
         if (vec->type()->Is<sem::U32>()) {
-          return intrinsic(Intrinsic::kLoadVec3U32);
+          out = DecomposeStorageAccess::Intrinsic::DataType::kVec3U32;
+          return true;
         }
         if (vec->type()->Is<sem::F32>()) {
-          return intrinsic(Intrinsic::kLoadVec3F32);
+          out = DecomposeStorageAccess::Intrinsic::DataType::kVec3F32;
+          return true;
         }
         break;
       case 4:
         if (vec->type()->Is<sem::I32>()) {
-          return intrinsic(Intrinsic::kLoadVec4I32);
+          out = DecomposeStorageAccess::Intrinsic::DataType::kVec4I32;
+          return true;
         }
         if (vec->type()->Is<sem::U32>()) {
-          return intrinsic(Intrinsic::kLoadVec4U32);
+          out = DecomposeStorageAccess::Intrinsic::DataType::kVec4U32;
+          return true;
         }
         if (vec->type()->Is<sem::F32>()) {
-          return intrinsic(Intrinsic::kLoadVec4F32);
+          out = DecomposeStorageAccess::Intrinsic::DataType::kVec4F32;
+          return true;
         }
         break;
     }
+    return false;
   }
-  return nullptr;
+
+  return false;
+}
+
+/// @returns a DecomposeStorageAccess::Intrinsic decoration that can be applied
+/// to a stub function to load the type `ty`.
+DecomposeStorageAccess::Intrinsic* IntrinsicLoadFor(ProgramBuilder* builder,
+                                                    const sem::Type* ty) {
+  DecomposeStorageAccess::Intrinsic::DataType type;
+  if (!IntrinsicDataTypeFor(ty, type)) {
+    return nullptr;
+  }
+  return builder->ASTNodes().Create<DecomposeStorageAccess::Intrinsic>(
+      builder->ID(), DecomposeStorageAccess::Intrinsic::Op::kLoad, type);
 }
 
 /// @returns a DecomposeStorageAccess::Intrinsic decoration that can be applied
 /// to a stub function to store the type `ty`.
 DecomposeStorageAccess::Intrinsic* IntrinsicStoreFor(ProgramBuilder* builder,
                                                      const sem::Type* ty) {
-  using Intrinsic = DecomposeStorageAccess::Intrinsic;
+  DecomposeStorageAccess::Intrinsic::DataType type;
+  if (!IntrinsicDataTypeFor(ty, type)) {
+    return nullptr;
+  }
+  return builder->ASTNodes().Create<DecomposeStorageAccess::Intrinsic>(
+      builder->ID(), DecomposeStorageAccess::Intrinsic::Op::kStore, type);
+}
 
-  auto intrinsic = [builder](Intrinsic::Type type) {
-    return builder->ASTNodes().Create<Intrinsic>(builder->ID(), type);
-  };
+/// @returns a DecomposeStorageAccess::Intrinsic decoration that can be applied
+/// to a stub function for the atomic op and the type `ty`.
+DecomposeStorageAccess::Intrinsic* IntrinsicAtomicFor(ProgramBuilder* builder,
+                                                      sem::IntrinsicType ity,
+                                                      const sem::Type* ty) {
+  auto op = DecomposeStorageAccess::Intrinsic::Op::kAtomicLoad;
+  switch (ity) {
+    case sem::IntrinsicType::kAtomicLoad:
+      op = DecomposeStorageAccess::Intrinsic::Op::kAtomicLoad;
+      break;
+    case sem::IntrinsicType::kAtomicStore:
+      op = DecomposeStorageAccess::Intrinsic::Op::kAtomicStore;
+      break;
+    case sem::IntrinsicType::kAtomicAdd:
+      op = DecomposeStorageAccess::Intrinsic::Op::kAtomicAdd;
+      break;
+    case sem::IntrinsicType::kAtomicMax:
+      op = DecomposeStorageAccess::Intrinsic::Op::kAtomicMax;
+      break;
+    case sem::IntrinsicType::kAtomicMin:
+      op = DecomposeStorageAccess::Intrinsic::Op::kAtomicMin;
+      break;
+    case sem::IntrinsicType::kAtomicAnd:
+      op = DecomposeStorageAccess::Intrinsic::Op::kAtomicAnd;
+      break;
+    case sem::IntrinsicType::kAtomicOr:
+      op = DecomposeStorageAccess::Intrinsic::Op::kAtomicOr;
+      break;
+    case sem::IntrinsicType::kAtomicXor:
+      op = DecomposeStorageAccess::Intrinsic::Op::kAtomicXor;
+      break;
+    case sem::IntrinsicType::kAtomicExchange:
+      op = DecomposeStorageAccess::Intrinsic::Op::kAtomicExchange;
+      break;
+    case sem::IntrinsicType::kAtomicCompareExchangeWeak:
+      op = DecomposeStorageAccess::Intrinsic::Op::kAtomicCompareExchangeWeak;
+      break;
+    default:
+      TINT_ICE(builder->Diagnostics())
+          << "invalid IntrinsicType for DecomposeStorageAccess::Intrinsic: "
+          << ty->type_name();
+      break;
+  }
 
-  if (ty->Is<sem::I32>()) {
-    return intrinsic(Intrinsic::kStoreI32);
+  DecomposeStorageAccess::Intrinsic::DataType type;
+  if (!IntrinsicDataTypeFor(ty, type)) {
+    return nullptr;
   }
-  if (ty->Is<sem::U32>()) {
-    return intrinsic(Intrinsic::kStoreU32);
-  }
-  if (ty->Is<sem::F32>()) {
-    return intrinsic(Intrinsic::kStoreF32);
-  }
-  if (auto* vec = ty->As<sem::Vector>()) {
-    switch (vec->size()) {
-      case 2:
-        if (vec->type()->Is<sem::I32>()) {
-          return intrinsic(Intrinsic::kStoreVec2U32);
-        }
-        if (vec->type()->Is<sem::U32>()) {
-          return intrinsic(Intrinsic::kStoreVec2F32);
-        }
-        if (vec->type()->Is<sem::F32>()) {
-          return intrinsic(Intrinsic::kStoreVec2I32);
-        }
-        break;
-      case 3:
-        if (vec->type()->Is<sem::I32>()) {
-          return intrinsic(Intrinsic::kStoreVec3U32);
-        }
-        if (vec->type()->Is<sem::U32>()) {
-          return intrinsic(Intrinsic::kStoreVec3F32);
-        }
-        if (vec->type()->Is<sem::F32>()) {
-          return intrinsic(Intrinsic::kStoreVec3I32);
-        }
-        break;
-      case 4:
-        if (vec->type()->Is<sem::I32>()) {
-          return intrinsic(Intrinsic::kStoreVec4U32);
-        }
-        if (vec->type()->Is<sem::U32>()) {
-          return intrinsic(Intrinsic::kStoreVec4F32);
-        }
-        if (vec->type()->Is<sem::F32>()) {
-          return intrinsic(Intrinsic::kStoreVec4I32);
-        }
-        break;
-    }
-  }
-  return nullptr;
+  return builder->ASTNodes().Create<DecomposeStorageAccess::Intrinsic>(
+      builder->ID(), op, type);
 }
 
 /// Inserts `node` before `insert_after` in the global declarations of
@@ -374,9 +414,11 @@
   /// The visited order of AST expressions (superset of #accesses)
   std::vector<ast::Expression*> expression_order;
   /// [buffer-type, element-type] -> load function name
-  std::unordered_map<TypePair, Symbol, TypePair::Hasher> load_funcs;
+  std::unordered_map<LoadStoreKey, Symbol, LoadStoreKey::Hasher> load_funcs;
   /// [buffer-type, element-type] -> store function name
-  std::unordered_map<TypePair, Symbol, TypePair::Hasher> store_funcs;
+  std::unordered_map<LoadStoreKey, Symbol, LoadStoreKey::Hasher> store_funcs;
+  /// [buffer-type, element-type, atomic-op] -> load function name
+  std::unordered_map<AtomicKey, Symbol, AtomicKey::Hasher> atomic_funcs;
   /// List of storage buffer writes
   std::vector<Store> stores;
 
@@ -419,7 +461,7 @@
                   const sem::Type* buf_ty,
                   const sem::Type* el_ty,
                   const sem::VariableUser* var_user) {
-    return utils::GetOrCreate(load_funcs, TypePair{buf_ty, el_ty}, [&] {
+    return utils::GetOrCreate(load_funcs, LoadStoreKey{buf_ty, el_ty}, [&] {
       auto* buf_ast_ty = CreateASTTypeFor(&ctx, buf_ty);
 
       ast::VariableList params = {
@@ -495,7 +537,7 @@
                    const sem::Type* buf_ty,
                    const sem::Type* el_ty,
                    const sem::VariableUser* var_user) {
-    return utils::GetOrCreate(store_funcs, TypePair{buf_ty, el_ty}, [&] {
+    return utils::GetOrCreate(store_funcs, LoadStoreKey{buf_ty, el_ty}, [&] {
       auto* buf_ast_ty = CreateASTTypeFor(&ctx, buf_ty);
       auto* el_ast_ty = CreateASTTypeFor(&ctx, el_ty);
       ast::VariableList params{
@@ -560,69 +602,161 @@
       return func->symbol();
     });
   }
+
+  /// AtomicFunc() returns a symbol to an intrinsic function that performs an
+  /// atomic operation from a storage buffer of type `buf_ty`. The function has
+  /// the signature:
+  // `fn atomic_op(buf : buf_ty, offset : u32, ...) -> T`
+  /// @param ctx the CloneContext
+  /// @param insert_after the user-declared type to insert the function after
+  /// @param buf_ty the storage buffer type
+  /// @param el_ty the storage buffer element type
+  /// @param intrinsic the atomic intrinsic
+  /// @param var_user the variable user
+  /// @return the name of the function that performs the load
+  Symbol AtomicFunc(CloneContext& ctx,
+                    const ast::TypeDecl* insert_after,
+                    const sem::Type* buf_ty,
+                    const sem::Type* el_ty,
+                    const sem::Intrinsic* intrinsic,
+                    const sem::VariableUser* var_user) {
+    auto op = intrinsic->Type();
+    return utils::GetOrCreate(atomic_funcs, AtomicKey{buf_ty, el_ty, op}, [&] {
+      auto* buf_ast_ty = CreateASTTypeFor(&ctx, buf_ty);
+
+      // The first parameter to all WGSL atomics is the expression to the
+      // atomic. This is replaced with two parameters: the buffer and offset.
+
+      ast::VariableList params = {
+          // Note: The buffer parameter requires the kStorage StorageClass in
+          // order for HLSL to emit this as a ByteAddressBuffer.
+          ctx.dst->create<ast::Variable>(
+              ctx.dst->Sym("buffer"), ast::StorageClass::kStorage,
+              var_user->Variable()->Access(), buf_ast_ty, true, nullptr,
+              ast::DecorationList{}),
+          ctx.dst->Param("offset", ctx.dst->ty.u32()),
+      };
+
+      // Other parameters are copied as-is:
+      for (size_t i = 1; i < intrinsic->Parameters().size(); i++) {
+        auto& param = intrinsic->Parameters()[i];
+        auto* ty = CreateASTTypeFor(&ctx, param.type);
+        params.emplace_back(ctx.dst->Param("param_" + std::to_string(i), ty));
+      }
+
+      auto* atomic = IntrinsicAtomicFor(ctx.dst, op, el_ty);
+      if (atomic == nullptr) {
+        TINT_ICE(ctx.dst->Diagnostics())
+            << "IntrinsicAtomicFor() returned nullptr for op " << op
+            << " and type " << el_ty->type_name();
+      }
+
+      auto* ret_ty = CreateASTTypeFor(&ctx, intrinsic->ReturnType());
+      auto* func = ctx.dst->create<ast::Function>(
+          ctx.dst->Sym(), params, ret_ty, nullptr,
+          ast::DecorationList{
+              atomic,
+              ctx.dst->ASTNodes().Create<ast::DisableValidationDecoration>(
+                  ctx.dst->ID(), ast::DisabledValidation::kFunctionHasNoBody),
+          },
+          ast::DecorationList{});
+
+      InsertGlobal(ctx, insert_after, func);
+      return func->symbol();
+    });
+  }
 };
 
-DecomposeStorageAccess::Intrinsic::Intrinsic(ProgramID program_id, Type ty)
-    : Base(program_id), type(ty) {}
+DecomposeStorageAccess::Intrinsic::Intrinsic(ProgramID program_id,
+                                             Op o,
+                                             DataType ty)
+    : Base(program_id), op(o), type(ty) {}
 DecomposeStorageAccess::Intrinsic::~Intrinsic() = default;
 std::string DecomposeStorageAccess::Intrinsic::InternalName() const {
-  switch (type) {
-    case kLoadU32:
-      return "intrinsic_load_u32";
-    case kLoadF32:
-      return "intrinsic_load_f32";
-    case kLoadI32:
-      return "intrinsic_load_i32";
-    case kLoadVec2U32:
-      return "intrinsic_load_vec2_u32";
-    case kLoadVec2F32:
-      return "intrinsic_load_vec2_f32";
-    case kLoadVec2I32:
-      return "intrinsic_load_vec2_i32";
-    case kLoadVec3U32:
-      return "intrinsic_load_vec3_u32";
-    case kLoadVec3F32:
-      return "intrinsic_load_vec3_f32";
-    case kLoadVec3I32:
-      return "intrinsic_load_vec3_i32";
-    case kLoadVec4U32:
-      return "intrinsic_load_vec4_u32";
-    case kLoadVec4F32:
-      return "intrinsic_load_vec4_f32";
-    case kLoadVec4I32:
-      return "intrinsic_load_vec4_i32";
-    case kStoreU32:
-      return "intrinsic_store_u32";
-    case kStoreF32:
-      return "intrinsic_store_f32";
-    case kStoreI32:
-      return "intrinsic_store_i32";
-    case kStoreVec2U32:
-      return "intrinsic_store_vec2_u32";
-    case kStoreVec2F32:
-      return "intrinsic_store_vec2_f32";
-    case kStoreVec2I32:
-      return "intrinsic_store_vec2_i32";
-    case kStoreVec3U32:
-      return "intrinsic_store_vec3_u32";
-    case kStoreVec3F32:
-      return "intrinsic_store_vec3_f32";
-    case kStoreVec3I32:
-      return "intrinsic_store_vec3_i32";
-    case kStoreVec4U32:
-      return "intrinsic_store_vec4_u32";
-    case kStoreVec4F32:
-      return "intrinsic_store_vec4_f32";
-    case kStoreVec4I32:
-      return "intrinsic_store_vec4_i32";
+  std::stringstream ss;
+  switch (op) {
+    case Op::kLoad:
+      ss << "intrinsic_load_";
+      break;
+    case Op::kStore:
+      ss << "intrinsic_store_";
+      break;
+    case Op::kAtomicLoad:
+      ss << "intrinsic_atomic_load_";
+      break;
+    case Op::kAtomicStore:
+      ss << "intrinsic_atomic_store_";
+      break;
+    case Op::kAtomicAdd:
+      ss << "intrinsic_atomic_add_";
+      break;
+    case Op::kAtomicMax:
+      ss << "intrinsic_atomic_max_";
+      break;
+    case Op::kAtomicMin:
+      ss << "intrinsic_atomic_min_";
+      break;
+    case Op::kAtomicAnd:
+      ss << "intrinsic_atomic_and_";
+      break;
+    case Op::kAtomicOr:
+      ss << "intrinsic_atomic_or_";
+      break;
+    case Op::kAtomicXor:
+      ss << "intrinsic_atomic_xor_";
+      break;
+    case Op::kAtomicExchange:
+      ss << "intrinsic_atomic_exchange_";
+      break;
+    case Op::kAtomicCompareExchangeWeak:
+      ss << "intrinsic_atomic_compare_exchange_weak_";
+      break;
   }
-  return "";
+  switch (type) {
+    case DataType::kU32:
+      ss << "u32";
+      break;
+    case DataType::kF32:
+      ss << "f32";
+      break;
+    case DataType::kI32:
+      ss << "i32";
+      break;
+    case DataType::kVec2U32:
+      ss << "vec2_u32";
+      break;
+    case DataType::kVec2F32:
+      ss << "vec2_f32";
+      break;
+    case DataType::kVec2I32:
+      ss << "vec2_i32";
+      break;
+    case DataType::kVec3U32:
+      ss << "vec3_u32";
+      break;
+    case DataType::kVec3F32:
+      ss << "vec3_f32";
+      break;
+    case DataType::kVec3I32:
+      ss << "vec3_i32";
+      break;
+    case DataType::kVec4U32:
+      ss << "vec4_u32";
+      break;
+    case DataType::kVec4F32:
+      ss << "vec4_f32";
+      break;
+    case DataType::kVec4I32:
+      ss << "vec4_i32";
+      break;
+  }
+  return ss.str();
 }
 
 DecomposeStorageAccess::Intrinsic* DecomposeStorageAccess::Intrinsic::Clone(
     CloneContext* ctx) const {
   return ctx->dst->ASTNodes().Create<DecomposeStorageAccess::Intrinsic>(
-      ctx->dst->ID(), type);
+      ctx->dst->ID(), op, type);
 }
 
 DecomposeStorageAccess::DecomposeStorageAccess() = default;
@@ -728,6 +862,18 @@
       }
     }
 
+    if (auto* op = node->As<ast::UnaryOpExpression>()) {
+      if (op->op() == ast::UnaryOp::kAddressOf) {
+        // &X
+        if (auto access = state.TakeAccess(op->expr())) {
+          // HLSL does not support pointers, so just take the access from the
+          // reference and place it on the pointer.
+          state.AddAccess(op, std::move(access));
+          continue;
+        }
+      }
+    }
+
     if (auto* assign = node->As<ast::AssignmentStatement>()) {
       // X = Y
       // Move the LHS access to a store.
@@ -741,16 +887,31 @@
       if (auto* intrinsic = call->Target()->As<sem::Intrinsic>()) {
         if (intrinsic->Type() == sem::IntrinsicType::kArrayLength) {
           // arrayLength(X)
-          // Don't convert X into a load, this actually requires the real
-          // reference.
-          auto* arg = call_expr->params()[0];
+          // Don't convert X into a load, this intrinsic actually requires the
+          // real pointer.
+          state.TakeAccess(call_expr->params()[0]);
+        }
+        if (intrinsic->IsAtomic()) {
+          if (auto access = state.TakeAccess(call_expr->params()[0])) {
+            // atomic___(X)
 
-          // TODO(crbug.com/tint/806): Once the deprecated arrayLength()
-          // overload is removed,  this can safely assume a pointer arg.
-          if (auto* address_of = arg->As<ast::UnaryOpExpression>()) {
-            arg = address_of->expr();
+            auto* buf = access.var->Declaration();
+            auto* offset = access.offset->Build(ctx);
+            auto* buf_ty = access.var->Type()->UnwrapRef();
+            auto* el_ty = access.type->UnwrapRef()->As<sem::Atomic>()->Type();
+            auto* insert_after = TypeDeclOf(access.var->Type());
+            Symbol func =
+                state.AtomicFunc(ctx, insert_after, buf_ty, el_ty, intrinsic,
+                                 access.var->As<sem::VariableUser>());
+
+            ast::ExpressionList args{ctx.Clone(buf), offset};
+            for (size_t i = 1; i < call_expr->params().size(); i++) {
+              auto* arg = call_expr->params()[i];
+              args.emplace_back(ctx.Clone(arg));
+            }
+
+            ctx.Replace(call_expr, ctx.dst->Call(func, args));
           }
-          state.TakeAccess(arg);
         }
       }
     }
diff --git a/src/transform/decompose_storage_access.h b/src/transform/decompose_storage_access.h
index ad593b9..c257ec9 100644
--- a/src/transform/decompose_storage_access.h
+++ b/src/transform/decompose_storage_access.h
@@ -28,7 +28,8 @@
 namespace transform {
 
 /// DecomposeStorageAccess is a transform used to replace storage buffer
-/// accesses with a combination of load / store functions on primitive types.
+/// accesses with a combination of load, store or atomic functions on primitive
+/// types.
 class DecomposeStorageAccess : public Transform {
  public:
   /// Intrinsic is an InternalDecoration that's used to decorate a stub function
@@ -37,38 +38,43 @@
   /// with a possible cast.
   class Intrinsic : public Castable<Intrinsic, ast::InternalDecoration> {
    public:
-    /// Storage access intrinsic type
-    enum Type {
-      kLoadU32,       // `[RW]ByteAddressBuffer.Load()`
-      kLoadF32,       // `asfloat([RW]ByteAddressBuffer.Load())`
-      kLoadI32,       // `asint([RW]ByteAddressBuffer.Load())`
-      kLoadVec2U32,   // `[RW]ByteAddressBuffer.Load2()`
-      kLoadVec2F32,   // `asfloat([RW]ByteAddressBuffer.Load2())`
-      kLoadVec2I32,   // `asint([RW]ByteAddressBuffer.Load2())`
-      kLoadVec3U32,   // `[RW]ByteAddressBuffer.Load3()`
-      kLoadVec3F32,   // `asfloat([RW]ByteAddressBuffer.Load3())`
-      kLoadVec3I32,   // `asint([RW]ByteAddressBuffer.Load3())`
-      kLoadVec4U32,   // `[RW]ByteAddressBuffer.Load4()`
-      kLoadVec4F32,   // `asfloat([RW]ByteAddressBuffer.Load4())`
-      kLoadVec4I32,   // `asint([RW]ByteAddressBuffer.Load4())`
-      kStoreU32,      // `RWByteAddressBuffer.Store()`
-      kStoreF32,      // `asfloat(RWByteAddressBuffer.Store())`
-      kStoreI32,      // `asint(RWByteAddressBuffer.Store())`
-      kStoreVec2U32,  // `RWByteAddressBuffer.Store2()`
-      kStoreVec2F32,  // `asfloat(RWByteAddressBuffer.Store2())`
-      kStoreVec2I32,  // `asint(RWByteAddressBuffer.Store2())`
-      kStoreVec3U32,  // `RWByteAddressBuffer.Store3()`
-      kStoreVec3F32,  // `asfloat(RWByteAddressBuffer.Store3())`
-      kStoreVec3I32,  // `asint(RWByteAddressBuffer.Store3())`
-      kStoreVec4U32,  // `RWByteAddressBuffer.Store4()`
-      kStoreVec4F32,  // `asfloat(RWByteAddressBuffer.Store4())`
-      kStoreVec4I32,  // `asint(RWByteAddressBuffer.Store4())`
+    /// Intrinsic op
+    enum class Op {
+      kLoad,
+      kStore,
+      kAtomicLoad,
+      kAtomicStore,
+      kAtomicAdd,
+      kAtomicMax,
+      kAtomicMin,
+      kAtomicAnd,
+      kAtomicOr,
+      kAtomicXor,
+      kAtomicExchange,
+      kAtomicCompareExchangeWeak,
+    };
+
+    /// Intrinsic data type
+    enum class DataType {
+      kU32,
+      kF32,
+      kI32,
+      kVec2U32,
+      kVec2F32,
+      kVec2I32,
+      kVec3U32,
+      kVec3F32,
+      kVec3I32,
+      kVec4U32,
+      kVec4F32,
+      kVec4I32,
     };
 
     /// Constructor
     /// @param program_id the identifier of the program that owns this node
-    /// @param ty the type of the intrinsic
-    Intrinsic(ProgramID program_id, Type ty);
+    /// @param o the op of the intrinsic
+    /// @param ty the data type of the intrinsic
+    Intrinsic(ProgramID program_id, Op o, DataType ty);
     /// Destructor
     ~Intrinsic() override;
 
@@ -81,8 +87,11 @@
     /// @return the newly cloned object
     Intrinsic* Clone(CloneContext* ctx) const override;
 
+    /// The op of the intrinsic
+    Op const op;
+
     /// The type of the intrinsic
-    Type const type;
+    DataType const type;
   };
 
   /// Constructor
diff --git a/src/transform/decompose_storage_access_test.cc b/src/transform/decompose_storage_access_test.cc
index 5d870f9..4c7c035 100644
--- a/src/transform/decompose_storage_access_test.cc
+++ b/src/transform/decompose_storage_access_test.cc
@@ -309,31 +309,31 @@
 [[internal(intrinsic_store_f32), internal(disable_validation__function_has_no_body)]]
 fn tint_symbol_2(buffer : SB, offset : u32, value : f32)
 
-[[internal(intrinsic_store_vec2_u32), internal(disable_validation__function_has_no_body)]]
+[[internal(intrinsic_store_vec2_i32), internal(disable_validation__function_has_no_body)]]
 fn tint_symbol_3(buffer : SB, offset : u32, value : vec2<i32>)
 
-[[internal(intrinsic_store_vec2_f32), internal(disable_validation__function_has_no_body)]]
+[[internal(intrinsic_store_vec2_u32), internal(disable_validation__function_has_no_body)]]
 fn tint_symbol_4(buffer : SB, offset : u32, value : vec2<u32>)
 
-[[internal(intrinsic_store_vec2_i32), internal(disable_validation__function_has_no_body)]]
+[[internal(intrinsic_store_vec2_f32), internal(disable_validation__function_has_no_body)]]
 fn tint_symbol_5(buffer : SB, offset : u32, value : vec2<f32>)
 
-[[internal(intrinsic_store_vec3_u32), internal(disable_validation__function_has_no_body)]]
+[[internal(intrinsic_store_vec3_i32), internal(disable_validation__function_has_no_body)]]
 fn tint_symbol_6(buffer : SB, offset : u32, value : vec3<i32>)
 
-[[internal(intrinsic_store_vec3_f32), internal(disable_validation__function_has_no_body)]]
+[[internal(intrinsic_store_vec3_u32), internal(disable_validation__function_has_no_body)]]
 fn tint_symbol_7(buffer : SB, offset : u32, value : vec3<u32>)
 
-[[internal(intrinsic_store_vec3_i32), internal(disable_validation__function_has_no_body)]]
+[[internal(intrinsic_store_vec3_f32), internal(disable_validation__function_has_no_body)]]
 fn tint_symbol_8(buffer : SB, offset : u32, value : vec3<f32>)
 
-[[internal(intrinsic_store_vec4_u32), internal(disable_validation__function_has_no_body)]]
+[[internal(intrinsic_store_vec4_i32), internal(disable_validation__function_has_no_body)]]
 fn tint_symbol_9(buffer : SB, offset : u32, value : vec4<i32>)
 
-[[internal(intrinsic_store_vec4_f32), internal(disable_validation__function_has_no_body)]]
+[[internal(intrinsic_store_vec4_u32), internal(disable_validation__function_has_no_body)]]
 fn tint_symbol_10(buffer : SB, offset : u32, value : vec4<u32>)
 
-[[internal(intrinsic_store_vec4_i32), internal(disable_validation__function_has_no_body)]]
+[[internal(intrinsic_store_vec4_f32), internal(disable_validation__function_has_no_body)]]
 fn tint_symbol_11(buffer : SB, offset : u32, value : vec4<f32>)
 
 fn tint_symbol_12(buffer : SB, offset : u32, value : mat2x2<f32>) {
@@ -657,31 +657,31 @@
 [[internal(intrinsic_store_f32), internal(disable_validation__function_has_no_body)]]
 fn tint_symbol_2(buffer : SB, offset : u32, value : f32)
 
-[[internal(intrinsic_store_vec2_u32), internal(disable_validation__function_has_no_body)]]
+[[internal(intrinsic_store_vec2_i32), internal(disable_validation__function_has_no_body)]]
 fn tint_symbol_3(buffer : SB, offset : u32, value : vec2<i32>)
 
-[[internal(intrinsic_store_vec2_f32), internal(disable_validation__function_has_no_body)]]
+[[internal(intrinsic_store_vec2_u32), internal(disable_validation__function_has_no_body)]]
 fn tint_symbol_4(buffer : SB, offset : u32, value : vec2<u32>)
 
-[[internal(intrinsic_store_vec2_i32), internal(disable_validation__function_has_no_body)]]
+[[internal(intrinsic_store_vec2_f32), internal(disable_validation__function_has_no_body)]]
 fn tint_symbol_5(buffer : SB, offset : u32, value : vec2<f32>)
 
-[[internal(intrinsic_store_vec3_u32), internal(disable_validation__function_has_no_body)]]
+[[internal(intrinsic_store_vec3_i32), internal(disable_validation__function_has_no_body)]]
 fn tint_symbol_6(buffer : SB, offset : u32, value : vec3<i32>)
 
-[[internal(intrinsic_store_vec3_f32), internal(disable_validation__function_has_no_body)]]
+[[internal(intrinsic_store_vec3_u32), internal(disable_validation__function_has_no_body)]]
 fn tint_symbol_7(buffer : SB, offset : u32, value : vec3<u32>)
 
-[[internal(intrinsic_store_vec3_i32), internal(disable_validation__function_has_no_body)]]
+[[internal(intrinsic_store_vec3_f32), internal(disable_validation__function_has_no_body)]]
 fn tint_symbol_8(buffer : SB, offset : u32, value : vec3<f32>)
 
-[[internal(intrinsic_store_vec4_u32), internal(disable_validation__function_has_no_body)]]
+[[internal(intrinsic_store_vec4_i32), internal(disable_validation__function_has_no_body)]]
 fn tint_symbol_9(buffer : SB, offset : u32, value : vec4<i32>)
 
-[[internal(intrinsic_store_vec4_f32), internal(disable_validation__function_has_no_body)]]
+[[internal(intrinsic_store_vec4_u32), internal(disable_validation__function_has_no_body)]]
 fn tint_symbol_10(buffer : SB, offset : u32, value : vec4<u32>)
 
-[[internal(intrinsic_store_vec4_i32), internal(disable_validation__function_has_no_body)]]
+[[internal(intrinsic_store_vec4_f32), internal(disable_validation__function_has_no_body)]]
 fn tint_symbol_11(buffer : SB, offset : u32, value : vec4<f32>)
 
 fn tint_symbol_12(buffer : SB, offset : u32, value : mat2x2<f32>) {
@@ -1011,6 +1011,185 @@
   EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(DecomposeStorageAccessTest, StorageBufferAtomics) {
+  auto* src = R"(
+[[block]]
+struct SB {
+  padding : vec4<f32>;
+  a : atomic<i32>;
+  b : atomic<u32>;
+};
+
+[[group(0), binding(0)]] var<storage, read_write> sb : SB;
+
+[[stage(compute)]]
+fn main() {
+  atomicStore(&sb.a, 123);
+  ignore(atomicLoad(&sb.a));
+  ignore(atomicAdd(&sb.a, 123));
+  ignore(atomicMax(&sb.a, 123));
+  ignore(atomicMin(&sb.a, 123));
+  ignore(atomicAnd(&sb.a, 123));
+  ignore(atomicOr(&sb.a, 123));
+  ignore(atomicXor(&sb.a, 123));
+  ignore(atomicExchange(&sb.a, 123));
+  ignore(atomicCompareExchangeWeak(&sb.a, 123, 345));
+
+  atomicStore(&sb.b, 123u);
+  ignore(atomicLoad(&sb.b));
+  ignore(atomicAdd(&sb.b, 123u));
+  ignore(atomicMax(&sb.b, 123u));
+  ignore(atomicMin(&sb.b, 123u));
+  ignore(atomicAnd(&sb.b, 123u));
+  ignore(atomicOr(&sb.b, 123u));
+  ignore(atomicXor(&sb.b, 123u));
+  ignore(atomicExchange(&sb.b, 123u));
+  ignore(atomicCompareExchangeWeak(&sb.b, 123u, 345u));
+}
+)";
+
+  auto* expect = R"(
+[[block]]
+struct SB {
+  padding : vec4<f32>;
+  a : atomic<i32>;
+  b : atomic<u32>;
+};
+
+[[internal(intrinsic_atomic_store_i32), internal(disable_validation__function_has_no_body)]]
+fn tint_symbol(buffer : SB, offset : u32, param_1 : i32)
+
+[[internal(intrinsic_atomic_load_i32), internal(disable_validation__function_has_no_body)]]
+fn tint_symbol_1(buffer : SB, offset : u32) -> i32
+
+[[internal(intrinsic_atomic_add_i32), internal(disable_validation__function_has_no_body)]]
+fn tint_symbol_2(buffer : SB, offset : u32, param_1 : i32) -> i32
+
+[[internal(intrinsic_atomic_max_i32), internal(disable_validation__function_has_no_body)]]
+fn tint_symbol_3(buffer : SB, offset : u32, param_1 : i32) -> i32
+
+[[internal(intrinsic_atomic_min_i32), internal(disable_validation__function_has_no_body)]]
+fn tint_symbol_4(buffer : SB, offset : u32, param_1 : i32) -> i32
+
+[[internal(intrinsic_atomic_and_i32), internal(disable_validation__function_has_no_body)]]
+fn tint_symbol_5(buffer : SB, offset : u32, param_1 : i32) -> i32
+
+[[internal(intrinsic_atomic_or_i32), internal(disable_validation__function_has_no_body)]]
+fn tint_symbol_6(buffer : SB, offset : u32, param_1 : i32) -> i32
+
+[[internal(intrinsic_atomic_xor_i32), internal(disable_validation__function_has_no_body)]]
+fn tint_symbol_7(buffer : SB, offset : u32, param_1 : i32) -> i32
+
+[[internal(intrinsic_atomic_exchange_i32), internal(disable_validation__function_has_no_body)]]
+fn tint_symbol_8(buffer : SB, offset : u32, param_1 : i32) -> i32
+
+[[internal(intrinsic_atomic_compare_exchange_weak_i32), internal(disable_validation__function_has_no_body)]]
+fn tint_symbol_9(buffer : SB, offset : u32, param_1 : i32, param_2 : i32) -> vec2<i32>
+
+[[internal(intrinsic_atomic_store_u32), internal(disable_validation__function_has_no_body)]]
+fn tint_symbol_10(buffer : SB, offset : u32, param_1 : u32)
+
+[[internal(intrinsic_atomic_load_u32), internal(disable_validation__function_has_no_body)]]
+fn tint_symbol_11(buffer : SB, offset : u32) -> u32
+
+[[internal(intrinsic_atomic_add_u32), internal(disable_validation__function_has_no_body)]]
+fn tint_symbol_12(buffer : SB, offset : u32, param_1 : u32) -> u32
+
+[[internal(intrinsic_atomic_max_u32), internal(disable_validation__function_has_no_body)]]
+fn tint_symbol_13(buffer : SB, offset : u32, param_1 : u32) -> u32
+
+[[internal(intrinsic_atomic_min_u32), internal(disable_validation__function_has_no_body)]]
+fn tint_symbol_14(buffer : SB, offset : u32, param_1 : u32) -> u32
+
+[[internal(intrinsic_atomic_and_u32), internal(disable_validation__function_has_no_body)]]
+fn tint_symbol_15(buffer : SB, offset : u32, param_1 : u32) -> u32
+
+[[internal(intrinsic_atomic_or_u32), internal(disable_validation__function_has_no_body)]]
+fn tint_symbol_16(buffer : SB, offset : u32, param_1 : u32) -> u32
+
+[[internal(intrinsic_atomic_xor_u32), internal(disable_validation__function_has_no_body)]]
+fn tint_symbol_17(buffer : SB, offset : u32, param_1 : u32) -> u32
+
+[[internal(intrinsic_atomic_exchange_u32), internal(disable_validation__function_has_no_body)]]
+fn tint_symbol_18(buffer : SB, offset : u32, param_1 : u32) -> u32
+
+[[internal(intrinsic_atomic_compare_exchange_weak_u32), internal(disable_validation__function_has_no_body)]]
+fn tint_symbol_19(buffer : SB, offset : u32, param_1 : u32, param_2 : u32) -> vec2<u32>
+
+[[group(0), binding(0)]] var<storage, read_write> sb : SB;
+
+[[stage(compute)]]
+fn main() {
+  tint_symbol(sb, 16u, 123);
+  ignore(tint_symbol_1(sb, 16u));
+  ignore(tint_symbol_2(sb, 16u, 123));
+  ignore(tint_symbol_3(sb, 16u, 123));
+  ignore(tint_symbol_4(sb, 16u, 123));
+  ignore(tint_symbol_5(sb, 16u, 123));
+  ignore(tint_symbol_6(sb, 16u, 123));
+  ignore(tint_symbol_7(sb, 16u, 123));
+  ignore(tint_symbol_8(sb, 16u, 123));
+  ignore(tint_symbol_9(sb, 16u, 123, 345));
+  tint_symbol_10(sb, 20u, 123u);
+  ignore(tint_symbol_11(sb, 20u));
+  ignore(tint_symbol_12(sb, 20u, 123u));
+  ignore(tint_symbol_13(sb, 20u, 123u));
+  ignore(tint_symbol_14(sb, 20u, 123u));
+  ignore(tint_symbol_15(sb, 20u, 123u));
+  ignore(tint_symbol_16(sb, 20u, 123u));
+  ignore(tint_symbol_17(sb, 20u, 123u));
+  ignore(tint_symbol_18(sb, 20u, 123u));
+  ignore(tint_symbol_19(sb, 20u, 123u, 345u));
+}
+)";
+
+  auto got = Run<DecomposeStorageAccess>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(DecomposeStorageAccessTest, WorkgroupBufferAtomics) {
+  auto* src = R"(
+struct S {
+  padding : vec4<f32>;
+  a : atomic<i32>;
+  b : atomic<u32>;
+};
+
+var<workgroup> w : S;
+
+[[stage(compute)]]
+fn main() {
+  atomicStore(&(w.a), 123);
+  ignore(atomicLoad(&(w.a)));
+  ignore(atomicAdd(&(w.a), 123));
+  ignore(atomicMax(&(w.a), 123));
+  ignore(atomicMin(&(w.a), 123));
+  ignore(atomicAnd(&(w.a), 123));
+  ignore(atomicOr(&(w.a), 123));
+  ignore(atomicXor(&(w.a), 123));
+  ignore(atomicExchange(&(w.a), 123));
+  ignore(atomicCompareExchangeWeak(&(w.a), 123, 345));
+  atomicStore(&(w.b), 123u);
+  ignore(atomicLoad(&(w.b)));
+  ignore(atomicAdd(&(w.b), 123u));
+  ignore(atomicMax(&(w.b), 123u));
+  ignore(atomicMin(&(w.b), 123u));
+  ignore(atomicAnd(&(w.b), 123u));
+  ignore(atomicOr(&(w.b), 123u));
+  ignore(atomicXor(&(w.b), 123u));
+  ignore(atomicExchange(&(w.b), 123u));
+  ignore(atomicCompareExchangeWeak(&(w.b), 123u, 345u));
+}
+)";
+
+  auto* expect = src;
+
+  auto got = Run<DecomposeStorageAccess>(src);
+
+  EXPECT_EQ(expect, str(got));
+}
+
 }  // namespace
 }  // namespace transform
 }  // namespace tint
diff --git a/src/transform/transform.cc b/src/transform/transform.cc
index 2fbe85d..c334337 100644
--- a/src/transform/transform.cc
+++ b/src/transform/transform.cc
@@ -17,6 +17,7 @@
 #include <algorithm>
 
 #include "src/program_builder.h"
+#include "src/sem/atomic_type.h"
 #include "src/sem/reference_type.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::transform::Data);
@@ -111,6 +112,9 @@
   if (auto* s = ty->As<sem::Reference>()) {
     return CreateASTTypeFor(ctx, s->StoreType());
   }
+  if (auto* a = ty->As<sem::Atomic>()) {
+    return ctx->dst->create<ast::Atomic>(CreateASTTypeFor(ctx, a->Type()));
+  }
   if (auto* t = ty->As<sem::DepthTexture>()) {
     return ctx->dst->create<ast::DepthTexture>(t->dim());
   }
diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc
index 82f5de2..b637a1f 100644
--- a/src/writer/hlsl/generator_impl.cc
+++ b/src/writer/hlsl/generator_impl.cc
@@ -25,6 +25,7 @@
 #include "src/ast/override_decoration.h"
 #include "src/ast/variable_decl_statement.h"
 #include "src/sem/array.h"
+#include "src/sem/atomic_type.h"
 #include "src/sem/call.h"
 #include "src/sem/depth_texture_type.h"
 #include "src/sem/function.h"
@@ -35,7 +36,6 @@
 #include "src/sem/struct.h"
 #include "src/sem/variable.h"
 #include "src/transform/calculate_array_length.h"
-#include "src/transform/decompose_storage_access.h"
 #include "src/utils/scoped_assignment.h"
 #include "src/writer/append_vector.h"
 #include "src/writer/float_to_string.h"
@@ -431,99 +431,7 @@
     if (auto* intrinsic =
             ast::GetDecoration<transform::DecomposeStorageAccess::Intrinsic>(
                 func->Declaration()->decorations())) {
-      auto load = [&](const char* cast, int n) {
-        if (cast) {
-          out << cast << "(";
-        }
-        if (!EmitExpression(pre, out, params[0])) {  // buffer
-          return false;
-        }
-        out << ".Load";
-        if (n > 1) {
-          out << n;
-        }
-        ScopedParen sp(out);
-        if (!EmitExpression(pre, out, params[1])) {  // offset
-          return false;
-        }
-        if (cast) {
-          out << ")";
-        }
-        return true;
-      };
-      auto store = [&](int n) {
-        if (!EmitExpression(pre, out, params[0])) {  // buffer
-          return false;
-        }
-        out << ".Store";
-        if (n > 1) {
-          out << n;
-        }
-        ScopedParen sp1(out);
-        if (!EmitExpression(pre, out, params[1])) {  // offset
-          return false;
-        }
-        out << ", asuint";
-        ScopedParen sp2(out);
-        if (!EmitExpression(pre, out, params[2])) {  // value
-          return false;
-        }
-        return true;
-      };
-
-      switch (intrinsic->type) {
-        case transform::DecomposeStorageAccess::Intrinsic::kLoadU32:
-          return load(nullptr, 1);
-        case transform::DecomposeStorageAccess::Intrinsic::kLoadF32:
-          return load("asfloat", 1);
-        case transform::DecomposeStorageAccess::Intrinsic::kLoadI32:
-          return load("asint", 1);
-        case transform::DecomposeStorageAccess::Intrinsic::kLoadVec2U32:
-          return load(nullptr, 2);
-        case transform::DecomposeStorageAccess::Intrinsic::kLoadVec2F32:
-          return load("asfloat", 2);
-        case transform::DecomposeStorageAccess::Intrinsic::kLoadVec2I32:
-          return load("asint", 2);
-        case transform::DecomposeStorageAccess::Intrinsic::kLoadVec3U32:
-          return load(nullptr, 3);
-        case transform::DecomposeStorageAccess::Intrinsic::kLoadVec3F32:
-          return load("asfloat", 3);
-        case transform::DecomposeStorageAccess::Intrinsic::kLoadVec3I32:
-          return load("asint", 3);
-        case transform::DecomposeStorageAccess::Intrinsic::kLoadVec4U32:
-          return load(nullptr, 4);
-        case transform::DecomposeStorageAccess::Intrinsic::kLoadVec4F32:
-          return load("asfloat", 4);
-        case transform::DecomposeStorageAccess::Intrinsic::kLoadVec4I32:
-          return load("asint", 4);
-        case transform::DecomposeStorageAccess::Intrinsic::kStoreU32:
-          return store(1);
-        case transform::DecomposeStorageAccess::Intrinsic::kStoreF32:
-          return store(1);
-        case transform::DecomposeStorageAccess::Intrinsic::kStoreI32:
-          return store(1);
-        case transform::DecomposeStorageAccess::Intrinsic::kStoreVec2U32:
-          return store(2);
-        case transform::DecomposeStorageAccess::Intrinsic::kStoreVec2F32:
-          return store(2);
-        case transform::DecomposeStorageAccess::Intrinsic::kStoreVec2I32:
-          return store(2);
-        case transform::DecomposeStorageAccess::Intrinsic::kStoreVec3U32:
-          return store(3);
-        case transform::DecomposeStorageAccess::Intrinsic::kStoreVec3F32:
-          return store(3);
-        case transform::DecomposeStorageAccess::Intrinsic::kStoreVec3I32:
-          return store(3);
-        case transform::DecomposeStorageAccess::Intrinsic::kStoreVec4U32:
-          return store(4);
-        case transform::DecomposeStorageAccess::Intrinsic::kStoreVec4F32:
-          return store(4);
-        case transform::DecomposeStorageAccess::Intrinsic::kStoreVec4I32:
-          return store(4);
-      }
-
-      TINT_UNIMPLEMENTED(diagnostics_) << static_cast<int>(intrinsic->type);
-      return false;
+      return EmitDecomposeStorageAccessIntrinsic(pre, out, expr, intrinsic);
     }
   }
 
@@ -544,6 +452,8 @@
       return EmitDataUnpackingCall(pre, out, expr, intrinsic);
     } else if (intrinsic->IsBarrier()) {
       return EmitBarrierCall(pre, out, intrinsic);
+    } else if (intrinsic->IsAtomic()) {
+      return EmitWorkgroupAtomicCall(pre, out, expr, intrinsic);
     }
     auto name = generate_builtin_name(intrinsic);
     if (name.empty()) {
@@ -597,6 +507,486 @@
   return true;
 }
 
+bool GeneratorImpl::EmitDecomposeStorageAccessIntrinsic(
+    std::ostream& pre,
+    std::ostream& out,
+    ast::CallExpression* expr,
+    const transform::DecomposeStorageAccess::Intrinsic* intrinsic) {
+  const auto& params = expr->params();
+
+  using Op = transform::DecomposeStorageAccess::Intrinsic::Op;
+  using DataType = transform::DecomposeStorageAccess::Intrinsic::DataType;
+  switch (intrinsic->op) {
+    case Op::kLoad: {
+      auto load = [&](const char* cast, int n) {
+        if (cast) {
+          out << cast << "(";
+        }
+        if (!EmitExpression(pre, out, params[0])) {  // buffer
+          return false;
+        }
+        out << ".Load";
+        if (n > 1) {
+          out << n;
+        }
+        ScopedParen sp(out);
+        if (!EmitExpression(pre, out, params[1])) {  // offset
+          return false;
+        }
+        if (cast) {
+          out << ")";
+        }
+        return true;
+      };
+      switch (intrinsic->type) {
+        case DataType::kU32:
+          return load(nullptr, 1);
+        case DataType::kF32:
+          return load("asfloat", 1);
+        case DataType::kI32:
+          return load("asint", 1);
+        case DataType::kVec2U32:
+          return load(nullptr, 2);
+        case DataType::kVec2F32:
+          return load("asfloat", 2);
+        case DataType::kVec2I32:
+          return load("asint", 2);
+        case DataType::kVec3U32:
+          return load(nullptr, 3);
+        case DataType::kVec3F32:
+          return load("asfloat", 3);
+        case DataType::kVec3I32:
+          return load("asint", 3);
+        case DataType::kVec4U32:
+          return load(nullptr, 4);
+        case DataType::kVec4F32:
+          return load("asfloat", 4);
+        case DataType::kVec4I32:
+          return load("asint", 4);
+      }
+      TINT_UNREACHABLE(diagnostics_)
+          << "unsupported DecomposeStorageAccess::Intrinsic::DataType: "
+          << static_cast<int>(intrinsic->type);
+      return false;
+    }
+
+    case Op::kStore: {
+      auto store = [&](int n) {
+        if (!EmitExpression(pre, out, params[0])) {  // buffer
+          return false;
+        }
+        out << ".Store";
+        if (n > 1) {
+          out << n;
+        }
+        ScopedParen sp1(out);
+        if (!EmitExpression(pre, out, params[1])) {  // offset
+          return false;
+        }
+        out << ", asuint";
+        ScopedParen sp2(out);
+        if (!EmitExpression(pre, out, params[2])) {  // value
+          return false;
+        }
+        return true;
+      };
+      switch (intrinsic->type) {
+        case DataType::kU32:
+          return store(1);
+        case DataType::kF32:
+          return store(1);
+        case DataType::kI32:
+          return store(1);
+        case DataType::kVec2U32:
+          return store(2);
+        case DataType::kVec2F32:
+          return store(2);
+        case DataType::kVec2I32:
+          return store(2);
+        case DataType::kVec3U32:
+          return store(3);
+        case DataType::kVec3F32:
+          return store(3);
+        case DataType::kVec3I32:
+          return store(3);
+        case DataType::kVec4U32:
+          return store(4);
+        case DataType::kVec4F32:
+          return store(4);
+        case DataType::kVec4I32:
+          return store(4);
+      }
+      TINT_UNREACHABLE(diagnostics_)
+          << "unsupported DecomposeStorageAccess::Intrinsic::DataType: "
+          << static_cast<int>(intrinsic->type);
+      return false;
+    }
+
+    case Op::kAtomicLoad:
+    case Op::kAtomicStore:
+    case Op::kAtomicAdd:
+    case Op::kAtomicMax:
+    case Op::kAtomicMin:
+    case Op::kAtomicAnd:
+    case Op::kAtomicOr:
+    case Op::kAtomicXor:
+    case Op::kAtomicExchange:
+    case Op::kAtomicCompareExchangeWeak:
+      return EmitStorageAtomicCall(pre, out, expr, intrinsic->op);
+  }
+
+  TINT_UNREACHABLE(diagnostics_)
+      << "unsupported DecomposeStorageAccess::Intrinsic::Op: "
+      << static_cast<int>(intrinsic->op);
+  return false;
+}
+
+bool GeneratorImpl::EmitStorageAtomicCall(
+    std::ostream& pre,
+    std::ostream& out,
+    ast::CallExpression* expr,
+    transform::DecomposeStorageAccess::Intrinsic::Op op) {
+  using Op = transform::DecomposeStorageAccess::Intrinsic::Op;
+
+  std::stringstream ss;
+  std::string result = generate_name("atomic_result");
+
+  auto* result_ty = TypeOf(expr);
+  if (!result_ty->Is<sem::Void>()) {
+    if (!EmitType(ss, TypeOf(expr), ast::StorageClass::kNone,
+                  ast::Access::kUndefined, "")) {
+      return false;
+    }
+    ss << " " << result << " = ";
+    if (!EmitZeroValue(ss, result_ty)) {
+      return false;
+    }
+    make_indent(ss << ";" << std::endl);
+  }
+
+  auto* buffer = expr->params()[0];
+  auto* offset = expr->params()[1];
+
+  switch (op) {
+    case Op::kAtomicLoad: {
+      // HLSL does not have an InterlockedLoad, so we emulate it with
+      // InterlockedOr using 0 as the OR value
+      if (!EmitExpression(pre, ss, buffer)) {
+        return false;
+      }
+      ss << ".InterlockedOr";
+      {
+        ScopedParen sp(ss);
+        if (!EmitExpression(pre, ss, offset)) {
+          return false;
+        }
+        ss << ", 0, " << result;
+      }
+
+      make_indent(ss << ";" << std::endl);
+      pre << ss.str();
+      out << result;
+      return true;
+    }
+    case Op::kAtomicStore: {
+      // HLSL does not have an InterlockedStore, so we emulate it with
+      // InterlockedExchange and discard the returned value
+      auto* value = expr->params()[2];
+      auto* value_ty = TypeOf(value);
+      if (!EmitType(pre, value_ty, ast::StorageClass::kNone,
+                    ast::Access::kUndefined, "")) {
+        return false;
+      }
+      pre << " " << result << " = ";
+      if (!EmitZeroValue(pre, value_ty)) {
+        return false;
+      }
+      make_indent(pre << ";" << std::endl);
+
+      if (!EmitExpression(pre, out, buffer)) {
+        return false;
+      }
+      out << ".InterlockedExchange";
+      {
+        ScopedParen sp(out);
+        if (!EmitExpression(pre, out, offset)) {
+          return false;
+        }
+        out << ", ";
+        if (!EmitExpression(pre, out, value)) {
+          return false;
+        }
+        out << ", " << result;
+      }
+      return true;
+    }
+    case Op::kAtomicCompareExchangeWeak: {
+      auto* compare_value = expr->params()[2];
+      auto* value = expr->params()[3];
+
+      std::string compare = generate_name("atomic_compare_value");
+      if (!EmitType(ss, TypeOf(compare_value), ast::StorageClass::kNone,
+                    ast::Access::kUndefined, "")) {
+        return false;
+      }
+      ss << " " << compare << " = ";
+      if (!EmitExpression(pre, ss, compare_value)) {
+        return false;
+      }
+      make_indent(ss << ";" << std::endl);
+
+      if (!EmitExpression(pre, ss, buffer)) {
+        return false;
+      }
+      ss << ".InterlockedCompareExchange";
+      {
+        ScopedParen sp(ss);
+        if (!EmitExpression(pre, ss, offset)) {
+          return false;
+        }
+        ss << ", " << compare << ", ";
+        if (!EmitExpression(pre, ss, value)) {
+          return false;
+        }
+        ss << ", " << result << ".x";
+      }
+      make_indent(ss << ";" << std::endl);
+
+      ss << result << ".y = " << result << ".x == " << compare;
+      make_indent(ss << ";" << std::endl);
+
+      pre << ss.str();
+      out << result;
+      return true;
+    }
+
+    case Op::kAtomicAdd:
+      if (!EmitExpression(pre, ss, buffer)) {
+        return false;
+      }
+      ss << ".InterlockedAdd";
+      break;
+    case Op::kAtomicMax:
+      if (!EmitExpression(pre, ss, buffer)) {
+        return false;
+      }
+      ss << ".InterlockedMax";
+      break;
+    case Op::kAtomicMin:
+      if (!EmitExpression(pre, ss, buffer)) {
+        return false;
+      }
+      ss << ".InterlockedMin";
+      break;
+    case Op::kAtomicAnd:
+      if (!EmitExpression(pre, ss, buffer)) {
+        return false;
+      }
+      ss << ".InterlockedAnd";
+      break;
+    case Op::kAtomicOr:
+      if (!EmitExpression(pre, ss, buffer)) {
+        return false;
+      }
+      ss << ".InterlockedOr";
+      break;
+    case Op::kAtomicXor:
+      if (!EmitExpression(pre, ss, buffer)) {
+        return false;
+      }
+      ss << ".InterlockedXor";
+      break;
+    case Op::kAtomicExchange:
+      if (!EmitExpression(pre, ss, buffer)) {
+        return false;
+      }
+      ss << ".InterlockedExchange";
+      break;
+
+    default:
+      TINT_UNREACHABLE(diagnostics_)
+          << "unsupported atomic DecomposeStorageAccess::Intrinsic::Op: "
+          << static_cast<int>(op);
+      return false;
+  }
+
+  {
+    ScopedParen sp(ss);
+    if (!EmitExpression(pre, ss, offset)) {
+      return false;
+    }
+
+    for (size_t i = 1; i < expr->params().size() - 1; i++) {
+      auto* arg = expr->params()[i];
+      ss << ", ";
+      if (!EmitExpression(pre, ss, arg)) {
+        return false;
+      }
+    }
+
+    ss << ", " << result;
+  }
+
+  make_indent(ss << ";" << std::endl);
+  pre << ss.str();
+  out << result;
+
+  return true;
+}
+
+bool GeneratorImpl::EmitWorkgroupAtomicCall(std::ostream& pre,
+                                            std::ostream& out,
+                                            ast::CallExpression* expr,
+                                            const sem::Intrinsic* intrinsic) {
+  std::stringstream ss;
+  std::string result = generate_name("atomic_result");
+
+  if (!intrinsic->ReturnType()->Is<sem::Void>()) {
+    if (!EmitType(ss, intrinsic->ReturnType(), ast::StorageClass::kNone,
+                  ast::Access::kUndefined, "")) {
+      return false;
+    }
+    ss << " " << result << " = ";
+    if (!EmitZeroValue(ss, intrinsic->ReturnType())) {
+      return false;
+    }
+    make_indent(ss << ";" << std::endl);
+  }
+
+  switch (intrinsic->Type()) {
+    case sem::IntrinsicType::kAtomicLoad: {
+      // HLSL does not have an InterlockedLoad, so we emulate it with
+      // InterlockedOr using 0 as the OR value
+      ss << "InterlockedOr";
+      {
+        ScopedParen sp(ss);
+        if (!EmitExpression(pre, ss, expr->params()[0])) {
+          return false;
+        }
+        ss << ", 0, " << result;
+      }
+      make_indent(ss << ";" << std::endl);
+
+      pre << ss.str();
+      out << result;
+      return true;
+    }
+    case sem::IntrinsicType::kAtomicStore: {
+      // HLSL does not have an InterlockedStore, so we emulate it with
+      // InterlockedExchange and discard the returned value
+      auto* value_ty = intrinsic->Parameters()[1].type;
+      if (!EmitType(pre, value_ty, ast::StorageClass::kNone,
+                    ast::Access::kUndefined, "")) {
+        return false;
+      }
+      pre << " " << result << " = ";
+      if (!EmitZeroValue(pre, value_ty)) {
+        return false;
+      }
+      make_indent(pre << ";" << std::endl);
+
+      out << "InterlockedExchange";
+      {
+        ScopedParen sp(out);
+        if (!EmitExpression(pre, out, expr->params()[0])) {
+          return false;
+        }
+        out << ", ";
+        if (!EmitExpression(pre, out, expr->params()[1])) {
+          return false;
+        }
+        out << ", " << result;
+      }
+      return true;
+    }
+    case sem::IntrinsicType::kAtomicCompareExchangeWeak: {
+      auto* dest = expr->params()[0];
+      auto* compare_value = expr->params()[1];
+      auto* value = expr->params()[2];
+
+      std::string compare = generate_name("atomic_compare_value");
+      if (!EmitType(ss, TypeOf(compare_value), ast::StorageClass::kNone,
+                    ast::Access::kUndefined, "")) {
+        return false;
+      }
+      ss << " " << compare << " = ";
+      if (!EmitExpression(pre, ss, compare_value)) {
+        return false;
+      }
+      make_indent(ss << ";" << std::endl);
+
+      ss << "InterlockedCompareExchange";
+      {
+        ScopedParen sp(ss);
+        if (!EmitExpression(pre, ss, dest)) {
+          return false;
+        }
+        ss << ", " << compare << ", ";
+        if (!EmitExpression(pre, ss, value)) {
+          return false;
+        }
+        ss << ", " << result << ".x";
+      }
+      make_indent(ss << ";" << std::endl);
+
+      ss << result << ".y = " << result << ".x == " << compare;
+      make_indent(ss << ";" << std::endl);
+
+      pre << ss.str();
+      out << result;
+      return true;
+    }
+
+    case sem::IntrinsicType::kAtomicAdd:
+      ss << "InterlockedAdd";
+      break;
+    case sem::IntrinsicType::kAtomicMax:
+      ss << "InterlockedMax";
+      break;
+    case sem::IntrinsicType::kAtomicMin:
+      ss << "InterlockedMin";
+      break;
+    case sem::IntrinsicType::kAtomicAnd:
+      ss << "InterlockedAnd";
+      break;
+    case sem::IntrinsicType::kAtomicOr:
+      ss << "InterlockedOr";
+      break;
+    case sem::IntrinsicType::kAtomicXor:
+      ss << "InterlockedXor";
+      break;
+    case sem::IntrinsicType::kAtomicExchange:
+      ss << "InterlockedExchange";
+      break;
+
+    default:
+      TINT_UNREACHABLE(diagnostics_)
+          << "unsupported atomic intrinsic: " << intrinsic->Type();
+      return false;
+  }
+
+  {
+    ScopedParen sp(ss);
+    for (size_t i = 0; i < expr->params().size(); i++) {
+      auto* arg = expr->params()[i];
+      if (i > 0) {
+        ss << ", ";
+      }
+      if (!EmitExpression(pre, ss, arg)) {
+        return false;
+      }
+    }
+
+    ss << ", " << result;
+  }
+  make_indent(ss << ";" << std::endl);
+
+  pre << ss.str();
+  out << result;
+
+  return true;
+}
+
 bool GeneratorImpl::EmitSelectCall(std::ostream& pre,
                                    std::ostream& out,
                                    ast::CallExpression* expr) {
@@ -1153,11 +1543,10 @@
   }
 
   return true;
-}  // namespace hlsl
+}
 
 std::string GeneratorImpl::generate_builtin_name(
     const sem::Intrinsic* intrinsic) {
-  std::string out;
   switch (intrinsic->Type()) {
     case sem::IntrinsicType::kAbs:
     case sem::IntrinsicType::kAcos:
@@ -1198,71 +1587,51 @@
     case sem::IntrinsicType::kTanh:
     case sem::IntrinsicType::kTranspose:
     case sem::IntrinsicType::kTrunc:
-      out = intrinsic->str();
-      break;
+      return intrinsic->str();
     case sem::IntrinsicType::kCountOneBits:
-      out = "countbits";
-      break;
+      return "countbits";
     case sem::IntrinsicType::kDpdx:
-      out = "ddx";
-      break;
+      return "ddx";
     case sem::IntrinsicType::kDpdxCoarse:
-      out = "ddx_coarse";
-      break;
+      return "ddx_coarse";
     case sem::IntrinsicType::kDpdxFine:
-      out = "ddx_fine";
-      break;
+      return "ddx_fine";
     case sem::IntrinsicType::kDpdy:
-      out = "ddy";
-      break;
+      return "ddy";
     case sem::IntrinsicType::kDpdyCoarse:
-      out = "ddy_coarse";
-      break;
+      return "ddy_coarse";
     case sem::IntrinsicType::kDpdyFine:
-      out = "ddy_fine";
-      break;
+      return "ddy_fine";
     case sem::IntrinsicType::kFaceForward:
-      out = "faceforward";
-      break;
+      return "faceforward";
     case sem::IntrinsicType::kFract:
-      out = "frac";
-      break;
+      return "frac";
     case sem::IntrinsicType::kFma:
-      out = "mad";
-      break;
+      return "mad";
     case sem::IntrinsicType::kFwidth:
     case sem::IntrinsicType::kFwidthCoarse:
     case sem::IntrinsicType::kFwidthFine:
-      out = "fwidth";
-      break;
+      return "fwidth";
     case sem::IntrinsicType::kInverseSqrt:
-      out = "rsqrt";
-      break;
+      return "rsqrt";
     case sem::IntrinsicType::kIsFinite:
-      out = "isfinite";
-      break;
+      return "isfinite";
     case sem::IntrinsicType::kIsInf:
-      out = "isinf";
-      break;
+      return "isinf";
     case sem::IntrinsicType::kIsNan:
-      out = "isnan";
-      break;
+      return "isnan";
     case sem::IntrinsicType::kMix:
-      out = "lerp";
-      break;
+      return "lerp";
     case sem::IntrinsicType::kReverseBits:
-      out = "reversebits";
-      break;
+      return "reversebits";
     case sem::IntrinsicType::kSmoothStep:
-      out = "smoothstep";
-      break;
+      return "smoothstep";
     default:
       diagnostics_.add_error("Unknown builtin method: " +
                              std::string(intrinsic->str()));
-      return "";
   }
 
-  return out;
+  return "";
 }
 
 bool GeneratorImpl::EmitCase(std::ostream& out, ast::CaseStatement* stmt) {
@@ -2237,6 +2606,10 @@
       }
       out << ", " << size << ">";
     }
+  } else if (auto* atomic = type->As<sem::Atomic>()) {
+    if (!EmitType(out, atomic->Type(), storage_class, access, name)) {
+      return false;
+    }
   } else if (type->Is<sem::Void>()) {
     out << "void";
   } else {
diff --git a/src/writer/hlsl/generator_impl.h b/src/writer/hlsl/generator_impl.h
index d14b8a1..2cb9e02 100644
--- a/src/writer/hlsl/generator_impl.h
+++ b/src/writer/hlsl/generator_impl.h
@@ -32,6 +32,7 @@
 #include "src/ast/unary_op_expression.h"
 #include "src/program_builder.h"
 #include "src/scope_stack.h"
+#include "src/transform/decompose_storage_access.h"
 #include "src/writer/text_generator.h"
 
 namespace tint {
@@ -115,6 +116,18 @@
   bool EmitCall(std::ostream& pre,
                 std::ostream& out,
                 ast::CallExpression* expr);
+  /// Handles generating a call expression to a
+  /// transform::DecomposeStorageAccess::Intrinsic
+  /// @param pre the preamble for the expression stream
+  /// @param out the output of the expression stream
+  /// @param expr the call expression
+  /// @param intrinsic the transform::DecomposeStorageAccess::Intrinsic
+  /// @returns true if the call expression is emitted
+  bool EmitDecomposeStorageAccessIntrinsic(
+      std::ostream& pre,
+      std::ostream& out,
+      ast::CallExpression* expr,
+      const transform::DecomposeStorageAccess::Intrinsic* intrinsic);
   /// Handles generating a barrier intrinsic call
   /// @param pre the preamble for the expression stream
   /// @param out the output of the expression stream
@@ -123,6 +136,27 @@
   bool EmitBarrierCall(std::ostream& pre,
                        std::ostream& out,
                        const sem::Intrinsic* intrinsic);
+  /// Handles generating an atomic intrinsic call for a storage buffer variable
+  /// @param pre the preamble for the expression stream
+  /// @param out the output of the expression stream
+  /// @param expr the call expression
+  /// @param op the atomic op
+  /// @returns true if the call expression is emitted
+  bool EmitStorageAtomicCall(
+      std::ostream& pre,
+      std::ostream& out,
+      ast::CallExpression* expr,
+      transform::DecomposeStorageAccess::Intrinsic::Op op);
+  /// Handles generating an atomic intrinsic call for a workgroup variable
+  /// @param pre the preamble for the expression stream
+  /// @param out the output of the expression stream
+  /// @param expr the call expression
+  /// @param intrinsic the semantic information for the atomic intrinsic
+  /// @returns true if the call expression is emitted
+  bool EmitWorkgroupAtomicCall(std::ostream& pre,
+                               std::ostream& out,
+                               ast::CallExpression* expr,
+                               const sem::Intrinsic* intrinsic);
   /// Handles generating a call to a texture function (`textureSample`,
   /// `textureSampleGrad`, etc)
   /// @param pre the preamble for the expression stream
diff --git a/test/intrinsics/gen/atomicAdd/794055.wgsl.expected.hlsl b/test/intrinsics/gen/atomicAdd/794055.wgsl.expected.hlsl
index 1722f96..58d211c 100644
--- a/test/intrinsics/gen/atomicAdd/794055.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicAdd/794055.wgsl.expected.hlsl
@@ -1,15 +1,13 @@
-SKIP: FAILED
+groupshared int arg_0;
 
-
-var<workgroup> arg_0 : atomic<i32>;
-
-fn atomicAdd_794055() {
-  var res : i32 = atomicAdd(&(arg_0), 1);
+void atomicAdd_794055() {
+  int atomic_result = 0;
+  InterlockedAdd(arg_0, 1, atomic_result);
+  int res = atomic_result;
 }
 
-[[stage(compute)]]
-fn compute_main() {
+[numthreads(1, 1, 1)]
+void compute_main() {
   atomicAdd_794055();
+  return;
 }
-
-Failed to generate: error: unknown type in EmitType
diff --git a/test/intrinsics/gen/atomicAdd/794055.wgsl.expected.msl b/test/intrinsics/gen/atomicAdd/794055.wgsl.expected.msl
index 664bfff..9cf781e 100644
--- a/test/intrinsics/gen/atomicAdd/794055.wgsl.expected.msl
+++ b/test/intrinsics/gen/atomicAdd/794055.wgsl.expected.msl
@@ -1,10 +1,14 @@
 SKIP: FAILED
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
 
+fn atomicAdd_794055(tint_symbol : ptr<workgroup, atomic<i32>>) {
+  var res : i32 = atomicAdd(&(*(tint_symbol)), 1);
+}
+
+[[stage(compute)]]
+fn compute_main() {
+  [[internal(disable_validation__function_var_storage_class)]] var<workgroup> tint_symbol_1 : atomic<i32>;
+  atomicAdd_794055(&(tint_symbol_1));
+}
+
+error: cannot declare an atomic var in a function scope
diff --git a/test/intrinsics/gen/atomicAdd/8a199a.wgsl.expected.hlsl b/test/intrinsics/gen/atomicAdd/8a199a.wgsl.expected.hlsl
index 664bfff..b13b466 100644
--- a/test/intrinsics/gen/atomicAdd/8a199a.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicAdd/8a199a.wgsl.expected.hlsl
@@ -1,10 +1,18 @@
-SKIP: FAILED
+RWByteAddressBuffer sb_rw : register(u0, space0);
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+void atomicAdd_8a199a() {
+  uint atomic_result = 0u;
+  sb_rw.InterlockedAdd(0u, 0u, atomic_result);
+  uint res = atomic_result;
+}
 
+void fragment_main() {
+  atomicAdd_8a199a();
+  return;
+}
+
+[numthreads(1, 1, 1)]
+void compute_main() {
+  atomicAdd_8a199a();
+  return;
+}
diff --git a/test/intrinsics/gen/atomicAdd/d32fe4.wgsl.expected.hlsl b/test/intrinsics/gen/atomicAdd/d32fe4.wgsl.expected.hlsl
index 664bfff..a578c6e 100644
--- a/test/intrinsics/gen/atomicAdd/d32fe4.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicAdd/d32fe4.wgsl.expected.hlsl
@@ -1,10 +1,18 @@
-SKIP: FAILED
+RWByteAddressBuffer sb_rw : register(u0, space0);
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+void atomicAdd_d32fe4() {
+  int atomic_result = 0;
+  sb_rw.InterlockedAdd(0u, 0u, atomic_result);
+  int res = atomic_result;
+}
 
+void fragment_main() {
+  atomicAdd_d32fe4();
+  return;
+}
+
+[numthreads(1, 1, 1)]
+void compute_main() {
+  atomicAdd_d32fe4();
+  return;
+}
diff --git a/test/intrinsics/gen/atomicAdd/d5db1d.wgsl.expected.hlsl b/test/intrinsics/gen/atomicAdd/d5db1d.wgsl.expected.hlsl
index 388aa97..b14673c 100644
--- a/test/intrinsics/gen/atomicAdd/d5db1d.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicAdd/d5db1d.wgsl.expected.hlsl
@@ -1,15 +1,13 @@
-SKIP: FAILED
+groupshared uint arg_0;
 
-
-var<workgroup> arg_0 : atomic<u32>;
-
-fn atomicAdd_d5db1d() {
-  var res : u32 = atomicAdd(&(arg_0), 1u);
+void atomicAdd_d5db1d() {
+  uint atomic_result = 0u;
+  InterlockedAdd(arg_0, 1u, atomic_result);
+  uint res = atomic_result;
 }
 
-[[stage(compute)]]
-fn compute_main() {
+[numthreads(1, 1, 1)]
+void compute_main() {
   atomicAdd_d5db1d();
+  return;
 }
-
-Failed to generate: error: unknown type in EmitType
diff --git a/test/intrinsics/gen/atomicAdd/d5db1d.wgsl.expected.msl b/test/intrinsics/gen/atomicAdd/d5db1d.wgsl.expected.msl
index 664bfff..3e13cfd 100644
--- a/test/intrinsics/gen/atomicAdd/d5db1d.wgsl.expected.msl
+++ b/test/intrinsics/gen/atomicAdd/d5db1d.wgsl.expected.msl
@@ -1,10 +1,14 @@
 SKIP: FAILED
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
 
+fn atomicAdd_d5db1d(tint_symbol : ptr<workgroup, atomic<u32>>) {
+  var res : u32 = atomicAdd(&(*(tint_symbol)), 1u);
+}
+
+[[stage(compute)]]
+fn compute_main() {
+  [[internal(disable_validation__function_var_storage_class)]] var<workgroup> tint_symbol_1 : atomic<u32>;
+  atomicAdd_d5db1d(&(tint_symbol_1));
+}
+
+error: cannot declare an atomic var in a function scope
diff --git a/test/intrinsics/gen/atomicAnd/152966.wgsl.expected.hlsl b/test/intrinsics/gen/atomicAnd/152966.wgsl.expected.hlsl
index 664bfff..819eaf2 100644
--- a/test/intrinsics/gen/atomicAnd/152966.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicAnd/152966.wgsl.expected.hlsl
@@ -1,10 +1,18 @@
-SKIP: FAILED
+RWByteAddressBuffer sb_rw : register(u0, space0);
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+void atomicAnd_152966() {
+  int atomic_result = 0;
+  sb_rw.InterlockedAnd(0u, 0u, atomic_result);
+  int res = atomic_result;
+}
 
+void fragment_main() {
+  atomicAnd_152966();
+  return;
+}
+
+[numthreads(1, 1, 1)]
+void compute_main() {
+  atomicAnd_152966();
+  return;
+}
diff --git a/test/intrinsics/gen/atomicAnd/34edd3.wgsl.expected.hlsl b/test/intrinsics/gen/atomicAnd/34edd3.wgsl.expected.hlsl
index b51ffc0..c05630a 100644
--- a/test/intrinsics/gen/atomicAnd/34edd3.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicAnd/34edd3.wgsl.expected.hlsl
@@ -1,15 +1,13 @@
-SKIP: FAILED
+groupshared uint arg_0;
 
-
-var<workgroup> arg_0 : atomic<u32>;
-
-fn atomicAnd_34edd3() {
-  var res : u32 = atomicAnd(&(arg_0), 1u);
+void atomicAnd_34edd3() {
+  uint atomic_result = 0u;
+  InterlockedAnd(arg_0, 1u, atomic_result);
+  uint res = atomic_result;
 }
 
-[[stage(compute)]]
-fn compute_main() {
+[numthreads(1, 1, 1)]
+void compute_main() {
   atomicAnd_34edd3();
+  return;
 }
-
-Failed to generate: error: unknown type in EmitType
diff --git a/test/intrinsics/gen/atomicAnd/34edd3.wgsl.expected.msl b/test/intrinsics/gen/atomicAnd/34edd3.wgsl.expected.msl
index 664bfff..6a5bb56 100644
--- a/test/intrinsics/gen/atomicAnd/34edd3.wgsl.expected.msl
+++ b/test/intrinsics/gen/atomicAnd/34edd3.wgsl.expected.msl
@@ -1,10 +1,14 @@
 SKIP: FAILED
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
 
+fn atomicAnd_34edd3(tint_symbol : ptr<workgroup, atomic<u32>>) {
+  var res : u32 = atomicAnd(&(*(tint_symbol)), 1u);
+}
+
+[[stage(compute)]]
+fn compute_main() {
+  [[internal(disable_validation__function_var_storage_class)]] var<workgroup> tint_symbol_1 : atomic<u32>;
+  atomicAnd_34edd3(&(tint_symbol_1));
+}
+
+error: cannot declare an atomic var in a function scope
diff --git a/test/intrinsics/gen/atomicAnd/45a819.wgsl.expected.hlsl b/test/intrinsics/gen/atomicAnd/45a819.wgsl.expected.hlsl
index a393010..76085c8 100644
--- a/test/intrinsics/gen/atomicAnd/45a819.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicAnd/45a819.wgsl.expected.hlsl
@@ -1,15 +1,13 @@
-SKIP: FAILED
+groupshared int arg_0;
 
-
-var<workgroup> arg_0 : atomic<i32>;
-
-fn atomicAnd_45a819() {
-  var res : i32 = atomicAnd(&(arg_0), 1);
+void atomicAnd_45a819() {
+  int atomic_result = 0;
+  InterlockedAnd(arg_0, 1, atomic_result);
+  int res = atomic_result;
 }
 
-[[stage(compute)]]
-fn compute_main() {
+[numthreads(1, 1, 1)]
+void compute_main() {
   atomicAnd_45a819();
+  return;
 }
-
-Failed to generate: error: unknown type in EmitType
diff --git a/test/intrinsics/gen/atomicAnd/45a819.wgsl.expected.msl b/test/intrinsics/gen/atomicAnd/45a819.wgsl.expected.msl
index 664bfff..47755f6 100644
--- a/test/intrinsics/gen/atomicAnd/45a819.wgsl.expected.msl
+++ b/test/intrinsics/gen/atomicAnd/45a819.wgsl.expected.msl
@@ -1,10 +1,14 @@
 SKIP: FAILED
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
 
+fn atomicAnd_45a819(tint_symbol : ptr<workgroup, atomic<i32>>) {
+  var res : i32 = atomicAnd(&(*(tint_symbol)), 1);
+}
+
+[[stage(compute)]]
+fn compute_main() {
+  [[internal(disable_validation__function_var_storage_class)]] var<workgroup> tint_symbol_1 : atomic<i32>;
+  atomicAnd_45a819(&(tint_symbol_1));
+}
+
+error: cannot declare an atomic var in a function scope
diff --git a/test/intrinsics/gen/atomicAnd/85a8d9.wgsl.expected.hlsl b/test/intrinsics/gen/atomicAnd/85a8d9.wgsl.expected.hlsl
index 664bfff..434f98d 100644
--- a/test/intrinsics/gen/atomicAnd/85a8d9.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicAnd/85a8d9.wgsl.expected.hlsl
@@ -1,10 +1,18 @@
-SKIP: FAILED
+RWByteAddressBuffer sb_rw : register(u0, space0);
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+void atomicAnd_85a8d9() {
+  uint atomic_result = 0u;
+  sb_rw.InterlockedAnd(0u, 0u, atomic_result);
+  uint res = atomic_result;
+}
 
+void fragment_main() {
+  atomicAnd_85a8d9();
+  return;
+}
+
+[numthreads(1, 1, 1)]
+void compute_main() {
+  atomicAnd_85a8d9();
+  return;
+}
diff --git a/test/intrinsics/gen/atomicCompareExchangeWeak/12871c.wgsl.expected.hlsl b/test/intrinsics/gen/atomicCompareExchangeWeak/12871c.wgsl.expected.hlsl
index 664bfff..0f540c2 100644
--- a/test/intrinsics/gen/atomicCompareExchangeWeak/12871c.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicCompareExchangeWeak/12871c.wgsl.expected.hlsl
@@ -1,10 +1,20 @@
-SKIP: FAILED
+RWByteAddressBuffer sb_rw : register(u0, space0);
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+void atomicCompareExchangeWeak_12871c() {
+  int2 atomic_result = int2(0, 0);
+  int atomic_compare_value = 1;
+  sb_rw.InterlockedCompareExchange(0u, atomic_compare_value, 1, atomic_result.x);
+  atomic_result.y = atomic_result.x == atomic_compare_value;
+  int2 res = atomic_result;
+}
 
+void fragment_main() {
+  atomicCompareExchangeWeak_12871c();
+  return;
+}
+
+[numthreads(1, 1, 1)]
+void compute_main() {
+  atomicCompareExchangeWeak_12871c();
+  return;
+}
diff --git a/test/intrinsics/gen/atomicCompareExchangeWeak/6673da.wgsl.expected.hlsl b/test/intrinsics/gen/atomicCompareExchangeWeak/6673da.wgsl.expected.hlsl
index 664bfff..0011dec 100644
--- a/test/intrinsics/gen/atomicCompareExchangeWeak/6673da.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicCompareExchangeWeak/6673da.wgsl.expected.hlsl
@@ -1,10 +1,20 @@
-SKIP: FAILED
+RWByteAddressBuffer sb_rw : register(u0, space0);
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+void atomicCompareExchangeWeak_6673da() {
+  uint2 atomic_result = uint2(0u, 0u);
+  uint atomic_compare_value = 1u;
+  sb_rw.InterlockedCompareExchange(0u, atomic_compare_value, 1u, atomic_result.x);
+  atomic_result.y = atomic_result.x == atomic_compare_value;
+  uint2 res = atomic_result;
+}
 
+void fragment_main() {
+  atomicCompareExchangeWeak_6673da();
+  return;
+}
+
+[numthreads(1, 1, 1)]
+void compute_main() {
+  atomicCompareExchangeWeak_6673da();
+  return;
+}
diff --git a/test/intrinsics/gen/atomicCompareExchangeWeak/89ea3b.wgsl.expected.hlsl b/test/intrinsics/gen/atomicCompareExchangeWeak/89ea3b.wgsl.expected.hlsl
index 2b6a58e..fbc219f 100644
--- a/test/intrinsics/gen/atomicCompareExchangeWeak/89ea3b.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicCompareExchangeWeak/89ea3b.wgsl.expected.hlsl
@@ -1,15 +1,15 @@
-SKIP: FAILED
+groupshared int arg_0;
 
-
-var<workgroup> arg_0 : atomic<i32>;
-
-fn atomicCompareExchangeWeak_89ea3b() {
-  var res : vec2<i32> = atomicCompareExchangeWeak(&(arg_0), 1, 1);
+void atomicCompareExchangeWeak_89ea3b() {
+  int2 atomic_result = int2(0, 0);
+  int atomic_compare_value = 1;
+  InterlockedCompareExchange(arg_0, atomic_compare_value, 1, atomic_result.x);
+  atomic_result.y = atomic_result.x == atomic_compare_value;
+  int2 res = atomic_result;
 }
 
-[[stage(compute)]]
-fn compute_main() {
+[numthreads(1, 1, 1)]
+void compute_main() {
   atomicCompareExchangeWeak_89ea3b();
+  return;
 }
-
-Failed to generate: error: unknown type in EmitType
diff --git a/test/intrinsics/gen/atomicCompareExchangeWeak/89ea3b.wgsl.expected.msl b/test/intrinsics/gen/atomicCompareExchangeWeak/89ea3b.wgsl.expected.msl
index 664bfff..c6431fb 100644
--- a/test/intrinsics/gen/atomicCompareExchangeWeak/89ea3b.wgsl.expected.msl
+++ b/test/intrinsics/gen/atomicCompareExchangeWeak/89ea3b.wgsl.expected.msl
@@ -1,10 +1,14 @@
 SKIP: FAILED
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
 
+fn atomicCompareExchangeWeak_89ea3b(tint_symbol : ptr<workgroup, atomic<i32>>) {
+  var res : vec2<i32> = atomicCompareExchangeWeak(&(*(tint_symbol)), 1, 1);
+}
+
+[[stage(compute)]]
+fn compute_main() {
+  [[internal(disable_validation__function_var_storage_class)]] var<workgroup> tint_symbol_1 : atomic<i32>;
+  atomicCompareExchangeWeak_89ea3b(&(tint_symbol_1));
+}
+
+error: cannot declare an atomic var in a function scope
diff --git a/test/intrinsics/gen/atomicCompareExchangeWeak/b2ab2c.wgsl.expected.hlsl b/test/intrinsics/gen/atomicCompareExchangeWeak/b2ab2c.wgsl.expected.hlsl
index 8d82315..6342525 100644
--- a/test/intrinsics/gen/atomicCompareExchangeWeak/b2ab2c.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicCompareExchangeWeak/b2ab2c.wgsl.expected.hlsl
@@ -1,15 +1,15 @@
-SKIP: FAILED
+groupshared uint arg_0;
 
-
-var<workgroup> arg_0 : atomic<u32>;
-
-fn atomicCompareExchangeWeak_b2ab2c() {
-  var res : vec2<u32> = atomicCompareExchangeWeak(&(arg_0), 1u, 1u);
+void atomicCompareExchangeWeak_b2ab2c() {
+  uint2 atomic_result = uint2(0u, 0u);
+  uint atomic_compare_value = 1u;
+  InterlockedCompareExchange(arg_0, atomic_compare_value, 1u, atomic_result.x);
+  atomic_result.y = atomic_result.x == atomic_compare_value;
+  uint2 res = atomic_result;
 }
 
-[[stage(compute)]]
-fn compute_main() {
+[numthreads(1, 1, 1)]
+void compute_main() {
   atomicCompareExchangeWeak_b2ab2c();
+  return;
 }
-
-Failed to generate: error: unknown type in EmitType
diff --git a/test/intrinsics/gen/atomicCompareExchangeWeak/b2ab2c.wgsl.expected.msl b/test/intrinsics/gen/atomicCompareExchangeWeak/b2ab2c.wgsl.expected.msl
index 664bfff..1b632df 100644
--- a/test/intrinsics/gen/atomicCompareExchangeWeak/b2ab2c.wgsl.expected.msl
+++ b/test/intrinsics/gen/atomicCompareExchangeWeak/b2ab2c.wgsl.expected.msl
@@ -1,10 +1,14 @@
 SKIP: FAILED
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
 
+fn atomicCompareExchangeWeak_b2ab2c(tint_symbol : ptr<workgroup, atomic<u32>>) {
+  var res : vec2<u32> = atomicCompareExchangeWeak(&(*(tint_symbol)), 1u, 1u);
+}
+
+[[stage(compute)]]
+fn compute_main() {
+  [[internal(disable_validation__function_var_storage_class)]] var<workgroup> tint_symbol_1 : atomic<u32>;
+  atomicCompareExchangeWeak_b2ab2c(&(tint_symbol_1));
+}
+
+error: cannot declare an atomic var in a function scope
diff --git a/test/intrinsics/gen/atomicExchange/0a5dca.wgsl.expected.hlsl b/test/intrinsics/gen/atomicExchange/0a5dca.wgsl.expected.hlsl
index 8fd62b5..7878fe1 100644
--- a/test/intrinsics/gen/atomicExchange/0a5dca.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicExchange/0a5dca.wgsl.expected.hlsl
@@ -1,15 +1,13 @@
-SKIP: FAILED
+groupshared uint arg_0;
 
-
-var<workgroup> arg_0 : atomic<u32>;
-
-fn atomicExchange_0a5dca() {
-  var res : u32 = atomicExchange(&(arg_0), 1u);
+void atomicExchange_0a5dca() {
+  uint atomic_result = 0u;
+  InterlockedExchange(arg_0, 1u, atomic_result);
+  uint res = atomic_result;
 }
 
-[[stage(compute)]]
-fn compute_main() {
+[numthreads(1, 1, 1)]
+void compute_main() {
   atomicExchange_0a5dca();
+  return;
 }
-
-Failed to generate: error: unknown type in EmitType
diff --git a/test/intrinsics/gen/atomicExchange/0a5dca.wgsl.expected.msl b/test/intrinsics/gen/atomicExchange/0a5dca.wgsl.expected.msl
index 664bfff..070beca 100644
--- a/test/intrinsics/gen/atomicExchange/0a5dca.wgsl.expected.msl
+++ b/test/intrinsics/gen/atomicExchange/0a5dca.wgsl.expected.msl
@@ -1,10 +1,14 @@
 SKIP: FAILED
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
 
+fn atomicExchange_0a5dca(tint_symbol : ptr<workgroup, atomic<u32>>) {
+  var res : u32 = atomicExchange(&(*(tint_symbol)), 1u);
+}
+
+[[stage(compute)]]
+fn compute_main() {
+  [[internal(disable_validation__function_var_storage_class)]] var<workgroup> tint_symbol_1 : atomic<u32>;
+  atomicExchange_0a5dca(&(tint_symbol_1));
+}
+
+error: cannot declare an atomic var in a function scope
diff --git a/test/intrinsics/gen/atomicExchange/d59712.wgsl.expected.hlsl b/test/intrinsics/gen/atomicExchange/d59712.wgsl.expected.hlsl
index 664bfff..736c4f5 100644
--- a/test/intrinsics/gen/atomicExchange/d59712.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicExchange/d59712.wgsl.expected.hlsl
@@ -1,10 +1,18 @@
-SKIP: FAILED
+RWByteAddressBuffer sb_rw : register(u0, space0);
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+void atomicExchange_d59712() {
+  uint atomic_result = 0u;
+  sb_rw.InterlockedExchange(0u, 0u, atomic_result);
+  uint res = atomic_result;
+}
 
+void fragment_main() {
+  atomicExchange_d59712();
+  return;
+}
+
+[numthreads(1, 1, 1)]
+void compute_main() {
+  atomicExchange_d59712();
+  return;
+}
diff --git a/test/intrinsics/gen/atomicExchange/e114ba.wgsl.expected.hlsl b/test/intrinsics/gen/atomicExchange/e114ba.wgsl.expected.hlsl
index 4b1ab2c..289f8b9 100644
--- a/test/intrinsics/gen/atomicExchange/e114ba.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicExchange/e114ba.wgsl.expected.hlsl
@@ -1,15 +1,13 @@
-SKIP: FAILED
+groupshared int arg_0;
 
-
-var<workgroup> arg_0 : atomic<i32>;
-
-fn atomicExchange_e114ba() {
-  var res : i32 = atomicExchange(&(arg_0), 1);
+void atomicExchange_e114ba() {
+  int atomic_result = 0;
+  InterlockedExchange(arg_0, 1, atomic_result);
+  int res = atomic_result;
 }
 
-[[stage(compute)]]
-fn compute_main() {
+[numthreads(1, 1, 1)]
+void compute_main() {
   atomicExchange_e114ba();
+  return;
 }
-
-Failed to generate: error: unknown type in EmitType
diff --git a/test/intrinsics/gen/atomicExchange/e114ba.wgsl.expected.msl b/test/intrinsics/gen/atomicExchange/e114ba.wgsl.expected.msl
index 664bfff..9e1b24d 100644
--- a/test/intrinsics/gen/atomicExchange/e114ba.wgsl.expected.msl
+++ b/test/intrinsics/gen/atomicExchange/e114ba.wgsl.expected.msl
@@ -1,10 +1,14 @@
 SKIP: FAILED
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
 
+fn atomicExchange_e114ba(tint_symbol : ptr<workgroup, atomic<i32>>) {
+  var res : i32 = atomicExchange(&(*(tint_symbol)), 1);
+}
+
+[[stage(compute)]]
+fn compute_main() {
+  [[internal(disable_validation__function_var_storage_class)]] var<workgroup> tint_symbol_1 : atomic<i32>;
+  atomicExchange_e114ba(&(tint_symbol_1));
+}
+
+error: cannot declare an atomic var in a function scope
diff --git a/test/intrinsics/gen/atomicExchange/f2e22f.wgsl.expected.hlsl b/test/intrinsics/gen/atomicExchange/f2e22f.wgsl.expected.hlsl
index 664bfff..ce77930 100644
--- a/test/intrinsics/gen/atomicExchange/f2e22f.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicExchange/f2e22f.wgsl.expected.hlsl
@@ -1,10 +1,18 @@
-SKIP: FAILED
+RWByteAddressBuffer sb_rw : register(u0, space0);
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+void atomicExchange_f2e22f() {
+  int atomic_result = 0;
+  sb_rw.InterlockedExchange(0u, 0u, atomic_result);
+  int res = atomic_result;
+}
 
+void fragment_main() {
+  atomicExchange_f2e22f();
+  return;
+}
+
+[numthreads(1, 1, 1)]
+void compute_main() {
+  atomicExchange_f2e22f();
+  return;
+}
diff --git a/test/intrinsics/gen/atomicLoad/0806ad.wgsl.expected.hlsl b/test/intrinsics/gen/atomicLoad/0806ad.wgsl.expected.hlsl
index 664bfff..a573e45 100644
--- a/test/intrinsics/gen/atomicLoad/0806ad.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicLoad/0806ad.wgsl.expected.hlsl
@@ -1,10 +1,18 @@
-SKIP: FAILED
+RWByteAddressBuffer sb_rw : register(u0, space0);
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+void atomicLoad_0806ad() {
+  int atomic_result = 0;
+  sb_rw.InterlockedOr(0u, 0, atomic_result);
+  int res = atomic_result;
+}
 
+void fragment_main() {
+  atomicLoad_0806ad();
+  return;
+}
+
+[numthreads(1, 1, 1)]
+void compute_main() {
+  atomicLoad_0806ad();
+  return;
+}
diff --git a/test/intrinsics/gen/atomicLoad/361bf1.wgsl.expected.hlsl b/test/intrinsics/gen/atomicLoad/361bf1.wgsl.expected.hlsl
index eb5a482..08e1446 100644
--- a/test/intrinsics/gen/atomicLoad/361bf1.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicLoad/361bf1.wgsl.expected.hlsl
@@ -1,15 +1,13 @@
-SKIP: FAILED
+groupshared uint arg_0;
 
-
-var<workgroup> arg_0 : atomic<u32>;
-
-fn atomicLoad_361bf1() {
-  var res : u32 = atomicLoad(&(arg_0));
+void atomicLoad_361bf1() {
+  uint atomic_result = 0u;
+  InterlockedOr(arg_0, 0, atomic_result);
+  uint res = atomic_result;
 }
 
-[[stage(compute)]]
-fn compute_main() {
+[numthreads(1, 1, 1)]
+void compute_main() {
   atomicLoad_361bf1();
+  return;
 }
-
-Failed to generate: error: unknown type in EmitType
diff --git a/test/intrinsics/gen/atomicLoad/361bf1.wgsl.expected.msl b/test/intrinsics/gen/atomicLoad/361bf1.wgsl.expected.msl
index 664bfff..7d5661a 100644
--- a/test/intrinsics/gen/atomicLoad/361bf1.wgsl.expected.msl
+++ b/test/intrinsics/gen/atomicLoad/361bf1.wgsl.expected.msl
@@ -1,10 +1,14 @@
 SKIP: FAILED
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
 
+fn atomicLoad_361bf1(tint_symbol : ptr<workgroup, atomic<u32>>) {
+  var res : u32 = atomicLoad(&(*(tint_symbol)));
+}
+
+[[stage(compute)]]
+fn compute_main() {
+  [[internal(disable_validation__function_var_storage_class)]] var<workgroup> tint_symbol_1 : atomic<u32>;
+  atomicLoad_361bf1(&(tint_symbol_1));
+}
+
+error: cannot declare an atomic var in a function scope
diff --git a/test/intrinsics/gen/atomicLoad/afcc03.wgsl.expected.hlsl b/test/intrinsics/gen/atomicLoad/afcc03.wgsl.expected.hlsl
index c43459a..bc4f09c 100644
--- a/test/intrinsics/gen/atomicLoad/afcc03.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicLoad/afcc03.wgsl.expected.hlsl
@@ -1,15 +1,13 @@
-SKIP: FAILED
+groupshared int arg_0;
 
-
-var<workgroup> arg_0 : atomic<i32>;
-
-fn atomicLoad_afcc03() {
-  var res : i32 = atomicLoad(&(arg_0));
+void atomicLoad_afcc03() {
+  int atomic_result = 0;
+  InterlockedOr(arg_0, 0, atomic_result);
+  int res = atomic_result;
 }
 
-[[stage(compute)]]
-fn compute_main() {
+[numthreads(1, 1, 1)]
+void compute_main() {
   atomicLoad_afcc03();
+  return;
 }
-
-Failed to generate: error: unknown type in EmitType
diff --git a/test/intrinsics/gen/atomicLoad/afcc03.wgsl.expected.msl b/test/intrinsics/gen/atomicLoad/afcc03.wgsl.expected.msl
index 664bfff..6304ed0 100644
--- a/test/intrinsics/gen/atomicLoad/afcc03.wgsl.expected.msl
+++ b/test/intrinsics/gen/atomicLoad/afcc03.wgsl.expected.msl
@@ -1,10 +1,14 @@
 SKIP: FAILED
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
 
+fn atomicLoad_afcc03(tint_symbol : ptr<workgroup, atomic<i32>>) {
+  var res : i32 = atomicLoad(&(*(tint_symbol)));
+}
+
+[[stage(compute)]]
+fn compute_main() {
+  [[internal(disable_validation__function_var_storage_class)]] var<workgroup> tint_symbol_1 : atomic<i32>;
+  atomicLoad_afcc03(&(tint_symbol_1));
+}
+
+error: cannot declare an atomic var in a function scope
diff --git a/test/intrinsics/gen/atomicLoad/fe6cc3.wgsl.expected.hlsl b/test/intrinsics/gen/atomicLoad/fe6cc3.wgsl.expected.hlsl
index 664bfff..86a939e 100644
--- a/test/intrinsics/gen/atomicLoad/fe6cc3.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicLoad/fe6cc3.wgsl.expected.hlsl
@@ -1,10 +1,18 @@
-SKIP: FAILED
+RWByteAddressBuffer sb_rw : register(u0, space0);
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+void atomicLoad_fe6cc3() {
+  uint atomic_result = 0u;
+  sb_rw.InterlockedOr(0u, 0, atomic_result);
+  uint res = atomic_result;
+}
 
+void fragment_main() {
+  atomicLoad_fe6cc3();
+  return;
+}
+
+[numthreads(1, 1, 1)]
+void compute_main() {
+  atomicLoad_fe6cc3();
+  return;
+}
diff --git a/test/intrinsics/gen/atomicMax/51b9be.wgsl.expected.hlsl b/test/intrinsics/gen/atomicMax/51b9be.wgsl.expected.hlsl
index 664bfff..fc4250b 100644
--- a/test/intrinsics/gen/atomicMax/51b9be.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicMax/51b9be.wgsl.expected.hlsl
@@ -1,10 +1,18 @@
-SKIP: FAILED
+RWByteAddressBuffer sb_rw : register(u0, space0);
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+void atomicMax_51b9be() {
+  uint atomic_result = 0u;
+  sb_rw.InterlockedMax(0u, 0u, atomic_result);
+  uint res = atomic_result;
+}
 
+void fragment_main() {
+  atomicMax_51b9be();
+  return;
+}
+
+[numthreads(1, 1, 1)]
+void compute_main() {
+  atomicMax_51b9be();
+  return;
+}
diff --git a/test/intrinsics/gen/atomicMax/92aa72.wgsl.expected.hlsl b/test/intrinsics/gen/atomicMax/92aa72.wgsl.expected.hlsl
index 664bfff..d23b380 100644
--- a/test/intrinsics/gen/atomicMax/92aa72.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicMax/92aa72.wgsl.expected.hlsl
@@ -1,10 +1,18 @@
-SKIP: FAILED
+RWByteAddressBuffer sb_rw : register(u0, space0);
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+void atomicMax_92aa72() {
+  int atomic_result = 0;
+  sb_rw.InterlockedMax(0u, 0u, atomic_result);
+  int res = atomic_result;
+}
 
+void fragment_main() {
+  atomicMax_92aa72();
+  return;
+}
+
+[numthreads(1, 1, 1)]
+void compute_main() {
+  atomicMax_92aa72();
+  return;
+}
diff --git a/test/intrinsics/gen/atomicMax/a89cc3.wgsl.expected.hlsl b/test/intrinsics/gen/atomicMax/a89cc3.wgsl.expected.hlsl
index deabbd0..f6a9e65 100644
--- a/test/intrinsics/gen/atomicMax/a89cc3.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicMax/a89cc3.wgsl.expected.hlsl
@@ -1,15 +1,13 @@
-SKIP: FAILED
+groupshared int arg_0;
 
-
-var<workgroup> arg_0 : atomic<i32>;
-
-fn atomicMax_a89cc3() {
-  var res : i32 = atomicMax(&(arg_0), 1);
+void atomicMax_a89cc3() {
+  int atomic_result = 0;
+  InterlockedMax(arg_0, 1, atomic_result);
+  int res = atomic_result;
 }
 
-[[stage(compute)]]
-fn compute_main() {
+[numthreads(1, 1, 1)]
+void compute_main() {
   atomicMax_a89cc3();
+  return;
 }
-
-Failed to generate: error: unknown type in EmitType
diff --git a/test/intrinsics/gen/atomicMax/a89cc3.wgsl.expected.msl b/test/intrinsics/gen/atomicMax/a89cc3.wgsl.expected.msl
index 664bfff..bdb46ff 100644
--- a/test/intrinsics/gen/atomicMax/a89cc3.wgsl.expected.msl
+++ b/test/intrinsics/gen/atomicMax/a89cc3.wgsl.expected.msl
@@ -1,10 +1,14 @@
 SKIP: FAILED
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
 
+fn atomicMax_a89cc3(tint_symbol : ptr<workgroup, atomic<i32>>) {
+  var res : i32 = atomicMax(&(*(tint_symbol)), 1);
+}
+
+[[stage(compute)]]
+fn compute_main() {
+  [[internal(disable_validation__function_var_storage_class)]] var<workgroup> tint_symbol_1 : atomic<i32>;
+  atomicMax_a89cc3(&(tint_symbol_1));
+}
+
+error: cannot declare an atomic var in a function scope
diff --git a/test/intrinsics/gen/atomicMax/beccfc.wgsl.expected.hlsl b/test/intrinsics/gen/atomicMax/beccfc.wgsl.expected.hlsl
index d07cc1a..0183b3d 100644
--- a/test/intrinsics/gen/atomicMax/beccfc.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicMax/beccfc.wgsl.expected.hlsl
@@ -1,15 +1,13 @@
-SKIP: FAILED
+groupshared uint arg_0;
 
-
-var<workgroup> arg_0 : atomic<u32>;
-
-fn atomicMax_beccfc() {
-  var res : u32 = atomicMax(&(arg_0), 1u);
+void atomicMax_beccfc() {
+  uint atomic_result = 0u;
+  InterlockedMax(arg_0, 1u, atomic_result);
+  uint res = atomic_result;
 }
 
-[[stage(compute)]]
-fn compute_main() {
+[numthreads(1, 1, 1)]
+void compute_main() {
   atomicMax_beccfc();
+  return;
 }
-
-Failed to generate: error: unknown type in EmitType
diff --git a/test/intrinsics/gen/atomicMax/beccfc.wgsl.expected.msl b/test/intrinsics/gen/atomicMax/beccfc.wgsl.expected.msl
index 664bfff..5dc602c 100644
--- a/test/intrinsics/gen/atomicMax/beccfc.wgsl.expected.msl
+++ b/test/intrinsics/gen/atomicMax/beccfc.wgsl.expected.msl
@@ -1,10 +1,14 @@
 SKIP: FAILED
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
 
+fn atomicMax_beccfc(tint_symbol : ptr<workgroup, atomic<u32>>) {
+  var res : u32 = atomicMax(&(*(tint_symbol)), 1u);
+}
+
+[[stage(compute)]]
+fn compute_main() {
+  [[internal(disable_validation__function_var_storage_class)]] var<workgroup> tint_symbol_1 : atomic<u32>;
+  atomicMax_beccfc(&(tint_symbol_1));
+}
+
+error: cannot declare an atomic var in a function scope
diff --git a/test/intrinsics/gen/atomicMin/278235.wgsl.expected.hlsl b/test/intrinsics/gen/atomicMin/278235.wgsl.expected.hlsl
index 1279197..b6c6f08 100644
--- a/test/intrinsics/gen/atomicMin/278235.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicMin/278235.wgsl.expected.hlsl
@@ -1,15 +1,13 @@
-SKIP: FAILED
+groupshared int arg_0;
 
-
-var<workgroup> arg_0 : atomic<i32>;
-
-fn atomicMin_278235() {
-  var res : i32 = atomicMin(&(arg_0), 1);
+void atomicMin_278235() {
+  int atomic_result = 0;
+  InterlockedMin(arg_0, 1, atomic_result);
+  int res = atomic_result;
 }
 
-[[stage(compute)]]
-fn compute_main() {
+[numthreads(1, 1, 1)]
+void compute_main() {
   atomicMin_278235();
+  return;
 }
-
-Failed to generate: error: unknown type in EmitType
diff --git a/test/intrinsics/gen/atomicMin/278235.wgsl.expected.msl b/test/intrinsics/gen/atomicMin/278235.wgsl.expected.msl
index 664bfff..7eb65c5 100644
--- a/test/intrinsics/gen/atomicMin/278235.wgsl.expected.msl
+++ b/test/intrinsics/gen/atomicMin/278235.wgsl.expected.msl
@@ -1,10 +1,14 @@
 SKIP: FAILED
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
 
+fn atomicMin_278235(tint_symbol : ptr<workgroup, atomic<i32>>) {
+  var res : i32 = atomicMin(&(*(tint_symbol)), 1);
+}
+
+[[stage(compute)]]
+fn compute_main() {
+  [[internal(disable_validation__function_var_storage_class)]] var<workgroup> tint_symbol_1 : atomic<i32>;
+  atomicMin_278235(&(tint_symbol_1));
+}
+
+error: cannot declare an atomic var in a function scope
diff --git a/test/intrinsics/gen/atomicMin/69d383.wgsl.expected.hlsl b/test/intrinsics/gen/atomicMin/69d383.wgsl.expected.hlsl
index b697f7f..73abc32 100644
--- a/test/intrinsics/gen/atomicMin/69d383.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicMin/69d383.wgsl.expected.hlsl
@@ -1,15 +1,13 @@
-SKIP: FAILED
+groupshared uint arg_0;
 
-
-var<workgroup> arg_0 : atomic<u32>;
-
-fn atomicMin_69d383() {
-  var res : u32 = atomicMin(&(arg_0), 1u);
+void atomicMin_69d383() {
+  uint atomic_result = 0u;
+  InterlockedMin(arg_0, 1u, atomic_result);
+  uint res = atomic_result;
 }
 
-[[stage(compute)]]
-fn compute_main() {
+[numthreads(1, 1, 1)]
+void compute_main() {
   atomicMin_69d383();
+  return;
 }
-
-Failed to generate: error: unknown type in EmitType
diff --git a/test/intrinsics/gen/atomicMin/69d383.wgsl.expected.msl b/test/intrinsics/gen/atomicMin/69d383.wgsl.expected.msl
index 664bfff..5ed9a71 100644
--- a/test/intrinsics/gen/atomicMin/69d383.wgsl.expected.msl
+++ b/test/intrinsics/gen/atomicMin/69d383.wgsl.expected.msl
@@ -1,10 +1,14 @@
 SKIP: FAILED
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
 
+fn atomicMin_69d383(tint_symbol : ptr<workgroup, atomic<u32>>) {
+  var res : u32 = atomicMin(&(*(tint_symbol)), 1u);
+}
+
+[[stage(compute)]]
+fn compute_main() {
+  [[internal(disable_validation__function_var_storage_class)]] var<workgroup> tint_symbol_1 : atomic<u32>;
+  atomicMin_69d383(&(tint_symbol_1));
+}
+
+error: cannot declare an atomic var in a function scope
diff --git a/test/intrinsics/gen/atomicMin/8e38dc.wgsl.expected.hlsl b/test/intrinsics/gen/atomicMin/8e38dc.wgsl.expected.hlsl
index 664bfff..304bc49 100644
--- a/test/intrinsics/gen/atomicMin/8e38dc.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicMin/8e38dc.wgsl.expected.hlsl
@@ -1,10 +1,18 @@
-SKIP: FAILED
+RWByteAddressBuffer sb_rw : register(u0, space0);
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+void atomicMin_8e38dc() {
+  int atomic_result = 0;
+  sb_rw.InterlockedMin(0u, 0u, atomic_result);
+  int res = atomic_result;
+}
 
+void fragment_main() {
+  atomicMin_8e38dc();
+  return;
+}
+
+[numthreads(1, 1, 1)]
+void compute_main() {
+  atomicMin_8e38dc();
+  return;
+}
diff --git a/test/intrinsics/gen/atomicMin/c67a74.wgsl.expected.hlsl b/test/intrinsics/gen/atomicMin/c67a74.wgsl.expected.hlsl
index 664bfff..104ecf1 100644
--- a/test/intrinsics/gen/atomicMin/c67a74.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicMin/c67a74.wgsl.expected.hlsl
@@ -1,10 +1,18 @@
-SKIP: FAILED
+RWByteAddressBuffer sb_rw : register(u0, space0);
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+void atomicMin_c67a74() {
+  uint atomic_result = 0u;
+  sb_rw.InterlockedMin(0u, 0u, atomic_result);
+  uint res = atomic_result;
+}
 
+void fragment_main() {
+  atomicMin_c67a74();
+  return;
+}
+
+[numthreads(1, 1, 1)]
+void compute_main() {
+  atomicMin_c67a74();
+  return;
+}
diff --git a/test/intrinsics/gen/atomicOr/5e3d61.wgsl.expected.hlsl b/test/intrinsics/gen/atomicOr/5e3d61.wgsl.expected.hlsl
index 52aa94e..8b6e92c 100644
--- a/test/intrinsics/gen/atomicOr/5e3d61.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicOr/5e3d61.wgsl.expected.hlsl
@@ -1,15 +1,13 @@
-SKIP: FAILED
+groupshared uint arg_0;
 
-
-var<workgroup> arg_0 : atomic<u32>;
-
-fn atomicOr_5e3d61() {
-  var res : u32 = atomicOr(&(arg_0), 1u);
+void atomicOr_5e3d61() {
+  uint atomic_result = 0u;
+  InterlockedOr(arg_0, 1u, atomic_result);
+  uint res = atomic_result;
 }
 
-[[stage(compute)]]
-fn compute_main() {
+[numthreads(1, 1, 1)]
+void compute_main() {
   atomicOr_5e3d61();
+  return;
 }
-
-Failed to generate: error: unknown type in EmitType
diff --git a/test/intrinsics/gen/atomicOr/5e3d61.wgsl.expected.msl b/test/intrinsics/gen/atomicOr/5e3d61.wgsl.expected.msl
index 664bfff..e38ef78 100644
--- a/test/intrinsics/gen/atomicOr/5e3d61.wgsl.expected.msl
+++ b/test/intrinsics/gen/atomicOr/5e3d61.wgsl.expected.msl
@@ -1,10 +1,14 @@
 SKIP: FAILED
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
 
+fn atomicOr_5e3d61(tint_symbol : ptr<workgroup, atomic<u32>>) {
+  var res : u32 = atomicOr(&(*(tint_symbol)), 1u);
+}
+
+[[stage(compute)]]
+fn compute_main() {
+  [[internal(disable_validation__function_var_storage_class)]] var<workgroup> tint_symbol_1 : atomic<u32>;
+  atomicOr_5e3d61(&(tint_symbol_1));
+}
+
+error: cannot declare an atomic var in a function scope
diff --git a/test/intrinsics/gen/atomicOr/5e95d4.wgsl.expected.hlsl b/test/intrinsics/gen/atomicOr/5e95d4.wgsl.expected.hlsl
index 664bfff..315eee7 100644
--- a/test/intrinsics/gen/atomicOr/5e95d4.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicOr/5e95d4.wgsl.expected.hlsl
@@ -1,10 +1,18 @@
-SKIP: FAILED
+RWByteAddressBuffer sb_rw : register(u0, space0);
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+void atomicOr_5e95d4() {
+  uint atomic_result = 0u;
+  sb_rw.InterlockedOr(0u, 0u, atomic_result);
+  uint res = atomic_result;
+}
 
+void fragment_main() {
+  atomicOr_5e95d4();
+  return;
+}
+
+[numthreads(1, 1, 1)]
+void compute_main() {
+  atomicOr_5e95d4();
+  return;
+}
diff --git a/test/intrinsics/gen/atomicOr/8d96a0.wgsl.expected.hlsl b/test/intrinsics/gen/atomicOr/8d96a0.wgsl.expected.hlsl
index 664bfff..5b68897 100644
--- a/test/intrinsics/gen/atomicOr/8d96a0.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicOr/8d96a0.wgsl.expected.hlsl
@@ -1,10 +1,18 @@
-SKIP: FAILED
+RWByteAddressBuffer sb_rw : register(u0, space0);
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+void atomicOr_8d96a0() {
+  int atomic_result = 0;
+  sb_rw.InterlockedOr(0u, 0u, atomic_result);
+  int res = atomic_result;
+}
 
+void fragment_main() {
+  atomicOr_8d96a0();
+  return;
+}
+
+[numthreads(1, 1, 1)]
+void compute_main() {
+  atomicOr_8d96a0();
+  return;
+}
diff --git a/test/intrinsics/gen/atomicOr/d09248.wgsl.expected.hlsl b/test/intrinsics/gen/atomicOr/d09248.wgsl.expected.hlsl
index 4ebdc78..889ce1c 100644
--- a/test/intrinsics/gen/atomicOr/d09248.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicOr/d09248.wgsl.expected.hlsl
@@ -1,15 +1,13 @@
-SKIP: FAILED
+groupshared int arg_0;
 
-
-var<workgroup> arg_0 : atomic<i32>;
-
-fn atomicOr_d09248() {
-  var res : i32 = atomicOr(&(arg_0), 1);
+void atomicOr_d09248() {
+  int atomic_result = 0;
+  InterlockedOr(arg_0, 1, atomic_result);
+  int res = atomic_result;
 }
 
-[[stage(compute)]]
-fn compute_main() {
+[numthreads(1, 1, 1)]
+void compute_main() {
   atomicOr_d09248();
+  return;
 }
-
-Failed to generate: error: unknown type in EmitType
diff --git a/test/intrinsics/gen/atomicOr/d09248.wgsl.expected.msl b/test/intrinsics/gen/atomicOr/d09248.wgsl.expected.msl
index 664bfff..e8c75dd 100644
--- a/test/intrinsics/gen/atomicOr/d09248.wgsl.expected.msl
+++ b/test/intrinsics/gen/atomicOr/d09248.wgsl.expected.msl
@@ -1,10 +1,14 @@
 SKIP: FAILED
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
 
+fn atomicOr_d09248(tint_symbol : ptr<workgroup, atomic<i32>>) {
+  var res : i32 = atomicOr(&(*(tint_symbol)), 1);
+}
+
+[[stage(compute)]]
+fn compute_main() {
+  [[internal(disable_validation__function_var_storage_class)]] var<workgroup> tint_symbol_1 : atomic<i32>;
+  atomicOr_d09248(&(tint_symbol_1));
+}
+
+error: cannot declare an atomic var in a function scope
diff --git a/test/intrinsics/gen/atomicStore/726882.wgsl.expected.hlsl b/test/intrinsics/gen/atomicStore/726882.wgsl.expected.hlsl
index 3e2cdaa..65a71a8 100644
--- a/test/intrinsics/gen/atomicStore/726882.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicStore/726882.wgsl.expected.hlsl
@@ -1,15 +1,12 @@
-SKIP: FAILED
+groupshared uint arg_0;
 
-
-var<workgroup> arg_0 : atomic<u32>;
-
-fn atomicStore_726882() {
-  atomicStore(&(arg_0), 1u);
+void atomicStore_726882() {
+  uint atomic_result = 0u;
+  InterlockedExchange(arg_0, 1u, atomic_result);
 }
 
-[[stage(compute)]]
-fn compute_main() {
+[numthreads(1, 1, 1)]
+void compute_main() {
   atomicStore_726882();
+  return;
 }
-
-Failed to generate: error: unknown type in EmitType
diff --git a/test/intrinsics/gen/atomicStore/726882.wgsl.expected.msl b/test/intrinsics/gen/atomicStore/726882.wgsl.expected.msl
index 664bfff..c2468d6 100644
--- a/test/intrinsics/gen/atomicStore/726882.wgsl.expected.msl
+++ b/test/intrinsics/gen/atomicStore/726882.wgsl.expected.msl
@@ -1,10 +1,14 @@
 SKIP: FAILED
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
 
+fn atomicStore_726882(tint_symbol : ptr<workgroup, atomic<u32>>) {
+  atomicStore(&(*(tint_symbol)), 1u);
+}
+
+[[stage(compute)]]
+fn compute_main() {
+  [[internal(disable_validation__function_var_storage_class)]] var<workgroup> tint_symbol_1 : atomic<u32>;
+  atomicStore_726882(&(tint_symbol_1));
+}
+
+error: cannot declare an atomic var in a function scope
diff --git a/test/intrinsics/gen/atomicStore/8bea94.wgsl.expected.hlsl b/test/intrinsics/gen/atomicStore/8bea94.wgsl.expected.hlsl
index 40616cc..31257e0 100644
--- a/test/intrinsics/gen/atomicStore/8bea94.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicStore/8bea94.wgsl.expected.hlsl
@@ -1,15 +1,12 @@
-SKIP: FAILED
+groupshared int arg_0;
 
-
-var<workgroup> arg_0 : atomic<i32>;
-
-fn atomicStore_8bea94() {
-  atomicStore(&(arg_0), 1);
+void atomicStore_8bea94() {
+  int atomic_result = 0;
+  InterlockedExchange(arg_0, 1, atomic_result);
 }
 
-[[stage(compute)]]
-fn compute_main() {
+[numthreads(1, 1, 1)]
+void compute_main() {
   atomicStore_8bea94();
+  return;
 }
-
-Failed to generate: error: unknown type in EmitType
diff --git a/test/intrinsics/gen/atomicStore/8bea94.wgsl.expected.msl b/test/intrinsics/gen/atomicStore/8bea94.wgsl.expected.msl
index 664bfff..651a1da 100644
--- a/test/intrinsics/gen/atomicStore/8bea94.wgsl.expected.msl
+++ b/test/intrinsics/gen/atomicStore/8bea94.wgsl.expected.msl
@@ -1,10 +1,14 @@
 SKIP: FAILED
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
 
+fn atomicStore_8bea94(tint_symbol : ptr<workgroup, atomic<i32>>) {
+  atomicStore(&(*(tint_symbol)), 1);
+}
+
+[[stage(compute)]]
+fn compute_main() {
+  [[internal(disable_validation__function_var_storage_class)]] var<workgroup> tint_symbol_1 : atomic<i32>;
+  atomicStore_8bea94(&(tint_symbol_1));
+}
+
+error: cannot declare an atomic var in a function scope
diff --git a/test/intrinsics/gen/atomicStore/cdc29e.wgsl.expected.hlsl b/test/intrinsics/gen/atomicStore/cdc29e.wgsl.expected.hlsl
index 664bfff..031984b 100644
--- a/test/intrinsics/gen/atomicStore/cdc29e.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicStore/cdc29e.wgsl.expected.hlsl
@@ -1,10 +1,17 @@
-SKIP: FAILED
+RWByteAddressBuffer sb_rw : register(u0, space0);
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+void atomicStore_cdc29e() {
+  uint atomic_result = 0u;
+  sb_rw.InterlockedExchange(0u, 1u, atomic_result);
+}
 
+void fragment_main() {
+  atomicStore_cdc29e();
+  return;
+}
+
+[numthreads(1, 1, 1)]
+void compute_main() {
+  atomicStore_cdc29e();
+  return;
+}
diff --git a/test/intrinsics/gen/atomicStore/d1e9a6.wgsl.expected.hlsl b/test/intrinsics/gen/atomicStore/d1e9a6.wgsl.expected.hlsl
index 664bfff..9fa1886 100644
--- a/test/intrinsics/gen/atomicStore/d1e9a6.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicStore/d1e9a6.wgsl.expected.hlsl
@@ -1,10 +1,17 @@
-SKIP: FAILED
+RWByteAddressBuffer sb_rw : register(u0, space0);
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+void atomicStore_d1e9a6() {
+  int atomic_result = 0;
+  sb_rw.InterlockedExchange(0u, 1, atomic_result);
+}
 
+void fragment_main() {
+  atomicStore_d1e9a6();
+  return;
+}
+
+[numthreads(1, 1, 1)]
+void compute_main() {
+  atomicStore_d1e9a6();
+  return;
+}
diff --git a/test/intrinsics/gen/atomicXor/54510e.wgsl.expected.hlsl b/test/intrinsics/gen/atomicXor/54510e.wgsl.expected.hlsl
index 664bfff..d81f8e5 100644
--- a/test/intrinsics/gen/atomicXor/54510e.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicXor/54510e.wgsl.expected.hlsl
@@ -1,10 +1,18 @@
-SKIP: FAILED
+RWByteAddressBuffer sb_rw : register(u0, space0);
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+void atomicXor_54510e() {
+  uint atomic_result = 0u;
+  sb_rw.InterlockedXor(0u, 0u, atomic_result);
+  uint res = atomic_result;
+}
 
+void fragment_main() {
+  atomicXor_54510e();
+  return;
+}
+
+[numthreads(1, 1, 1)]
+void compute_main() {
+  atomicXor_54510e();
+  return;
+}
diff --git a/test/intrinsics/gen/atomicXor/75dc95.wgsl.expected.hlsl b/test/intrinsics/gen/atomicXor/75dc95.wgsl.expected.hlsl
index 83797cf..a2f2005 100644
--- a/test/intrinsics/gen/atomicXor/75dc95.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicXor/75dc95.wgsl.expected.hlsl
@@ -1,15 +1,13 @@
-SKIP: FAILED
+groupshared int arg_0;
 
-
-var<workgroup> arg_0 : atomic<i32>;
-
-fn atomicXor_75dc95() {
-  var res : i32 = atomicXor(&(arg_0), 1);
+void atomicXor_75dc95() {
+  int atomic_result = 0;
+  InterlockedXor(arg_0, 1, atomic_result);
+  int res = atomic_result;
 }
 
-[[stage(compute)]]
-fn compute_main() {
+[numthreads(1, 1, 1)]
+void compute_main() {
   atomicXor_75dc95();
+  return;
 }
-
-Failed to generate: error: unknown type in EmitType
diff --git a/test/intrinsics/gen/atomicXor/75dc95.wgsl.expected.msl b/test/intrinsics/gen/atomicXor/75dc95.wgsl.expected.msl
index 664bfff..32bbb93 100644
--- a/test/intrinsics/gen/atomicXor/75dc95.wgsl.expected.msl
+++ b/test/intrinsics/gen/atomicXor/75dc95.wgsl.expected.msl
@@ -1,10 +1,14 @@
 SKIP: FAILED
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
 
+fn atomicXor_75dc95(tint_symbol : ptr<workgroup, atomic<i32>>) {
+  var res : i32 = atomicXor(&(*(tint_symbol)), 1);
+}
+
+[[stage(compute)]]
+fn compute_main() {
+  [[internal(disable_validation__function_var_storage_class)]] var<workgroup> tint_symbol_1 : atomic<i32>;
+  atomicXor_75dc95(&(tint_symbol_1));
+}
+
+error: cannot declare an atomic var in a function scope
diff --git a/test/intrinsics/gen/atomicXor/c1b78c.wgsl.expected.hlsl b/test/intrinsics/gen/atomicXor/c1b78c.wgsl.expected.hlsl
index 664bfff..660aaf1 100644
--- a/test/intrinsics/gen/atomicXor/c1b78c.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicXor/c1b78c.wgsl.expected.hlsl
@@ -1,10 +1,18 @@
-SKIP: FAILED
+RWByteAddressBuffer sb_rw : register(u0, space0);
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+void atomicXor_c1b78c() {
+  int atomic_result = 0;
+  sb_rw.InterlockedXor(0u, 0u, atomic_result);
+  int res = atomic_result;
+}
 
+void fragment_main() {
+  atomicXor_c1b78c();
+  return;
+}
+
+[numthreads(1, 1, 1)]
+void compute_main() {
+  atomicXor_c1b78c();
+  return;
+}
diff --git a/test/intrinsics/gen/atomicXor/c8e6be.wgsl.expected.hlsl b/test/intrinsics/gen/atomicXor/c8e6be.wgsl.expected.hlsl
index 423045a..afa7fd5 100644
--- a/test/intrinsics/gen/atomicXor/c8e6be.wgsl.expected.hlsl
+++ b/test/intrinsics/gen/atomicXor/c8e6be.wgsl.expected.hlsl
@@ -1,15 +1,13 @@
-SKIP: FAILED
+groupshared uint arg_0;
 
-
-var<workgroup> arg_0 : atomic<u32>;
-
-fn atomicXor_c8e6be() {
-  var res : u32 = atomicXor(&(arg_0), 1u);
+void atomicXor_c8e6be() {
+  uint atomic_result = 0u;
+  InterlockedXor(arg_0, 1u, atomic_result);
+  uint res = atomic_result;
 }
 
-[[stage(compute)]]
-fn compute_main() {
+[numthreads(1, 1, 1)]
+void compute_main() {
   atomicXor_c8e6be();
+  return;
 }
-
-Failed to generate: error: unknown type in EmitType
diff --git a/test/intrinsics/gen/atomicXor/c8e6be.wgsl.expected.msl b/test/intrinsics/gen/atomicXor/c8e6be.wgsl.expected.msl
index 664bfff..4ee0172 100644
--- a/test/intrinsics/gen/atomicXor/c8e6be.wgsl.expected.msl
+++ b/test/intrinsics/gen/atomicXor/c8e6be.wgsl.expected.msl
@@ -1,10 +1,14 @@
 SKIP: FAILED
 
-../src/transform/transform.cc:133 internal compiler error: TINT_UNREACHABLE Unhandled type: tint::sem::Atomic
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
 
+fn atomicXor_c8e6be(tint_symbol : ptr<workgroup, atomic<u32>>) {
+  var res : u32 = atomicXor(&(*(tint_symbol)), 1u);
+}
+
+[[stage(compute)]]
+fn compute_main() {
+  [[internal(disable_validation__function_var_storage_class)]] var<workgroup> tint_symbol_1 : atomic<u32>;
+  atomicXor_c8e6be(&(tint_symbol_1));
+}
+
+error: cannot declare an atomic var in a function scope