tint/writer: Handle and emit 'const' variables

Bug: tint:1580
Change-Id: Ib3a5ff5c567e19eca1ba8fb3c2f7e83dee68e2a0
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/94686
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc
index 8139e6b..bd58e30 100644
--- a/src/tint/writer/hlsl/generator_impl.cc
+++ b/src/tint/writer/hlsl/generator_impl.cc
@@ -2617,12 +2617,7 @@
             // TODO(crbug.com/tint/1580): Once 'const' is implemented, 'let' will no longer resolve
             // to a shader-creation time constant value, and this can be removed.
             if (auto constant = sem->ConstantValue()) {
-                // We do not want to inline array constants, as this will undo the work of
-                // PromoteInitializersToLet, which ensures that arrays are declarated in 'let's
-                // before their usage.
-                if (!constant.Type()->Is<sem::Array>()) {
-                    return EmitConstant(out, constant);
-                }
+                return EmitConstant(out, constant);
             }
         }
     }
@@ -2856,6 +2851,9 @@
         },
         [&](const ast::Let* let) { return EmitProgramConstVariable(let); },
         [&](const ast::Override* override) { return EmitOverride(override); },
+        [&](const ast::Const*) {
+            return true;  // Constants are embedded at their use
+        },
         [&](Default) {
             TINT_ICE(Writer, diagnostics_)
                 << "unhandled global variable type " << global->TypeInfo().name;
@@ -3174,8 +3172,7 @@
             return true;
         },
         [&](const sem::Matrix* m) {
-            if (!EmitType(out, constant.Type(), ast::StorageClass::kNone, ast::Access::kUndefined,
-                          "")) {
+            if (!EmitType(out, m, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
                 return false;
             }
 
@@ -3193,6 +3190,34 @@
             }
             return true;
         },
+        [&](const sem::Array* a) {
+            if (constant.AllZero(start, end)) {
+                out << "(";
+                if (!EmitType(out, a, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
+                    return false;
+                }
+                out << ")0";
+                return true;
+            }
+
+            out << "{";
+            TINT_DEFER(out << "}");
+
+            auto* el_ty = a->ElemType();
+
+            uint32_t step = 0;
+            sem::Type::DeepestElementOf(el_ty, &step);
+            for (size_t i = start; i < end; i += step) {
+                if (i > start) {
+                    out << ", ";
+                }
+                if (!EmitConstantRange(out, constant, el_ty, i, i + step)) {
+                    return false;
+                }
+            }
+
+            return true;
+        },
         [&](Default) {
             diagnostics_.add_error(
                 diag::System::Writer,
@@ -3571,6 +3596,9 @@
                 v->variable,  //
                 [&](const ast::Var* var) { return EmitVar(var); },
                 [&](const ast::Let* let) { return EmitLet(let); },
+                [&](const ast::Const*) {
+                    return true;  // Constants are embedded at their use
+                },
                 [&](Default) {  //
                     TINT_ICE(Writer, diagnostics_)
                         << "unknown variable type: " << v->variable->TypeInfo().name;