[d3d] Move SingleEntryPoint to raise

Move the call to the SingleEntryPoint transform directly into the HLSL
raise routine.

Change-Id: I8a10e28d97b7366dc933375ca9059753e5c026c8
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/268255
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/dawn/native/d3d/D3DCompilationRequest.h b/src/dawn/native/d3d/D3DCompilationRequest.h
index 7dafa20..e12b8c8 100644
--- a/src/dawn/native/d3d/D3DCompilationRequest.h
+++ b/src/dawn/native/d3d/D3DCompilationRequest.h
@@ -62,7 +62,6 @@
 #define HLSL_COMPILATION_REQUEST_MEMBERS(X)                                          \
     X(ShaderModuleBase::ShaderModuleHash, shaderModuleHash)                          \
     X(UnsafeUnserializedValue<ShaderModuleBase::ScopedUseTintProgram>, inputProgram) \
-    X(std::string_view, entryPointName)                                              \
     X(SingleShaderStage, stage)                                                      \
     X(uint32_t, shaderModel)                                                         \
     X(uint32_t, compileFlags)                                                        \
diff --git a/src/dawn/native/d3d/ShaderUtils.cpp b/src/dawn/native/d3d/ShaderUtils.cpp
index d6c9169..64b2e73 100644
--- a/src/dawn/native/d3d/ShaderUtils.cpp
+++ b/src/dawn/native/d3d/ShaderUtils.cpp
@@ -231,16 +231,6 @@
                         ir.Failure().reason);
     }
 
-    {
-        SCOPED_DAWN_HISTOGRAM_TIMER_MICROS(tracePlatform.UnsafeGetValue(),
-                                           "ShaderModuleSingleEntryPoint");
-        auto singleEntryPointResult =
-            tint::core::ir::transform::SingleEntryPoint(ir.Get(), r.entryPointName);
-        DAWN_INVALID_IF(singleEntryPointResult != tint::Success,
-                        "Pipeline single entry point (IR) failed:\n%s",
-                        singleEntryPointResult.Failure().reason);
-    }
-
     tint::Result<tint::hlsl::writer::Output> result;
     {
         SCOPED_DAWN_HISTOGRAM_TIMER_MICROS(tracePlatform.UnsafeGetValue(),
diff --git a/src/dawn/native/d3d11/ShaderModuleD3D11.cpp b/src/dawn/native/d3d11/ShaderModuleD3D11.cpp
index 84281ca..d227a0b 100644
--- a/src/dawn/native/d3d11/ShaderModuleD3D11.cpp
+++ b/src/dawn/native/d3d11/ShaderModuleD3D11.cpp
@@ -86,6 +86,7 @@
     req.hlsl.disableSymbolRenaming = device->IsToggleEnabled(Toggle::DisableSymbolRenaming);
     req.hlsl.dumpShaders = device->IsToggleEnabled(Toggle::DumpShaders);
     req.hlsl.dumpShadersOnFailure = device->IsToggleEnabled(Toggle::DumpShadersOnFailure);
+    req.hlsl.tintOptions.entry_point_name = programmableStage.entryPoint;
     req.hlsl.tintOptions.remapped_entry_point_name = device->GetIsolatedEntryPointName();
 
     req.bytecode.hasShaderF16Feature = false;
@@ -120,7 +121,6 @@
 
     req.hlsl.shaderModuleHash = GetHash();
     req.hlsl.inputProgram = UnsafeUnserializedValue(UseTintProgram());
-    req.hlsl.entryPointName = programmableStage.entryPoint.c_str();
     req.hlsl.stage = stage;
     req.hlsl.limits = LimitsForCompilationRequest::Create(device->GetLimits().v1);
     req.hlsl.adapterSupportedLimits = UnsafeUnserializedValue(
diff --git a/src/dawn/native/d3d12/ShaderModuleD3D12.cpp b/src/dawn/native/d3d12/ShaderModuleD3D12.cpp
index e6aaa9c..8678be8 100644
--- a/src/dawn/native/d3d12/ShaderModuleD3D12.cpp
+++ b/src/dawn/native/d3d12/ShaderModuleD3D12.cpp
@@ -131,6 +131,7 @@
     req.hlsl.disableSymbolRenaming = device->IsToggleEnabled(Toggle::DisableSymbolRenaming);
     req.hlsl.dumpShaders = device->IsToggleEnabled(Toggle::DumpShaders);
     req.hlsl.dumpShadersOnFailure = device->IsToggleEnabled(Toggle::DumpShadersOnFailure);
+    req.hlsl.tintOptions.entry_point_name = programmableStage.entryPoint;
     req.hlsl.tintOptions.remapped_entry_point_name = device->GetIsolatedEntryPointName();
 
     req.bytecode.hasShaderF16Feature = device->HasFeature(Feature::ShaderF16);
@@ -225,7 +226,6 @@
 
     req.hlsl.shaderModuleHash = GetHash();
     req.hlsl.inputProgram = UnsafeUnserializedValue(UseTintProgram());
-    req.hlsl.entryPointName = programmableStage.entryPoint.c_str();
     req.hlsl.stage = stage;
     req.hlsl.tintOptions.substitute_overrides_config = {
         .map = BuildSubstituteOverridesTransformConfig(programmableStage),
diff --git a/src/tint/cmd/tint/main.cc b/src/tint/cmd/tint/main.cc
index 1773970..97d564b 100644
--- a/src/tint/cmd/tint/main.cc
+++ b/src/tint/cmd/tint/main.cc
@@ -44,7 +44,6 @@
 #include "src/tint/lang/core/ir/disassembler.h"
 #include "src/tint/lang/core/ir/referenced_module_vars.h"
 #include "src/tint/lang/core/ir/transform/resource_binding_helper.h"
-#include "src/tint/lang/core/ir/transform/single_entry_point.h"
 #include "src/tint/lang/core/ir/var.h"
 #include "src/tint/lang/core/type/f16.h"
 #include "src/tint/lang/core/type/pointer.h"
@@ -1139,6 +1138,7 @@
         gen_options.remapped_entry_point_name = "tint_entry_point";
         gen_options.strip_all_names = true;
     }
+    gen_options.entry_point_name = options.ep_name;
     gen_options.disable_robustness = !options.enable_robustness;
     gen_options.disable_workgroup_init = options.disable_workgroup_init;
     gen_options.pixel_local = options.pixel_local_options;
@@ -1159,7 +1159,7 @@
     gen_options.substitute_overrides_config = substitute_override_cfg.Get();
 
     // Check that the module and options are supported by the backend.
-    auto check = tint::hlsl::writer::CanGenerate(ir, gen_options, options.ep_name);
+    auto check = tint::hlsl::writer::CanGenerate(ir, gen_options);
     if (check != tint::Success) {
         std::cerr << check.Failure() << "\n";
         return false;
@@ -1411,6 +1411,9 @@
     }
 
     switch (options.format) {
+        case Format::kHlsl:
+        case Format::kHlslFxc:
+            return GenerateHlsl(options, inspector, ir.Get());
         case Format::kMsl:
             return GenerateMsl(options, inspector, ir.Get());
         case Format::kSpirv:
@@ -1418,28 +1421,8 @@
             return GenerateSpirv(options, inspector, ir.Get());
         case Format::kGlsl:
             return GenerateGlsl(options, inspector, ir.Get());
-        default:
-            break;
-    }
-
-    // Strip the module down to a single entry point.
-    if (options.ep_name != "") {
-        auto singleEntryPointResult =
-            tint::core::ir::transform::SingleEntryPoint(ir.Get(), options.ep_name);
-        if (singleEntryPointResult != tint::Success) {
-            std::cerr << "SingleEntryPoint failed:\n" << singleEntryPointResult.Failure() << "\n";
-            return false;
-        }
-    }
-
-    switch (options.format) {
-        case Format::kHlsl:
-        case Format::kHlslFxc:
-            return GenerateHlsl(options, inspector, ir.Get());
         case Format::kWgsl:
             TINT_UNREACHABLE();
-        case Format::kNone:
-            break;
         default:
             std::cerr << "Unknown output format specified\n";
             break;
diff --git a/src/tint/lang/hlsl/writer/access_test.cc b/src/tint/lang/hlsl/writer/access_test.cc
index 6890ad4..ba03de6 100644
--- a/src/tint/lang/hlsl/writer/access_test.cc
+++ b/src/tint/lang/hlsl/writer/access_test.cc
@@ -34,7 +34,7 @@
 namespace {
 
 TEST_F(HlslWriterTest, AccessArray) {
-    auto* func = b.ComputeFunction("a");
+    auto* func = b.ComputeFunction("main");
 
     b.Append(func->Block(), [&] {
         auto* v = b.Var("v", b.Zero<array<f32, 3>>());
@@ -45,7 +45,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void a() {
+void main() {
   float v[3] = (float[3])0;
   float x = v[1u];
 }
@@ -62,7 +62,7 @@
     };
     auto* strct = ty.Struct(b.ir.symbols.New("S"), std::move(members));
 
-    auto* f = b.ComputeFunction("a");
+    auto* f = b.ComputeFunction("main");
 
     b.Append(f->Block(), [&] {
         auto* v = b.Var("v", b.Zero(strct));
@@ -78,7 +78,7 @@
 
 
 [numthreads(1, 1, 1)]
-void a() {
+void main() {
   S v = (S)0;
   float x = v.b;
 }
@@ -87,7 +87,7 @@
 }
 
 TEST_F(HlslWriterTest, AccessVector) {
-    auto* func = b.ComputeFunction("a");
+    auto* func = b.ComputeFunction("main");
 
     b.Append(func->Block(), [&] {
         auto* v = b.Var("v", b.Zero<vec3<f32>>());
@@ -98,7 +98,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void a() {
+void main() {
   float3 v = (0.0f).xxx;
   float x = v.y;
 }
@@ -107,7 +107,7 @@
 }
 
 TEST_F(HlslWriterTest, AccessMatrix) {
-    auto* func = b.ComputeFunction("a");
+    auto* func = b.ComputeFunction("main");
 
     b.Append(func->Block(), [&] {
         auto* v = b.Var("v", b.Zero<mat4x4<f32>>());
@@ -119,7 +119,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void a() {
+void main() {
   float4x4 v = float4x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx);
   float x = v[1u].z;
 }
@@ -128,7 +128,7 @@
 }
 
 TEST_F(HlslWriterTest, AccessStoreVectorElementConstantIndex) {
-    auto* func = b.Function("foo", ty.void_());
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* vec_var = b.Var("vec", ty.ptr<function, vec4<i32>>());
         b.StoreVectorElement(vec_var, 1_u, b.Constant(42_i));
@@ -137,15 +137,12 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+[numthreads(1, 1, 1)]
+void main() {
   int4 vec = (int(0)).xxxx;
   vec.y = int(42);
 }
 
-[numthreads(1, 1, 1)]
-void unused_entry_point() {
-}
-
 )");
 }
 
@@ -159,6 +156,12 @@
         b.Return(func);
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Call(func, b.Zero(ty.i32()));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 void foo(int idx) {
@@ -167,7 +170,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  foo(int(0));
 }
 
 )");
@@ -192,7 +196,7 @@
     };
     auto* s_strct = ty.Struct(b.ir.symbols.New("S"), std::move(members_s));
 
-    auto* f = b.ComputeFunction("a");
+    auto* f = b.ComputeFunction("main");
 
     b.Append(f->Block(), [&] {
         auto* v = b.Var("v", b.Zero(s_strct));
@@ -214,7 +218,7 @@
 
 
 [numthreads(1, 1, 1)]
-void a() {
+void main() {
   S v = (S)0;
   float x = v.c.e[1u];
 }
@@ -223,7 +227,7 @@
 }
 
 TEST_F(HlslWriterTest, AccessSwizzle) {
-    auto* f = b.ComputeFunction("a");
+    auto* f = b.ComputeFunction("main");
 
     b.Append(f->Block(), [&] {
         auto* v = b.Var("v", b.Zero<vec3<f32>>());
@@ -234,7 +238,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void a() {
+void main() {
   float3 v = (0.0f).xxx;
   float b = v.y;
 }
@@ -243,7 +247,7 @@
 }
 
 TEST_F(HlslWriterTest, AccessSwizzleMulti) {
-    auto* f = b.ComputeFunction("a");
+    auto* f = b.ComputeFunction("main");
 
     b.Append(f->Block(), [&] {
         auto* v = b.Var("v", b.Zero<vec4<f32>>());
@@ -254,7 +258,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void a() {
+void main() {
   float4 v = (0.0f).xxxx;
   float4 b = v.wzyx;
 }
@@ -267,7 +271,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("a", b.Load(var));
         b.Let("b", b.LoadVectorElement(var, 0_u));
@@ -280,7 +284,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 ByteAddressBuffer v : register(t0);
-void foo() {
+void main() {
   float4 a = asfloat(v.Load4(0u));
   float b = asfloat(v.Load(0u));
   float c = asfloat(v.Load(4u));
@@ -296,7 +300,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("a", b.Load(var));
         b.Let("b", b.LoadVectorElement(var, 0_u));
@@ -309,7 +313,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 ByteAddressBuffer v : register(t0);
-void foo() {
+void main() {
   vector<float16_t, 4> a = v.Load<vector<float16_t, 4> >(0u);
   float16_t b = v.Load<float16_t>(0u);
   float16_t c = v.Load<float16_t>(2u);
@@ -325,7 +329,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("a", b.Load(var));
         b.Let("b", b.Load(b.Access(ty.ptr<storage, vec4<f32>, core::Access::kRead>(), var, 3_u)));
@@ -341,7 +345,7 @@
   return float4x4(asfloat(v.Load4((offset + 0u))), asfloat(v.Load4((offset + 16u))), asfloat(v.Load4((offset + 32u))), asfloat(v.Load4((offset + 48u))));
 }
 
-void foo() {
+void main() {
   float4x4 a = v_1(0u);
   float4 b = asfloat(v.Load4(48u));
   float c = asfloat(v.Load(24u));
@@ -355,7 +359,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("a", b.Load(var));
         b.Let("b", b.Load(b.Access(ty.ptr<storage, vec3<f32>, core::Access::kRead>(), var, 3_u)));
@@ -387,7 +391,7 @@
   return v_4;
 }
 
-void foo() {
+void main() {
   float3 a[5] = v_1(0u);
   float3 b = asfloat(v.Load3(48u));
 }
@@ -405,7 +409,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("a", b.Load(var));
         b.Let("b", b.Load(b.Access(ty.ptr<storage, f32, core::Access::kRead>(), var, 1_u)));
@@ -425,7 +429,7 @@
   return v_2;
 }
 
-void foo() {
+void main() {
   SB a = v_1(0u);
   float b = asfloat(v.Load(4u));
 }
@@ -453,7 +457,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("a", b.Load(var));
         b.Let("b", b.LoadVectorElement(b.Access(ty.ptr<storage, vec3<f32>, core::Access::kRead>(),
@@ -527,7 +531,7 @@
   return v_17;
 }
 
-void foo() {
+void main() {
   SB a = v_14(0u);
   float b = asfloat(v.Load(136u));
 }
@@ -540,7 +544,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.StoreVectorElement(var, 0_u, 2_f);
         b.StoreVectorElement(var, 1_u, 4_f);
@@ -552,7 +556,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   v.Store(0u, asuint(2.0f));
   v.Store(4u, asuint(4.0f));
   v.Store(8u, asuint(8.0f));
@@ -579,7 +583,7 @@
         b.Return(bar);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Call(bar, var1);
         b.Call(bar, var2);
@@ -598,7 +602,7 @@
   float a = asfloat(v2.Load(4u));
 }
 
-void foo() {
+void main() {
   bar();
   bar_1();
 }
@@ -620,7 +624,7 @@
     var->SetBindingPoint(0, 0);
     b.ir.root_block->Append(var);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* x = b.Access(ty.ptr(storage, sb, core::Access::kReadWrite), var, 2_u);
         auto* y = b.Access(ty.ptr(storage, Inner, core::Access::kReadWrite), x->Result(), 1_u);
@@ -632,7 +636,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   uint b = v.Load(32u);
 }
 
@@ -652,7 +656,7 @@
     var->SetBindingPoint(0, 0);
     b.ir.root_block->Append(var);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* x = b.Let("x", var);
         auto* y = b.Let(
@@ -666,7 +670,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   float a = asfloat(v.Load(4u));
 }
 
@@ -694,7 +698,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* i = b.Load(b.Var("i", 4_i));
         auto* j = b.Load(b.Var("j", 1_u));
@@ -709,7 +713,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer sb : register(u0);
-void foo() {
+void main() {
   int i = int(4);
   uint j = 1u;
   uint v = j;
@@ -746,7 +750,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* j = b.Load(b.Var("j", 1_u));
         b.Let("x", b.LoadVectorElement(b.Access(ty.ptr<storage, vec3<f32>, read_write>(), var, 1_u,
@@ -758,7 +762,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer sb : register(u0);
-void foo() {
+void main() {
   uint j = 1u;
   uint v = 0u;
   sb.GetDimensions(v);
@@ -785,7 +789,7 @@
     var->SetBindingPoint(0, 0);
     b.ir.root_block->Append(var);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* x = b.Access(ty.ptr(uniform, sb, core::Access::kRead), var, 2_u);
         auto* y = b.Access(ty.ptr(uniform, Inner, core::Access::kRead), x->Result(), 1_u);
@@ -799,7 +803,7 @@
 cbuffer cbuffer_v : register(b0) {
   uint4 v[8];
 };
-void foo() {
+void main() {
   uint b = v[5u].y;
 }
 
@@ -821,7 +825,7 @@
     var->SetBindingPoint(0, 0);
     b.ir.root_block->Append(var);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* x = b.Let("x", var);
         auto* y =
@@ -837,7 +841,7 @@
 cbuffer cbuffer_v : register(b0) {
   uint4 v[2];
 };
-void foo() {
+void main() {
   float a = asfloat(v[1u].x);
 }
 
@@ -849,7 +853,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("a", b.Load(var));
         b.Return(func);
@@ -860,7 +864,7 @@
 cbuffer cbuffer_v : register(b0) {
   uint4 v[1];
 };
-void foo() {
+void main() {
   float a = asfloat(v[0u].x);
 }
 
@@ -872,7 +876,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("a", b.Load(var));
         b.Return(func);
@@ -891,7 +895,7 @@
   return vector<float16_t, 2>(v_2, float16_t(t_high));
 }
 
-void foo() {
+void main() {
   float16_t a = tint_bitcast_to_f16(v[0u].x).x;
 }
 
@@ -903,7 +907,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("a", b.Load(var));
         b.Let("b", b.LoadVectorElement(var, 0_u));
@@ -918,7 +922,7 @@
 cbuffer cbuffer_v : register(b0) {
   uint4 v[1];
 };
-void foo() {
+void main() {
   float4 a = asfloat(v[0u]);
   float b = asfloat(v[0u].x);
   float c = asfloat(v[0u].y);
@@ -934,7 +938,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* x = b.Var("x", 1_u);
         b.Let("a", b.Load(var));
@@ -970,7 +974,7 @@
   return vector<float16_t, 4>(v_4, v_5, v_6, float16_t(t_high.y));
 }
 
-void foo() {
+void main() {
   uint x = 1u;
   vector<float16_t, 4> a = tint_bitcast_to_f16_1(v[0u].xy);
   float16_t b = tint_bitcast_to_f16(v[0u].x).x;
@@ -990,7 +994,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("a", b.Load(var));
         b.Let("b", b.Load(b.Access(ty.ptr<uniform, vec4<f32>, core::Access::kRead>(), var, 3_u)));
@@ -1008,7 +1012,7 @@
   return float4x4(asfloat(v[(start_byte_offset / 16u)]), asfloat(v[((16u + start_byte_offset) / 16u)]), asfloat(v[((32u + start_byte_offset) / 16u)]), asfloat(v[((48u + start_byte_offset) / 16u)]));
 }
 
-void foo() {
+void main() {
   float4x4 a = v_1(0u);
   float4 b = asfloat(v[3u]);
   float c = asfloat(v[1u].z);
@@ -1022,7 +1026,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("a", b.Load(var));
         b.Let("b", b.Load(b.Access(ty.ptr<uniform, vec3<f32>, core::Access::kRead>(), var, 1_u)));
@@ -1040,7 +1044,7 @@
   return float2x3(asfloat(v[(start_byte_offset / 16u)].xyz), asfloat(v[((16u + start_byte_offset) / 16u)].xyz));
 }
 
-void foo() {
+void main() {
   float2x3 a = v_1(0u);
   float3 b = asfloat(v[1u].xyz);
   float c = asfloat(v[1u].z);
@@ -1054,7 +1058,7 @@
     var->SetBindingPoint(0, 0);
     b.ir.root_block->Append(var);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("a", b.Load(var));
         b.Let("b", b.Load(b.Access(ty.ptr(uniform, ty.vec3<f16>()), var, 1_u)));
@@ -1094,7 +1098,7 @@
   return matrix<float16_t, 2, 3>(v_9, tint_bitcast_to_f16_1(((((((8u + start_byte_offset) & 15u) >> 2u) == 2u)) ? (v_10.zw) : (v_10.xy))).xyz);
 }
 
-void foo() {
+void main() {
   matrix<float16_t, 2, 3> a = v_7(0u);
   vector<float16_t, 3> b = tint_bitcast_to_f16_1(v[0u].zw).xyz;
   float16_t c = tint_bitcast_to_f16(v[0u].w).x;
@@ -1107,7 +1111,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("a", b.Load(var));
         b.Let("b", b.Load(b.Access(ty.ptr<uniform, vec2<f32>, core::Access::kRead>(), var, 1_u)));
@@ -1130,7 +1134,7 @@
   return float3x2(v_3, v_5, asfloat(((((((16u + start_byte_offset) & 15u) >> 2u) == 2u)) ? (v_6.zw) : (v_6.xy))));
 }
 
-void foo() {
+void main() {
   float3x2 a = v_1(0u);
   float2 b = asfloat(v[0u].zw);
   float c = asfloat(v[0u].w);
@@ -1144,7 +1148,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("a", b.Load(var));
         b.Let("b", b.Load(b.Access(ty.ptr<uniform, vec2<f32>, core::Access::kRead>(), var, 1_u)));
@@ -1165,7 +1169,7 @@
   return float2x2(v_3, asfloat(((((((8u + start_byte_offset) & 15u) >> 2u) == 2u)) ? (v_4.zw) : (v_4.xy))));
 }
 
-void foo() {
+void main() {
   float2x2 a = v_1(0u);
   float2 b = asfloat(v[0u].zw);
   float c = asfloat(v[0u].w);
@@ -1179,7 +1183,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("a", b.Load(var));
         b.Let("b", b.Load(b.Access(ty.ptr<uniform, vec2<f16>, core::Access::kRead>(), var, 1_u)));
@@ -1206,7 +1210,7 @@
   return matrix<float16_t, 2, 2>(v_4, tint_bitcast_to_f16(v[((4u + start_byte_offset) / 16u)][(((4u + start_byte_offset) & 15u) >> 2u)]));
 }
 
-void foo() {
+void main() {
   matrix<float16_t, 2, 2> a = v_3(0u);
   vector<float16_t, 2> b = tint_bitcast_to_f16(v[0u].y);
   float16_t c = tint_bitcast_to_f16(v[0u].y).y;
@@ -1220,7 +1224,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("a", b.Load(var));
         b.Let("b", b.Load(b.Access(ty.ptr<uniform, vec3<f32>, core::Access::kRead>(), var, 3_u)));
@@ -1254,7 +1258,7 @@
   return v_4;
 }
 
-void foo() {
+void main() {
   float3 a[5] = v_1(0u);
   float3 b = asfloat(v[3u].xyz);
 }
@@ -1267,7 +1271,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("a", b.Load(var));
         b.Let("b", b.Load(b.Access(ty.ptr<uniform, vec3<f16>, core::Access::kRead>(), var, 3_u)));
@@ -1314,7 +1318,7 @@
   return v_9;
 }
 
-void foo() {
+void main() {
   vector<float16_t, 3> a[5] = v_5(0u);
   vector<float16_t, 3> b = tint_bitcast_to_f16(v[1u].zw).xyz;
 }
@@ -1327,7 +1331,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("a", b.Load(var));
         b.Let("b", b.Load(b.Access(ty.ptr<uniform, vec3<f32>, core::Access::kRead>(), var, 3_u)));
@@ -1361,7 +1365,7 @@
   return v_4;
 }
 
-void foo() {
+void main() {
   float3 a[42] = v_1(0u);
   float3 b = asfloat(v[3u].xyz);
 }
@@ -1379,7 +1383,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("a", b.Load(var));
         b.Let("b", b.Load(b.Access(ty.ptr<uniform, f32, core::Access::kRead>(), var, 1_u)));
@@ -1401,7 +1405,7 @@
   return v_2;
 }
 
-void foo() {
+void main() {
   SB a = v_1(0u);
   float b = asfloat(v[0u].y);
 }
@@ -1419,7 +1423,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("a", b.Load(var));
         b.Let("b", b.Load(b.Access(ty.ptr<uniform, f16, core::Access::kRead>(), var, 1_u)));
@@ -1452,7 +1456,7 @@
   return v_7;
 }
 
-void foo() {
+void main() {
   SB a = v_3(0u);
   float16_t b = tint_bitcast_to_f16(v[0u].y).x;
 }
@@ -1480,7 +1484,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("a", b.Load(var));
         b.Let("b", b.LoadVectorElement(b.Access(ty.ptr<uniform, vec3<f32>, core::Access::kRead>(),
@@ -1556,7 +1560,7 @@
   return v_17;
 }
 
-void foo() {
+void main() {
   SB a = v_14(0u);
   float b = asfloat(v[8u].z);
 }
@@ -1569,7 +1573,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Store(var, 2_f);
         b.Return(func);
@@ -1578,7 +1582,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   v.Store(0u, asuint(2.0f));
 }
 
@@ -1590,7 +1594,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Store(var, 2_h);
         b.Return(func);
@@ -1599,7 +1603,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   v.Store<float16_t>(0u, float16_t(2.0h));
 }
 
@@ -1611,7 +1615,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.StoreVectorElement(var, 1_u, 2_f);
         b.Return(func);
@@ -1620,7 +1624,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   v.Store(4u, asuint(2.0f));
 }
 
@@ -1632,7 +1636,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.StoreVectorElement(var, 1_u, 2_h);
         b.Return(func);
@@ -1641,7 +1645,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   v.Store<float16_t>(2u, float16_t(2.0h));
 }
 
@@ -1653,7 +1657,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Store(var, b.Composite(ty.vec3<f32>(), 2_f, 3_f, 4_f));
         b.Return(func);
@@ -1662,7 +1666,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   v.Store3(0u, asuint(float3(2.0f, 3.0f, 4.0f)));
 }
 
@@ -1674,7 +1678,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Store(var, b.Composite(ty.vec3<f16>(), 2_h, 3_h, 4_h));
         b.Return(func);
@@ -1683,7 +1687,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   v.Store<vector<float16_t, 3> >(0u, vector<float16_t, 3>(float16_t(2.0h), float16_t(3.0h), float16_t(4.0h)));
 }
 
@@ -1695,7 +1699,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.StoreVectorElement(
             b.Access(ty.ptr<storage, vec4<f32>, core::Access::kReadWrite>(), var, 1_u), 2_u, 5_f);
@@ -1705,7 +1709,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   v.Store(24u, asuint(5.0f));
 }
 
@@ -1717,7 +1721,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.StoreVectorElement(
             b.Access(ty.ptr<storage, vec2<f16>, core::Access::kReadWrite>(), var, 2_u), 1_u, 5_h);
@@ -1727,7 +1731,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   v.Store<float16_t>(10u, float16_t(5.0h));
 }
 
@@ -1739,7 +1743,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Store(b.Access(ty.ptr<storage, vec4<f32>, core::Access::kReadWrite>(), var, 1_u),
                 b.Splat<vec4<f32>>(5_f));
@@ -1749,7 +1753,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   v.Store4(16u, asuint((5.0f).xxxx));
 }
 
@@ -1761,7 +1765,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Store(b.Access(ty.ptr<storage, vec3<f16>, core::Access::kReadWrite>(), var, 1_u),
                 b.Splat<vec3<f16>>(5_h));
@@ -1771,7 +1775,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   v.Store<vector<float16_t, 3> >(8u, (float16_t(5.0h)).xxx);
 }
 
@@ -1783,7 +1787,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Store(var, b.Zero<mat4x4<f32>>());
         b.Return(func);
@@ -1799,7 +1803,7 @@
   v.Store4((offset + 48u), asuint(obj[3u]));
 }
 
-void foo() {
+void main() {
   v_1(0u, float4x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx));
 }
 
@@ -1811,7 +1815,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Store(var, b.Zero<mat4x4<f16>>());
         b.Return(func);
@@ -1827,7 +1831,7 @@
   v.Store<vector<float16_t, 4> >((offset + 24u), obj[3u]);
 }
 
-void foo() {
+void main() {
   v_1(0u, matrix<float16_t, 4, 4>((float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx));
 }
 
@@ -1839,7 +1843,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Store(b.Access(ty.ptr<storage, f32, core::Access::kReadWrite>(), var, 3_u), 1_f);
         b.Return(func);
@@ -1848,7 +1852,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   v.Store(12u, asuint(1.0f));
 }
 
@@ -1860,7 +1864,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Store(b.Access(ty.ptr<storage, f16, core::Access::kReadWrite>(), var, 3_u), 1_h);
         b.Return(func);
@@ -1869,7 +1873,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   v.Store<float16_t>(6u, float16_t(1.0h));
 }
 
@@ -1881,7 +1885,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* ary = b.Let("ary", b.Zero<array<vec3<f32>, 5>>());
         b.Store(var, ary);
@@ -1909,7 +1913,7 @@
   }
 }
 
-void foo() {
+void main() {
   float3 ary[5] = (float3[5])0;
   v_1(0u, ary);
 }
@@ -1927,7 +1931,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Store(b.Access(ty.ptr<storage, f32, core::Access::kReadWrite>(), var, 1_u), 3_f);
         b.Return(func);
@@ -1936,7 +1940,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   v.Store(4u, asuint(3.0f));
 }
 
@@ -1953,7 +1957,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Store(b.Access(ty.ptr<storage, f16, core::Access::kReadWrite>(), var, 1_u), 3_h);
         b.Return(func);
@@ -1962,7 +1966,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   v.Store<float16_t>(4u, float16_t(3.0h));
 }
 
@@ -1989,7 +1993,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Store(b.Access(ty.ptr<storage, f32, core::Access::kReadWrite>(), var, 1_u, 0_u), 2_f);
         b.Return(func);
@@ -1998,7 +2002,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   v.Store(16u, asuint(2.0f));
 }
 
@@ -2024,7 +2028,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* s = b.Let("s", b.Zero(SB));
         b.Store(var, s);
@@ -2066,7 +2070,7 @@
   v_2((offset + 16u), v_5);
 }
 
-void foo() {
+void main() {
   SB s = (SB)0;
   v_4(0u, s);
 }
@@ -2094,7 +2098,7 @@
     var->SetBindingPoint(0, 0);
 
     b.ir.root_block->Append(var);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* s = b.Let("s", b.Zero(SB));
         b.Store(var, s);
@@ -2161,7 +2165,7 @@
   v_7((offset + 16u), v_10);
 }
 
-void foo() {
+void main() {
   SB s = (SB)0;
   v_9(0u, s);
 }
@@ -2179,7 +2183,7 @@
     var->SetBindingPoint(0, 0);
     b.ir.root_block->Append(var);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* x = b.Access(ty.ptr(storage, ty.vec3<f32>(), core::Access::kReadWrite), var, 1_u);
         b.Let("b", b.LoadVectorElement(x, 1_u));
@@ -2190,7 +2194,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   float b = asfloat(v.Load(20u));
   float c = asfloat(v.Load(24u));
 }
@@ -2208,7 +2212,7 @@
     var->SetBindingPoint(0, 0);
     b.ir.root_block->Append(var);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* x = b.Access(ty.ptr(uniform, ty.vec3<f32>(), core::Access::kRead), var, 1_u);
         b.Let("b", b.LoadVectorElement(x, 1_u));
@@ -2221,7 +2225,7 @@
 cbuffer cbuffer_v : register(b0) {
   uint4 v[2];
 };
-void foo() {
+void main() {
   float b = asfloat(v[1u].y);
   float c = asfloat(v[1u].z);
 }
@@ -2243,7 +2247,7 @@
     b.ir.root_block->Append(vec2_u32);
     b.ir.root_block->Append(vec4_f16);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("a",
               b.Load(b.Access(ty.ptr<storage, vec3<f32>, core::Access::kReadWrite>(), arr, 3_u)));
@@ -2260,6 +2264,7 @@
     });
 
     Options options;
+    options.entry_point_name = "main";
     options.array_offset_from_uniform.ubo_binding = {11, 12};
     options.array_offset_from_uniform.bindpoint_to_offset_index[{1, 2}] = 3;
     options.array_offset_from_uniform.bindpoint_to_offset_index[{1, 3}] = 4;
@@ -2272,7 +2277,7 @@
 cbuffer cbuffer_tint_storage_buffer_dynamic_offsets : register(b12, space11) {
   uint4 tint_storage_buffer_dynamic_offsets[2];
 };
-void foo() {
+void main() {
   float3 a = asfloat(array_1.Load3((48u + tint_storage_buffer_dynamic_offsets[0u].w)));
   array_1.Store3((80u + tint_storage_buffer_dynamic_offsets[0u].w), asuint((0.0f).xxx));
   uint b = vec2_u32.Load((4u + tint_storage_buffer_dynamic_offsets[1u].x));
diff --git a/src/tint/lang/hlsl/writer/arraylength_test.cc b/src/tint/lang/hlsl/writer/arraylength_test.cc
index 8e8be5d..6b4c9ee 100644
--- a/src/tint/lang/hlsl/writer/arraylength_test.cc
+++ b/src/tint/lang/hlsl/writer/arraylength_test.cc
@@ -43,7 +43,7 @@
     sb->SetBindingPoint(0, 0);
     b.ir.root_block->Append(sb);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("len", b.Call(ty.u32(), core::BuiltinFn::kArrayLength, sb));
         b.Return(func);
@@ -52,7 +52,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer sb : register(u0);
-void foo() {
+void main() {
   uint v = 0u;
   sb.GetDimensions(v);
   uint len = (v / 4u);
@@ -72,7 +72,7 @@
     sb->SetBindingPoint(0, 0);
     b.ir.root_block->Append(sb);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("len", b.Call(ty.u32(), core::BuiltinFn::kArrayLength,
                             b.Access(ty.ptr<storage, array<i32>>(), sb, 1_u)));
@@ -82,7 +82,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer sb : register(u0);
-void foo() {
+void main() {
   uint v = 0u;
   sb.GetDimensions(v);
   uint len = ((v - 4u) / 4u);
@@ -100,7 +100,7 @@
     sb->SetBindingPoint(0, 0);
     b.ir.root_block->Append(sb);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("len", b.Call(ty.u32(), core::BuiltinFn::kArrayLength, sb));
         b.Return(func);
@@ -109,7 +109,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 ByteAddressBuffer sb : register(t0);
-void foo() {
+void main() {
   uint v = 0u;
   sb.GetDimensions(v);
   uint len = (v / 4u);
@@ -126,7 +126,7 @@
     sb->SetBindingPoint(0, 0);
     b.ir.root_block->Append(sb);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("len", b.Call(ty.u32(), core::BuiltinFn::kArrayLength, sb));
         b.Return(func);
@@ -135,7 +135,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer sb : register(u0);
-void foo() {
+void main() {
   uint v = 0u;
   sb.GetDimensions(v);
   uint len = (v / 16u);
@@ -149,7 +149,7 @@
     sb->SetBindingPoint(0, 0);
     b.ir.root_block->Append(sb);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("a", b.Call(ty.u32(), core::BuiltinFn::kArrayLength, sb));
         b.Let("b", b.Call(ty.u32(), core::BuiltinFn::kArrayLength, sb));
@@ -160,7 +160,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer sb : register(u0);
-void foo() {
+void main() {
   uint v = 0u;
   sb.GetDimensions(v);
   uint a = (v / 4u);
@@ -198,7 +198,7 @@
     sb3->SetBindingPoint(0, 2);
     b.ir.root_block->Append(sb3);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("len1", b.Call(ty.u32(), core::BuiltinFn::kArrayLength,
                              b.Access(ty.ptr<storage, array<i32>>(), sb1, 1_u)));
@@ -213,7 +213,7 @@
 RWByteAddressBuffer sb1 : register(u0);
 RWByteAddressBuffer sb2 : register(u1);
 RWByteAddressBuffer sb3 : register(u2);
-void foo() {
+void main() {
   uint v = 0u;
   sb1.GetDimensions(v);
   uint len1 = ((v - 4u) / 4u);
@@ -232,7 +232,7 @@
     auto* dst = b.Var("dest", ty.ptr(storage, ty.array<u32>()));
     dst->SetBindingPoint(0, 1);
     b.ir.root_block->Append(dst);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* access = b.Access(ty.ptr(storage, ty.u32()), dst, 0_u);
         b.Store(access, 123_u);
@@ -240,11 +240,12 @@
     });
 
     Options options;
+    options.entry_point_name = "main";
     options.disable_robustness = false;
     ASSERT_TRUE(Generate(options)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer dest : register(u1);
-void foo() {
+void main() {
   uint v = 0u;
   dest.GetDimensions(v);
   dest.Store((0u + (min(0u, ((v / 4u) - 1u)) * 4u)), 123u);
@@ -257,7 +258,7 @@
     auto* dst = b.Var("dest", ty.ptr(storage, ty.array<u32>()));
     dst->SetBindingPoint(0, 1);
     b.ir.root_block->Append(dst);
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* access = b.Access(ty.ptr(storage, ty.u32()), dst, 0_u);
         b.Store(access, 123_u);
@@ -265,6 +266,7 @@
     });
 
     Options options;
+    options.entry_point_name = "main";
     options.disable_robustness = false;
     options.array_length_from_uniform.ubo_binding = {30, 0};
     options.array_length_from_uniform.bindpoint_to_size_index[{0, 1}] = 0;
@@ -278,7 +280,7 @@
 cbuffer cbuffer_tint_storage_buffer_sizes : register(b0, space30) {
   uint4 tint_storage_buffer_sizes[1];
 };
-void foo() {
+void main() {
   tint_array_lengths_struct v = {(tint_storage_buffer_sizes[0u].x / 4u)};
   dest.Store((0u + (min(0u, (v.tint_array_length_0_1 - 1u)) * 4u)), 123u);
 }
diff --git a/src/tint/lang/hlsl/writer/binary_test.cc b/src/tint/lang/hlsl/writer/binary_test.cc
index 001de3e..b457d98 100644
--- a/src/tint/lang/hlsl/writer/binary_test.cc
+++ b/src/tint/lang/hlsl/writer/binary_test.cc
@@ -50,7 +50,7 @@
 TEST_P(HlslWriterBinaryU32Test, Emit) {
     auto params = GetParam();
 
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* l = b.Let("left", b.Constant(1_u));
         auto* r = b.Let("right", b.Constant(2_u));
@@ -62,7 +62,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   uint left = 1u;
   uint right = 2u;
   uint val = )" + std::string(params.result) +
@@ -81,7 +81,7 @@
                                          BinaryData{"(left ^ right)", core::BinaryOp::kXor}));
 
 TEST_F(HlslWriterTest, BinaryU32Div) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* l = b.Let("left", b.Constant(1_u));
         auto* r = b.Let("right", b.Constant(2_u));
@@ -97,7 +97,7 @@
 }
 
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   uint left = 1u;
   uint right = 2u;
   uint val = tint_div_u32(left, right);
@@ -107,7 +107,7 @@
 }
 
 TEST_F(HlslWriterTest, BinaryU32Mod) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* l = b.Let("left", b.Constant(1_u));
         auto* r = b.Let("right", b.Constant(2_u));
@@ -124,7 +124,7 @@
 }
 
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   uint left = 1u;
   uint right = 2u;
   uint val = tint_mod_u32(left, right);
@@ -134,7 +134,7 @@
 }
 
 TEST_F(HlslWriterTest, BinaryU32ShiftLeft) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* l = b.Let("left", b.Constant(1_u));
         auto* r = b.Let("right", b.Constant(2_u));
@@ -146,7 +146,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   uint left = 1u;
   uint right = 2u;
   uint val = (left << (right & 31u));
@@ -156,7 +156,7 @@
 }
 
 TEST_F(HlslWriterTest, BinaryU32ShiftRight) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* l = b.Let("left", b.Constant(1_u));
         auto* r = b.Let("right", b.Constant(2_u));
@@ -168,7 +168,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   uint left = 1u;
   uint right = 2u;
   uint val = (left >> (right & 31u));
@@ -181,7 +181,7 @@
 TEST_P(HlslWriterBinaryBoolTest, Emit) {
     auto params = GetParam();
 
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* l = b.Let("left", b.Constant(1_u));
         auto* r = b.Let("right", b.Constant(2_u));
@@ -193,7 +193,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   uint left = 1u;
   uint right = 2u;
   bool val = )" + std::string(params.result) +
@@ -213,7 +213,7 @@
                     BinaryData{"(left >= right)", core::BinaryOp::kGreaterThanEqual}));
 
 TEST_F(HlslWriterTest, BinaryF32Mod) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* left = b.Var("left", ty.ptr<core::AddressSpace::kFunction, f32>());
         auto* right = b.Var("right", ty.ptr<core::AddressSpace::kFunction, f32>());
@@ -229,7 +229,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   float left = 0.0f;
   float right = 0.0f;
   float v = left;
@@ -242,7 +242,7 @@
 }
 
 TEST_F(HlslWriterTest, BinaryF16Mod) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* left = b.Var("left", ty.ptr<core::AddressSpace::kFunction, f16>());
         auto* right = b.Var("right", ty.ptr<core::AddressSpace::kFunction, f16>());
@@ -258,7 +258,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   float16_t left = float16_t(0.0h);
   float16_t right = float16_t(0.0h);
   float16_t v = left;
@@ -271,7 +271,7 @@
 }
 
 TEST_F(HlslWriterTest, BinaryF32ModVec3) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* left = b.Var("left", ty.ptr(core::AddressSpace::kFunction, ty.vec3<f32>()));
         auto* right = b.Var("right", ty.ptr(core::AddressSpace::kFunction, ty.vec3<f32>()));
@@ -287,7 +287,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   float3 left = (0.0f).xxx;
   float3 right = (0.0f).xxx;
   float3 v = left;
@@ -300,7 +300,7 @@
 }
 
 TEST_F(HlslWriterTest, BinaryF16ModVec3) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* left = b.Var("left", ty.ptr(core::AddressSpace::kFunction, ty.vec3<f16>()));
         auto* right = b.Var("right", ty.ptr(core::AddressSpace::kFunction, ty.vec3<f16>()));
@@ -316,7 +316,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   vector<float16_t, 3> left = (float16_t(0.0h)).xxx;
   vector<float16_t, 3> right = (float16_t(0.0h)).xxx;
   vector<float16_t, 3> v = left;
@@ -329,7 +329,7 @@
 }
 
 TEST_F(HlslWriterTest, BinaryBoolAnd) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* left = b.Var("left", ty.ptr(core::AddressSpace::kFunction, ty.bool_()));
         auto* right = b.Var("right", ty.ptr(core::AddressSpace::kFunction, ty.bool_()));
@@ -345,7 +345,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   bool left = false;
   bool right = false;
   bool val = (left & right);
@@ -355,7 +355,7 @@
 }
 
 TEST_F(HlslWriterTest, BinaryBoolOr) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* left = b.Var("left", ty.ptr(core::AddressSpace::kFunction, ty.bool_()));
         auto* right = b.Var("right", ty.ptr(core::AddressSpace::kFunction, ty.bool_()));
@@ -371,7 +371,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   bool left = false;
   bool right = false;
   bool val = (left | right);
@@ -381,7 +381,7 @@
 }
 
 TEST_F(HlslWriterTest, BinaryMulMatVec) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* x = b.Var("x", b.Zero<mat4x4<f32>>());
         auto* y = b.Var("y", b.Zero<vec4<f32>>());
@@ -394,7 +394,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   float4x4 x = float4x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx);
   float4 y = (0.0f).xxxx;
   float4 c = mul(y, x);
@@ -404,7 +404,7 @@
 }
 
 TEST_F(HlslWriterTest, BinaryMulVecMat) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* x = b.Var("x", b.Zero<mat4x4<f32>>());
         auto* y = b.Var("y", b.Zero<vec4<f32>>());
@@ -417,7 +417,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   float4x4 x = float4x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx);
   float4 y = (0.0f).xxxx;
   float4 c = mul(x, y);
@@ -427,7 +427,7 @@
 }
 
 TEST_F(HlslWriterTest, BinaryMulVec4Mat3x4) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* x = b.Var("x", b.Zero<vec4<f32>>());
         auto* y = b.Var("y", b.Zero<mat3x4<f32>>());
@@ -440,7 +440,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   float4 x = (0.0f).xxxx;
   float3x4 y = float3x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx);
   float3 c = mul(y, x);
@@ -450,7 +450,7 @@
 }
 
 TEST_F(HlslWriterTest, BinaryMulMat3x2Vec3) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* x = b.Var("x", b.Zero<mat3x2<f32>>());
         auto* y = b.Var("y", b.Zero<vec3<f32>>());
@@ -463,7 +463,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   float3x2 x = float3x2((0.0f).xx, (0.0f).xx, (0.0f).xx);
   float3 y = (0.0f).xxx;
   float2 c = mul(y, x);
@@ -473,7 +473,7 @@
 }
 
 TEST_F(HlslWriterTest, BinaryMulMatMat) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* x = b.Var("x", b.Zero<mat4x4<f32>>());
         auto* y = b.Var("y", b.Zero<mat4x4<f32>>());
@@ -486,7 +486,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   float4x4 x = float4x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx);
   float4x4 y = float4x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx);
   float4x4 c = mul(y, x);
diff --git a/src/tint/lang/hlsl/writer/bitcast_test.cc b/src/tint/lang/hlsl/writer/bitcast_test.cc
index d23459c..4268eaf 100644
--- a/src/tint/lang/hlsl/writer/bitcast_test.cc
+++ b/src/tint/lang/hlsl/writer/bitcast_test.cc
@@ -39,7 +39,7 @@
 namespace {
 
 TEST_F(HlslWriterTest, BitcastIdentityNumeric) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* a = b.Var("a", 1_i);
         b.Let("bc", b.Bitcast<i32>(b.Load(a)));
@@ -48,7 +48,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   int a = int(1);
   int bc = a;
 }
@@ -57,7 +57,7 @@
 }
 
 TEST_F(HlslWriterTest, BitcastIdentityVec) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* a = b.Var("a", b.Construct<vec2<f32>>(1_f, 2_f));
         b.Let("bc", b.Bitcast<vec2<f32>>(b.Load(a)));
@@ -66,7 +66,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   float2 a = float2(1.0f, 2.0f);
   float2 bc = a;
 }
@@ -75,7 +75,7 @@
 }
 
 TEST_F(HlslWriterTest, BitcastToFloat) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* a = b.Var("a", 1_i);
         b.Let("bc", b.Bitcast<f32>(b.Load(a)));
@@ -84,7 +84,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   int a = int(1);
   float bc = asfloat(a);
 }
@@ -93,7 +93,7 @@
 }
 
 TEST_F(HlslWriterTest, BitcastToInt) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* a = b.Var("a", 1_u);
         b.Let("bc", b.Bitcast<i32>(b.Load(a)));
@@ -102,7 +102,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   uint a = 1u;
   int bc = asint(a);
 }
@@ -111,7 +111,7 @@
 }
 
 TEST_F(HlslWriterTest, BitcastToUint) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* a = b.Var("a", 1_i);
         b.Let("bc", b.Bitcast<u32>(b.Load(a)));
@@ -120,7 +120,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   int a = int(1);
   uint bc = asuint(a);
 }
@@ -129,7 +129,7 @@
 }
 
 TEST_F(HlslWriterTest, BitcastFromVec2F16) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* a = b.Var("a", b.Construct<vec2<f16>>(1_h, 2_h));
         auto* z = b.Load(a);
@@ -156,7 +156,7 @@
   return asint(((r.x & 65535u) | ((r.y & 65535u) << 16u)));
 }
 
-void foo() {
+void main() {
   vector<float16_t, 2> a = vector<float16_t, 2>(float16_t(1.0h), float16_t(2.0h));
   vector<float16_t, 2> v = a;
   int b = tint_bitcast_from_f16(v);
@@ -168,7 +168,7 @@
 }
 
 TEST_F(HlslWriterTest, BitcastToVec2F16) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* a = b.Var("a", 1_i);
         b.Let("b", b.Bitcast<vec2<f16>>(b.Load(a)));
@@ -207,7 +207,7 @@
   return vector<float16_t, 2>(v_3, float16_t(t_high));
 }
 
-void foo() {
+void main() {
   int a = int(1);
   vector<float16_t, 2> b = tint_bitcast_to_f16(a);
   float c = 1.0f;
@@ -220,7 +220,7 @@
 }
 
 TEST_F(HlslWriterTest, BitcastFromVec4F16) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* a = b.Var("a", b.Construct<vec4<f16>>(1_h, 2_h, 3_h, 4_h));
         auto* z = b.Load(a);
@@ -247,7 +247,7 @@
   return asint(uint2(((r.x & 65535u) | ((r.y & 65535u) << 16u)), ((r.z & 65535u) | ((r.w & 65535u) << 16u))));
 }
 
-void foo() {
+void main() {
   vector<float16_t, 4> a = vector<float16_t, 4>(float16_t(1.0h), float16_t(2.0h), float16_t(3.0h), float16_t(4.0h));
   vector<float16_t, 4> v = a;
   int2 b = tint_bitcast_from_f16(v);
@@ -259,7 +259,7 @@
 }
 
 TEST_F(HlslWriterTest, BitcastToVec4F16) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* a = b.Var("a", b.Construct<vec2<i32>>(1_i, 2_i));
         b.Let("b", b.Bitcast<vec4<f16>>(b.Load(a)));
@@ -310,7 +310,7 @@
   return vector<float16_t, 4>(v_7, v_8, v_9, float16_t(t_high.y));
 }
 
-void foo() {
+void main() {
   int2 a = int2(int(1), int(2));
   vector<float16_t, 4> b = tint_bitcast_to_f16(a);
   float2 c = float2(1.0f, 2.0f);
diff --git a/src/tint/lang/hlsl/writer/builtin_test.cc b/src/tint/lang/hlsl/writer/builtin_test.cc
index 66d70be..387ffe8 100644
--- a/src/tint/lang/hlsl/writer/builtin_test.cc
+++ b/src/tint/lang/hlsl/writer/builtin_test.cc
@@ -48,7 +48,7 @@
 namespace {
 
 TEST_F(HlslWriterTest, BuiltinSelectScalar) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* x = b.Let("x", 1_i);
         auto* y = b.Let("y", 2_i);
@@ -60,7 +60,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   int x = int(1);
   int y = int(2);
   int w = ((true) ? (y) : (x));
@@ -70,7 +70,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinSelectVector) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* x = b.Let("x", b.Construct<vec2<i32>>(1_i, 2_i));
         auto* y = b.Let("y", b.Construct<vec2<i32>>(3_i, 4_i));
@@ -83,7 +83,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   int2 x = int2(int(1), int(2));
   int2 y = int2(int(3), int(4));
   int2 w = ((bool2(true, false)) ? (y) : (x));
@@ -93,7 +93,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinTrunc) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* val = b.Var("v", b.Zero(ty.f32()));
 
@@ -106,7 +106,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   float v = 0.0f;
   float v_1 = v;
   float val = (((v_1 < 0.0f)) ? (ceil(v_1)) : (floor(v_1)));
@@ -116,7 +116,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinTruncVec) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* val = b.Var("v", b.Splat(ty.vec3<f32>(), 2_f));
 
@@ -129,7 +129,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   float3 v = (2.0f).xxx;
   float3 v_1 = v;
   float3 val = (((v_1 < (0.0f).xxx)) ? (ceil(v_1)) : (floor(v_1)));
@@ -139,7 +139,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinTruncF16) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* val = b.Var("v", b.Zero(ty.f16()));
 
@@ -152,7 +152,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   float16_t v = float16_t(0.0h);
   float16_t v_1 = v;
   float16_t val = (((v_1 < float16_t(0.0h))) ? (ceil(v_1)) : (floor(v_1)));
@@ -172,7 +172,7 @@
     var->SetBindingPoint(0, 0);
     b.ir.root_block->Append(var);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Call(ty.void_(), core::BuiltinFn::kAtomicStore,
                b.Access(ty.ptr<storage, atomic<i32>, read_write>(), var, 1_u), 123_i);
@@ -182,7 +182,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   int v_1 = int(0);
   v.InterlockedExchange(int(16u), int(123), v_1);
 }
@@ -195,7 +195,7 @@
     var->SetBindingPoint(0, 0);
     b.ir.root_block->Append(var);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Call(ty.void_(), core::BuiltinFn::kAtomicStore, var, 123_i);
         b.Return(func);
@@ -204,7 +204,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   int v_1 = int(0);
   v.InterlockedExchange(int(0u), int(123), v_1);
 }
@@ -223,7 +223,7 @@
     var->SetBindingPoint(0, 0);
     b.ir.root_block->Append(var);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("x", b.Call(ty.i32(), core::BuiltinFn::kAtomicLoad,
                           b.Access(ty.ptr<storage, atomic<i32>, read_write>(), var, 1_u)));
@@ -233,7 +233,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   int v_1 = int(0);
   v.InterlockedOr(int(16u), int(0), v_1);
   int x = v_1;
@@ -247,7 +247,7 @@
     var->SetBindingPoint(0, 0);
     b.ir.root_block->Append(var);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("x", b.Call(ty.i32(), core::BuiltinFn::kAtomicLoad, var));
         b.Return(func);
@@ -256,7 +256,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   int v_1 = int(0);
   v.InterlockedOr(int(0u), int(0), v_1);
   int x = v_1;
@@ -276,7 +276,7 @@
     var->SetBindingPoint(0, 0);
     b.ir.root_block->Append(var);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("x", b.Call(ty.i32(), core::BuiltinFn::kAtomicSub,
                           b.Access(ty.ptr<storage, atomic<i32>, read_write>(), var, 1_u), 123_i));
@@ -286,7 +286,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   int v_1 = int(0);
   v.InterlockedAdd(int(16u), asint((asuint(int(0)) - asuint(int(123)))), v_1);
   int x = v_1;
@@ -300,7 +300,7 @@
     var->SetBindingPoint(0, 0);
     b.ir.root_block->Append(var);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("x", b.Call(ty.i32(), core::BuiltinFn::kAtomicSub, var, 123_i));
         b.Return(func);
@@ -309,7 +309,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   int v_1 = int(0);
   v.InterlockedAdd(int(0u), asint((asuint(int(0)) - asuint(int(123)))), v_1);
   int x = v_1;
@@ -329,7 +329,7 @@
     var->SetBindingPoint(0, 0);
     b.ir.root_block->Append(var);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("x",
               b.Call(core::type::CreateAtomicCompareExchangeResult(ty, mod.symbols, ty.i32()),
@@ -346,7 +346,7 @@
 
 
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   int v_1 = int(0);
   v.InterlockedCompareExchange(int(16u), int(123), int(345), v_1);
   int v_2 = v_1;
@@ -361,7 +361,7 @@
     var->SetBindingPoint(0, 0);
     b.ir.root_block->Append(var);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("x", b.Call(core::type::CreateAtomicCompareExchangeResult(ty, mod.symbols, ty.i32()),
                           core::BuiltinFn::kAtomicCompareExchangeWeak, var, 123_i, 345_i));
@@ -376,7 +376,7 @@
 
 
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   int v_1 = int(0);
   v.InterlockedCompareExchange(int(0u), int(123), int(345), v_1);
   int v_2 = v_1;
@@ -408,7 +408,7 @@
     var->SetBindingPoint(0, 0);
     b.ir.root_block->Append(var);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("x", b.Call(ty.i32(), param.fn,
                           b.Access(ty.ptr<storage, atomic<i32>, read_write>(), var, 1_u), 123_i));
@@ -418,7 +418,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   int v_1 = int(0);
   v.)" + std::string(param.interlock) +
                                 R"((int(16u), int(123), v_1);
@@ -434,7 +434,7 @@
     var->SetBindingPoint(0, 0);
     b.ir.root_block->Append(var);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("x", b.Call(ty.i32(), param.fn, var, 123_i));
         b.Return(func);
@@ -443,7 +443,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer v : register(u0);
-void foo() {
+void main() {
   int v_1 = int(0);
   v.)" + std::string(param.interlock) +
                                 R"((int(0u), int(123), v_1);
@@ -474,7 +474,7 @@
     auto* var = b.Var("v", workgroup, sb, core::Access::kReadWrite);
     b.ir.root_block->Append(var);
 
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         b.Call(ty.void_(), core::BuiltinFn::kAtomicStore,
                b.Access(ty.ptr<workgroup, atomic<i32>, read_write>(), var, 1_u), 123_i);
@@ -488,13 +488,13 @@
   uint b;
 };
 
-struct foo_inputs {
+struct main_inputs {
   uint tint_local_index : SV_GroupIndex;
 };
 
 
 groupshared SB v;
-void foo_inner(uint tint_local_index) {
+void main_inner(uint tint_local_index) {
   if ((tint_local_index < 1u)) {
     v.padding = (0.0f).xxxx;
     int v_1 = int(0);
@@ -508,8 +508,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void foo(foo_inputs inputs) {
-  foo_inner(inputs.tint_local_index);
+void main(main_inputs inputs) {
+  main_inner(inputs.tint_local_index);
 }
 
 )");
@@ -525,7 +525,7 @@
     auto* var = b.Var("v", workgroup, sb, core::Access::kReadWrite);
     b.ir.root_block->Append(var);
 
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         b.Let("x", b.Call(ty.i32(), core::BuiltinFn::kAtomicLoad,
                           b.Access(ty.ptr<workgroup, atomic<i32>, read_write>(), var, 1_u)));
@@ -539,13 +539,13 @@
   uint b;
 };
 
-struct foo_inputs {
+struct main_inputs {
   uint tint_local_index : SV_GroupIndex;
 };
 
 
 groupshared SB v;
-void foo_inner(uint tint_local_index) {
+void main_inner(uint tint_local_index) {
   if ((tint_local_index < 1u)) {
     v.padding = (0.0f).xxxx;
     int v_1 = int(0);
@@ -560,8 +560,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void foo(foo_inputs inputs) {
-  foo_inner(inputs.tint_local_index);
+void main(main_inputs inputs) {
+  main_inner(inputs.tint_local_index);
 }
 
 )");
@@ -577,7 +577,7 @@
     auto* var = b.Var("v", workgroup, sb, core::Access::kReadWrite);
     b.ir.root_block->Append(var);
 
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         b.Let("x", b.Call(ty.i32(), core::BuiltinFn::kAtomicSub,
                           b.Access(ty.ptr<workgroup, atomic<i32>, read_write>(), var, 1_u), 123_i));
@@ -593,13 +593,13 @@
   uint b;
 };
 
-struct foo_inputs {
+struct main_inputs {
   uint tint_local_index : SV_GroupIndex;
 };
 
 
 groupshared SB v;
-void foo_inner(uint tint_local_index) {
+void main_inner(uint tint_local_index) {
   if ((tint_local_index < 1u)) {
     v.padding = (0.0f).xxxx;
     int v_1 = int(0);
@@ -617,8 +617,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void foo(foo_inputs inputs) {
-  foo_inner(inputs.tint_local_index);
+void main(main_inputs inputs) {
+  main_inner(inputs.tint_local_index);
 }
 
 )");
@@ -634,7 +634,7 @@
     auto* var = b.Var("v", workgroup, sb, core::Access::kReadWrite);
     b.ir.root_block->Append(var);
 
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         b.Let("x", b.Call(core::type::CreateAtomicCompareExchangeResult(ty, mod.symbols, ty.i32()),
                           core::BuiltinFn::kAtomicCompareExchangeWeak,
@@ -655,13 +655,13 @@
   bool exchanged;
 };
 
-struct foo_inputs {
+struct main_inputs {
   uint tint_local_index : SV_GroupIndex;
 };
 
 
 groupshared SB v;
-void foo_inner(uint tint_local_index) {
+void main_inner(uint tint_local_index) {
   if ((tint_local_index < 1u)) {
     v.padding = (0.0f).xxxx;
     int v_1 = int(0);
@@ -677,8 +677,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void foo(foo_inputs inputs) {
-  foo_inner(inputs.tint_local_index);
+void main(main_inputs inputs) {
+  main_inner(inputs.tint_local_index);
 }
 
 )");
@@ -690,7 +690,7 @@
     auto* var = b.Var("v", workgroup, ty.atomic<i32>(), core::Access::kReadWrite);
     b.ir.root_block->Append(var);
 
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
 
     b.Append(func->Block(), [&] {
         b.Let("x", b.Call(ty.i32(), param.fn, var, 123_i));
@@ -698,13 +698,13 @@
     });
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
-    EXPECT_EQ(output_.hlsl, R"(struct foo_inputs {
+    EXPECT_EQ(output_.hlsl, R"(struct main_inputs {
   uint tint_local_index : SV_GroupIndex;
 };
 
 
 groupshared int v;
-void foo_inner(uint tint_local_index) {
+void main_inner(uint tint_local_index) {
   if ((tint_local_index < 1u)) {
     int v_1 = int(0);
     InterlockedExchange(v, int(0), v_1);
@@ -717,8 +717,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void foo(foo_inputs inputs) {
-  foo_inner(inputs.tint_local_index);
+void main(main_inputs inputs) {
+  main_inner(inputs.tint_local_index);
 }
 
 )");
@@ -736,7 +736,7 @@
                                                     "InterlockedExchange"}));
 
 TEST_F(HlslWriterTest, BuiltinSignScalar) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("x", b.Call(ty.f16(), core::BuiltinFn::kSign, 1_h));
         b.Return(func);
@@ -744,7 +744,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   float16_t x = float16_t(sign(float16_t(1.0h)));
 }
 
@@ -752,7 +752,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinSignVector) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("x", b.Call(ty.vec3<f32>(), core::BuiltinFn::kSign,
                           b.Composite(ty.vec3<f32>(), 1_f, 2_f, 3_f)));
@@ -761,7 +761,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   float3 x = float3(sign(float3(1.0f, 2.0f, 3.0f)));
 }
 
@@ -769,7 +769,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinStorageBarrier) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         b.Call(ty.void_(), core::BuiltinFn::kStorageBarrier);
         b.Return(func);
@@ -778,7 +778,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   DeviceMemoryBarrierWithGroupSync();
 }
 
@@ -786,7 +786,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinTextureBarrier) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         b.Call(ty.void_(), core::BuiltinFn::kTextureBarrier);
         b.Return(func);
@@ -795,7 +795,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   DeviceMemoryBarrierWithGroupSync();
 }
 
@@ -803,7 +803,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinWorkgroupBarrier) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         b.Call(ty.void_(), core::BuiltinFn::kWorkgroupBarrier);
         b.Return(func);
@@ -812,7 +812,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   GroupMemoryBarrierWithGroupSync();
 }
 
@@ -820,18 +820,29 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinTextureNumLevels1D) {
-    auto* t = b.FunctionParam("t", ty.sampled_texture(core::type::TextureDimension::k1d, ty.f32()));
+    auto* st = ty.sampled_texture(core::type::TextureDimension::k1d, ty.f32());
+
+    core::ir::Var* v = b.Var("x", ty.ptr(handle, st));
+    v->SetBindingPoint(0, 0);
+    mod.root_block->Append(v);
 
     auto* func = b.Function("foo", ty.void_());
+    auto* t = b.FunctionParam("t", st);
     func->SetParams({t});
-
     b.Append(func->Block(), [&] {
         b.Let("d", b.Call(ty.u32(), core::BuiltinFn::kTextureNumLevels, t));
         b.Return(func);
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Call(func, b.Load(v));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
+Texture1D<float4> x : register(t0);
 void foo(Texture1D<float4> t) {
   uint2 v = (0u).xx;
   t.GetDimensions(0u, v.x, v.y);
@@ -839,25 +850,37 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  foo(x);
 }
 
 )");
 }
 
 TEST_F(HlslWriterTest, BuiltinTextureNumLevels2D) {
-    auto* t = b.FunctionParam("t", ty.sampled_texture(core::type::TextureDimension::k2d, ty.f32()));
+    auto* st = ty.sampled_texture(core::type::TextureDimension::k2d, ty.f32());
+
+    core::ir::Var* v = b.Var("x", ty.ptr(handle, st));
+    v->SetBindingPoint(0, 0);
+    mod.root_block->Append(v);
 
     auto* func = b.Function("foo", ty.void_());
+    auto* t = b.FunctionParam("t", st);
     func->SetParams({t});
-
     b.Append(func->Block(), [&] {
         b.Let("d", b.Call(ty.u32(), core::BuiltinFn::kTextureNumLevels, t));
         b.Return(func);
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Call(func, b.Load(v));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
+Texture2D<float4> x : register(t0);
 void foo(Texture2D<float4> t) {
   uint3 v = (0u).xxx;
   t.GetDimensions(0u, v.x, v.y, v.z);
@@ -865,25 +888,37 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  foo(x);
 }
 
 )");
 }
 
 TEST_F(HlslWriterTest, BuiltinTextureNumLevels3D) {
-    auto* t = b.FunctionParam("t", ty.sampled_texture(core::type::TextureDimension::k3d, ty.f32()));
+    auto* st = ty.sampled_texture(core::type::TextureDimension::k3d, ty.f32());
+
+    core::ir::Var* v = b.Var("x", ty.ptr(handle, st));
+    v->SetBindingPoint(0, 0);
+    mod.root_block->Append(v);
 
     auto* func = b.Function("foo", ty.void_());
+    auto* t = b.FunctionParam("t", st);
     func->SetParams({t});
-
     b.Append(func->Block(), [&] {
         b.Let("d", b.Call(ty.u32(), core::BuiltinFn::kTextureNumLevels, t));
         b.Return(func);
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Call(func, b.Load(v));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
+Texture3D<float4> x : register(t0);
 void foo(Texture3D<float4> t) {
   uint4 v = (0u).xxxx;
   t.GetDimensions(0u, v.x, v.y, v.z, v.w);
@@ -891,25 +926,37 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  foo(x);
 }
 
 )");
 }
 
 TEST_F(HlslWriterTest, BuiltinTextureDimension1D) {
-    auto* t = b.FunctionParam("t", ty.sampled_texture(core::type::TextureDimension::k1d, ty.f32()));
+    auto* st = ty.sampled_texture(core::type::TextureDimension::k1d, ty.f32());
+
+    core::ir::Var* v = b.Var("x", ty.ptr(handle, st));
+    v->SetBindingPoint(0, 0);
+    mod.root_block->Append(v);
 
     auto* func = b.Function("foo", ty.void_());
+    auto* t = b.FunctionParam("t", st);
     func->SetParams({t});
-
     b.Append(func->Block(), [&] {
         b.Let("d", b.Call(ty.u32(), core::BuiltinFn::kTextureDimensions, t));
         b.Return(func);
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Call(func, b.Load(v));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
+Texture1D<float4> x : register(t0);
 void foo(Texture1D<float4> t) {
   uint v = 0u;
   t.GetDimensions(v);
@@ -917,25 +964,37 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  foo(x);
 }
 
 )");
 }
 
 TEST_F(HlslWriterTest, BuiltinTextureDimension2D) {
-    auto* t = b.FunctionParam("t", ty.sampled_texture(core::type::TextureDimension::k2d, ty.f32()));
+    auto* st = ty.sampled_texture(core::type::TextureDimension::k2d, ty.f32());
+
+    core::ir::Var* v = b.Var("x", ty.ptr(handle, st));
+    v->SetBindingPoint(0, 0);
+    mod.root_block->Append(v);
 
     auto* func = b.Function("foo", ty.void_());
+    auto* t = b.FunctionParam("t", st);
     func->SetParams({t});
-
     b.Append(func->Block(), [&] {
         b.Let("d", b.Call(ty.vec2<u32>(), core::BuiltinFn::kTextureDimensions, t));
         b.Return(func);
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Call(func, b.Load(v));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
+Texture2D<float4> x : register(t0);
 void foo(Texture2D<float4> t) {
   uint2 v = (0u).xx;
   t.GetDimensions(v.x, v.y);
@@ -943,25 +1002,37 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  foo(x);
 }
 
 )");
 }
 
 TEST_F(HlslWriterTest, BuiltinTextureDimension2dLOD) {
-    auto* t = b.FunctionParam("t", ty.sampled_texture(core::type::TextureDimension::k2d, ty.f32()));
+    auto* st = ty.sampled_texture(core::type::TextureDimension::k2d, ty.f32());
+
+    core::ir::Var* v = b.Var("x", ty.ptr(handle, st));
+    v->SetBindingPoint(0, 0);
+    mod.root_block->Append(v);
 
     auto* func = b.Function("foo", ty.void_());
+    auto* t = b.FunctionParam("t", st);
     func->SetParams({t});
-
     b.Append(func->Block(), [&] {
         b.Let("d", b.Call(ty.vec2<u32>(), core::BuiltinFn::kTextureDimensions, t, 1_i));
         b.Return(func);
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Call(func, b.Load(v));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
+Texture2D<float4> x : register(t0);
 void foo(Texture2D<float4> t) {
   uint3 v = (0u).xxx;
   t.GetDimensions(uint(int(1)), v.x, v.y, v.z);
@@ -969,25 +1040,37 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  foo(x);
 }
 
 )");
 }
 
 TEST_F(HlslWriterTest, BuiltinTextureDimension3D) {
-    auto* t = b.FunctionParam("t", ty.sampled_texture(core::type::TextureDimension::k3d, ty.f32()));
+    auto* st = ty.sampled_texture(core::type::TextureDimension::k3d, ty.f32());
+
+    core::ir::Var* v = b.Var("x", ty.ptr(handle, st));
+    v->SetBindingPoint(0, 0);
+    mod.root_block->Append(v);
 
     auto* func = b.Function("foo", ty.void_());
+    auto* t = b.FunctionParam("t", st);
     func->SetParams({t});
-
     b.Append(func->Block(), [&] {
         b.Let("d", b.Call(ty.vec3<u32>(), core::BuiltinFn::kTextureDimensions, t));
         b.Return(func);
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Call(func, b.Load(v));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
+Texture3D<float4> x : register(t0);
 void foo(Texture3D<float4> t) {
   uint3 v = (0u).xxx;
   t.GetDimensions(v.x, v.y, v.z);
@@ -995,26 +1078,37 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  foo(x);
 }
 
 )");
 }
 
 TEST_F(HlslWriterTest, BuiltinTextureLayers2dArray) {
-    auto* t =
-        b.FunctionParam("t", ty.sampled_texture(core::type::TextureDimension::k2dArray, ty.f32()));
+    auto* st = ty.sampled_texture(core::type::TextureDimension::k2dArray, ty.f32());
+
+    core::ir::Var* v = b.Var("x", ty.ptr(handle, st));
+    v->SetBindingPoint(0, 0);
+    mod.root_block->Append(v);
 
     auto* func = b.Function("foo", ty.void_());
+    auto* t = b.FunctionParam("t", st);
     func->SetParams({t});
-
     b.Append(func->Block(), [&] {
         b.Let("d", b.Call(ty.u32(), core::BuiltinFn::kTextureNumLayers, t));
         b.Return(func);
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Call(func, b.Load(v));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
+Texture2DArray<float4> x : register(t0);
 void foo(Texture2DArray<float4> t) {
   uint3 v = (0u).xxx;
   t.GetDimensions(v.x, v.y, v.z);
@@ -1022,26 +1116,37 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  foo(x);
 }
 
 )");
 }
 
 TEST_F(HlslWriterTest, BuiltinTextureNumLayersCubeArray) {
-    auto* t = b.FunctionParam(
-        "t", ty.sampled_texture(core::type::TextureDimension::kCubeArray, ty.f32()));
+    auto* st = ty.sampled_texture(core::type::TextureDimension::kCubeArray, ty.f32());
+
+    core::ir::Var* v = b.Var("x", ty.ptr(handle, st));
+    v->SetBindingPoint(0, 0);
+    mod.root_block->Append(v);
 
     auto* func = b.Function("foo", ty.void_());
+    auto* t = b.FunctionParam("t", st);
     func->SetParams({t});
-
     b.Append(func->Block(), [&] {
         b.Let("d", b.Call(ty.u32(), core::BuiltinFn::kTextureNumLayers, t));
         b.Return(func);
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Call(func, b.Load(v));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
+TextureCubeArray<float4> x : register(t0);
 void foo(TextureCubeArray<float4> t) {
   uint3 v = (0u).xxx;
   t.GetDimensions(v.x, v.y, v.z);
@@ -1049,17 +1154,22 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  foo(x);
 }
 
 )");
 }
 
 TEST_F(HlslWriterTest, BuiltinTextureNumSamples) {
-    auto* t =
-        b.FunctionParam("t", ty.depth_multisampled_texture(core::type::TextureDimension::k2d));
+    auto* ms = ty.depth_multisampled_texture(core::type::TextureDimension::k2d);
+
+    core::ir::Var* v = b.Var("x", ty.ptr(handle, ms));
+    v->SetBindingPoint(0, 0);
+    mod.root_block->Append(v);
 
     auto* func = b.Function("foo", ty.void_());
+    auto* t = b.FunctionParam("t", ms);
     func->SetParams({t});
 
     b.Append(func->Block(), [&] {
@@ -1067,8 +1177,15 @@
         b.Return(func);
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Call(func, b.Load(v));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
+Texture2DMS<float4> x : register(t0);
 void foo(Texture2DMS<float4> t) {
   uint3 v = (0u).xxx;
   t.GetDimensions(v.x, v.y, v.z);
@@ -1076,7 +1193,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  foo(x);
 }
 
 )");
@@ -1088,7 +1206,7 @@
     t->SetBindingPoint(0, 0);
     b.ir.root_block->Append(t);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Value(1_u);
         auto* level = b.Value(3_u);
@@ -1097,11 +1215,12 @@
     });
 
     Options opts;
+    opts.entry_point_name = "main";
     opts.disable_robustness = true;
     ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 Texture1D<float4> v : register(t0);
-void foo() {
+void main() {
   int v_1 = int(1u);
   float4 x = v.Load(int2(v_1, int(3u)));
 }
@@ -1115,7 +1234,7 @@
     t->SetBindingPoint(0, 0);
     b.ir.root_block->Append(t);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Composite(ty.vec2<u32>(), 1_u, 2_u);
         auto* level = b.Value(3_u);
@@ -1124,11 +1243,12 @@
     });
 
     Options opts;
+    opts.entry_point_name = "main";
     opts.disable_robustness = true;
     ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 Texture2D<int4> v : register(t0);
-void foo() {
+void main() {
   int2 v_1 = int2(uint2(1u, 2u));
   int4 x = v.Load(int3(v_1, int(3u)));
 }
@@ -1142,7 +1262,7 @@
     t->SetBindingPoint(0, 0);
     b.ir.root_block->Append(t);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Composite(ty.vec3<i32>(), 1_i, 2_i, 3_i);
         auto* level = b.Value(4_u);
@@ -1151,11 +1271,12 @@
     });
 
     Options opts;
+    opts.entry_point_name = "main";
     opts.disable_robustness = true;
     ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 Texture3D<float4> v : register(t0);
-void foo() {
+void main() {
   float4 x = v.Load(int4(int3(int(1), int(2), int(3)), int(4u)));
 }
 
@@ -1168,7 +1289,7 @@
     t->SetBindingPoint(0, 0);
     b.ir.root_block->Append(t);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Composite(ty.vec2<i32>(), 1_i, 2_i);
         auto* sample_idx = b.Value(3_i);
@@ -1177,11 +1298,12 @@
     });
 
     Options opts;
+    opts.entry_point_name = "main";
     opts.disable_robustness = true;
     ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 Texture2DMS<int4> v : register(t0);
-void foo() {
+void main() {
   int4 x = v.Load(int2(int(1), int(2)), int(3));
 }
 
@@ -1193,7 +1315,7 @@
     t->SetBindingPoint(0, 0);
     b.ir.root_block->Append(t);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<i32>(), b.Value(1_i), b.Value(2_i));
         auto* level = b.Value(3_u);
@@ -1202,11 +1324,12 @@
     });
 
     Options opts;
+    opts.entry_point_name = "main";
     opts.disable_robustness = true;
     ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 Texture2D v : register(t0);
-void foo() {
+void main() {
   int2 v_1 = int2(int(1), int(2));
   float x = v.Load(int3(v_1, int(3u))).x;
 }
@@ -1219,7 +1342,7 @@
     t->SetBindingPoint(0, 0);
     b.ir.root_block->Append(t);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Composite(ty.vec2<i32>(), 1_i, 2_i);
         auto* array_idx = b.Value(3_u);
@@ -1230,11 +1353,12 @@
     });
 
     Options opts;
+    opts.entry_point_name = "main";
     opts.disable_robustness = true;
     ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 Texture2DArray v : register(t0);
-void foo() {
+void main() {
   float x = v.Load(int4(int2(int(1), int(2)), int(3u), int(4))).x;
 }
 
@@ -1247,7 +1371,7 @@
     t->SetBindingPoint(0, 0);
     b.ir.root_block->Append(t);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Composite(ty.vec2<i32>(), 1_i, 2_i);
         auto* sample_idx = b.Value(3_u);
@@ -1256,11 +1380,12 @@
     });
 
     Options opts;
+    opts.entry_point_name = "main";
     opts.disable_robustness = true;
     ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 Texture2DMS<float4> v : register(t0);
-void foo() {
+void main() {
   float x = v.Load(int2(int(1), int(2)), int(3u)).x;
 }
 
@@ -1274,7 +1399,7 @@
     t->SetBindingPoint(0, 0);
     b.ir.root_block->Append(t);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Value(1_i);
         auto* value = b.Composite(ty.vec4<f32>(), .5_f, 0_f, 0_f, 1_f);
@@ -1285,7 +1410,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWTexture1D<float4> v : register(u0);
-void foo() {
+void main() {
   v[int(1)] = float4(0.5f, 0.0f, 0.0f, 1.0f);
 }
 
@@ -1299,7 +1424,7 @@
     t->SetBindingPoint(0, 0);
     b.ir.root_block->Append(t);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Composite(ty.vec3<i32>(), 1_i, 2_i, 3_i);
         auto* value = b.Composite(ty.vec4<f32>(), .5_f, 0_f, 0_f, 1_f);
@@ -1310,7 +1435,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWTexture3D<float4> v : register(u0);
-void foo() {
+void main() {
   v[int3(int(1), int(2), int(3))] = float4(0.5f, 0.0f, 0.0f, 1.0f);
 }
 
@@ -1324,7 +1449,7 @@
     t->SetBindingPoint(0, 0);
     b.ir.root_block->Append(t);
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Composite(ty.vec2<i32>(), 1_i, 2_i);
         auto* value = b.Composite(ty.vec4<f32>(), .5_f, .4_f, .3_f, 1_f);
@@ -1335,7 +1460,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWTexture2DArray<float4> v : register(u0);
-void foo() {
+void main() {
   v[int3(int2(int(1), int(2)), int(3u))] = float4(0.5f, 0.40000000596046447754f, 0.30000001192092895508f, 1.0f);
 }
 
@@ -1353,7 +1478,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* depth_ref = b.Value(3_f);
@@ -1366,12 +1491,13 @@
     });
 
     Options opts;
+    opts.entry_point_name = "main";
     opts.disable_robustness = true;
     ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 Texture2D v : register(t0);
 SamplerComparisonState v_1 : register(s1);
-void foo() {
+void main() {
   float4 x = v.GatherCmp(v_1, float2(1.0f, 2.0f), 3.0f);
 }
 
@@ -1389,7 +1515,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* depth_ref = b.Value(3_f);
@@ -1403,12 +1529,13 @@
     });
 
     Options opts;
+    opts.entry_point_name = "main";
     opts.disable_robustness = true;
     ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 Texture2D v : register(t0);
 SamplerComparisonState v_1 : register(s1);
-void foo() {
+void main() {
   float4 x = v.GatherCmp(v_1, float2(1.0f, 2.0f), 3.0f, int2(int(4), int(5)));
 }
 
@@ -1426,7 +1553,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec3<f32>(), b.Value(1_f), b.Value(2_f), b.Value(2.5_f));
         auto* array_idx = b.Value(6_u);
@@ -1440,12 +1567,13 @@
     });
 
     Options opts;
+    opts.entry_point_name = "main";
     opts.disable_robustness = true;
     ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 TextureCubeArray v : register(t0);
 SamplerComparisonState v_1 : register(s1);
-void foo() {
+void main() {
   float3 v_2 = float3(1.0f, 2.0f, 2.5f);
   float4 x = v.GatherCmp(v_1, float4(v_2, float(6u)), 3.0f);
 }
@@ -1464,7 +1592,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* array_idx = b.Value(6_i);
@@ -1479,12 +1607,13 @@
     });
 
     Options opts;
+    opts.entry_point_name = "main";
     opts.disable_robustness = true;
     ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 Texture2DArray v : register(t0);
 SamplerComparisonState v_1 : register(s1);
-void foo() {
+void main() {
   float2 v_2 = float2(1.0f, 2.0f);
   float4 x = v.GatherCmp(v_1, float3(v_2, float(int(6))), 3.0f, int2(int(4), int(5)));
 }
@@ -1504,7 +1633,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
 
@@ -1515,12 +1644,13 @@
     });
 
     Options opts;
+    opts.entry_point_name = "main";
     opts.disable_robustness = true;
     ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 Texture2D<int4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   int4 x = v.GatherAlpha(v_1, float2(1.0f, 2.0f));
 }
 
@@ -1538,7 +1668,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* offset = b.Composite<vec2<i32>>(1_i, 3_i);
@@ -1550,12 +1680,13 @@
     });
 
     Options opts;
+    opts.entry_point_name = "main";
     opts.disable_robustness = true;
     ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 Texture2D<int4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   int4 x = v.GatherRed(v_1, float2(1.0f, 2.0f), int2(int(1), int(3)));
 }
 
@@ -1573,7 +1704,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* array_idx = b.Value(1_u);
@@ -1586,12 +1717,13 @@
     });
 
     Options opts;
+    opts.entry_point_name = "main";
     opts.disable_robustness = true;
     ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 Texture2DArray<int4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float2 v_2 = float2(1.0f, 2.0f);
   int4 x = v.GatherGreen(v_1, float3(v_2, float(1u)));
 }
@@ -1611,7 +1743,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* array_idx = b.Value(1_i);
@@ -1625,12 +1757,13 @@
     });
 
     Options opts;
+    opts.entry_point_name = "main";
     opts.disable_robustness = true;
     ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 Texture2DArray<int4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float2 v_2 = float2(1.0f, 2.0f);
   int4 x = v.GatherBlue(v_1, float3(v_2, float(int(1))), int2(int(1), int(2)));
 }
@@ -1649,7 +1782,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
 
@@ -1660,12 +1793,13 @@
     });
 
     Options opts;
+    opts.entry_point_name = "main";
     opts.disable_robustness = true;
     ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 Texture2D v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float4 x = v.Gather(v_1, float2(1.0f, 2.0f));
 }
 
@@ -1682,7 +1816,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* offset = b.Composite<vec2<i32>>(3_i, 4_i);
@@ -1694,12 +1828,13 @@
     });
 
     Options opts;
+    opts.entry_point_name = "main";
     opts.disable_robustness = true;
     ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 Texture2D v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float4 x = v.Gather(v_1, float2(1.0f, 2.0f), int2(int(3), int(4)));
 }
 
@@ -1716,7 +1851,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* array_idx = b.Value(4_i);
@@ -1728,12 +1863,13 @@
     });
 
     Options opts;
+    opts.entry_point_name = "main";
     opts.disable_robustness = true;
     ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 Texture2DArray v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float2 v_2 = float2(1.0f, 2.0f);
   float4 x = v.Gather(v_1, float3(v_2, float(int(4))));
 }
@@ -1751,7 +1887,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* array_idx = b.Value(4_u);
@@ -1765,12 +1901,13 @@
     });
 
     Options opts;
+    opts.entry_point_name = "main";
     opts.disable_robustness = true;
     ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 Texture2DArray v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float2 v_2 = float2(1.0f, 2.0f);
   float4 x = v.Gather(v_1, float3(v_2, float(4u)), int2(int(4), int(5)));
 }
@@ -1779,7 +1916,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinQuantizeToF16) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* v = b.Var("x", b.Zero(ty.vec2<f32>()));
         b.Let("a", b.Call(ty.vec2<f32>(), core::BuiltinFn::kQuantizeToF16, b.Load(v)));
@@ -1788,7 +1925,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   float2 x = (0.0f).xx;
   float2 a = f16tof32(f32tof16(x));
 }
@@ -1797,7 +1934,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinPack2x16Float) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", b.Splat(ty.vec2<f32>(), 2_f));
         b.Let("a", b.Call(ty.u32(), core::BuiltinFn::kPack2X16Float, b.Load(u)));
@@ -1806,7 +1943,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   float2 u = (2.0f).xx;
   uint2 v = f32tof16(u);
   uint a = (v.x | (v.y << 16u));
@@ -1816,7 +1953,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinUnpack2x16Float) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", 2_u);
         b.Let("a", b.Call(ty.vec2<f32>(), core::BuiltinFn::kUnpack2X16Float, b.Load(u)));
@@ -1825,7 +1962,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   uint u = 2u;
   uint v = u;
   float2 a = f16tof32(uint2((v & 65535u), (v >> 16u)));
@@ -1835,7 +1972,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinPack2x16Snorm) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", b.Splat(ty.vec2<f32>(), 2_f));
         b.Let("a", b.Call(ty.u32(), core::BuiltinFn::kPack2X16Snorm, b.Load(u)));
@@ -1844,7 +1981,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   float2 u = (2.0f).xx;
   int2 v = (int2(round((clamp(u, (-1.0f).xx, (1.0f).xx) * 32767.0f))) & (int(65535)).xx);
   uint a = asuint((v.x | (v.y << 16u)));
@@ -1854,7 +1991,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinUnpack2x16Snorm) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", 2_u);
         b.Let("a", b.Call(ty.vec2<f32>(), core::BuiltinFn::kUnpack2X16Snorm, b.Load(u)));
@@ -1863,7 +2000,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   uint u = 2u;
   int v = int(u);
   float2 a = clamp((float2((int2((v << 16u), v) >> (16u).xx)) / 32767.0f), (-1.0f).xx, (1.0f).xx);
@@ -1873,7 +2010,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinPack2x16Unorm) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", b.Splat(ty.vec2<f32>(), 2_f));
         b.Let("a", b.Call(ty.u32(), core::BuiltinFn::kPack2X16Unorm, b.Load(u)));
@@ -1882,7 +2019,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   float2 u = (2.0f).xx;
   uint2 v = uint2(round((clamp(u, (0.0f).xx, (1.0f).xx) * 65535.0f)));
   uint a = (v.x | (v.y << 16u));
@@ -1892,7 +2029,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinUnpack2x16Unorm) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", 2_u);
         b.Let("a", b.Call(ty.vec2<f32>(), core::BuiltinFn::kUnpack2X16Unorm, b.Load(u)));
@@ -1901,7 +2038,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   uint u = 2u;
   uint v = u;
   float2 a = (float2(uint2((v & 65535u), (v >> 16u))) / 65535.0f);
@@ -1911,7 +2048,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinPack4x8Snorm) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", b.Splat(ty.vec4<f32>(), 2_f));
         b.Let("a", b.Call(ty.u32(), core::BuiltinFn::kPack4X8Snorm, b.Load(u)));
@@ -1920,7 +2057,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   float4 u = (2.0f).xxxx;
   int4 v = (int4(round((clamp(u, (-1.0f).xxxx, (1.0f).xxxx) * 127.0f))) & (int(255)).xxxx);
   uint a = asuint((v.x | ((v.y << 8u) | ((v.z << 16u) | (v.w << 24u)))));
@@ -1930,7 +2067,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinUnpack4x8Snorm) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", 2_u);
         b.Let("a", b.Call(ty.vec4<f32>(), core::BuiltinFn::kUnpack4X8Snorm, b.Load(u)));
@@ -1939,7 +2076,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   uint u = 2u;
   int v = int(u);
   float4 a = clamp((float4((int4((v << 24u), (v << 16u), (v << 8u), v) >> (24u).xxxx)) / 127.0f), (-1.0f).xxxx, (1.0f).xxxx);
@@ -1949,7 +2086,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinPack4x8Unorm) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", b.Splat(ty.vec4<f32>(), 2_f));
         b.Let("a", b.Call(ty.u32(), core::BuiltinFn::kPack4X8Unorm, b.Load(u)));
@@ -1958,7 +2095,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   float4 u = (2.0f).xxxx;
   uint4 v = uint4(round((clamp(u, (0.0f).xxxx, (1.0f).xxxx) * 255.0f)));
   uint a = (v.x | ((v.y << 8u) | ((v.z << 16u) | (v.w << 24u))));
@@ -1968,7 +2105,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinUnpack4x8Unorm) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", 2_u);
         b.Let("a", b.Call(ty.vec4<f32>(), core::BuiltinFn::kUnpack4X8Unorm, b.Load(u)));
@@ -1977,7 +2114,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   uint u = 2u;
   uint v = u;
   float4 a = (float4(uint4((v & 255u), ((v >> 8u) & 255u), ((v >> 16u) & 255u), (v >> 24u))) / 255.0f);
@@ -1987,7 +2124,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinPack4xI8CorePolyfill) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", b.Splat(ty.vec4<i32>(), 2_i));
         b.Let("a", b.Call(ty.u32(), core::BuiltinFn::kPack4XI8, b.Load(u)));
@@ -1995,10 +2132,11 @@
     });
 
     Options opts{};
+    opts.entry_point_name = "main";
     opts.polyfill_pack_unpack_4x8 = true;
     ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   int4 u = (int(2)).xxxx;
   int4 v = u;
   uint4 v_1 = uint4(0u, 8u, 16u, 24u);
@@ -2010,7 +2148,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinUnpack4xI8CorePolyfill) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", 2_u);
         b.Let("a", b.Call(ty.vec4<i32>(), core::BuiltinFn::kUnpack4XI8, b.Load(u)));
@@ -2018,10 +2156,11 @@
     });
 
     Options opts{};
+    opts.entry_point_name = "main";
     opts.polyfill_pack_unpack_4x8 = true;
     ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   uint u = 2u;
   uint v = u;
   uint4 v_1 = uint4(24u, 16u, 8u, 0u);
@@ -2033,7 +2172,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinPack4xI8) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", b.Splat(ty.vec4<i32>(), 2_i));
         b.Let("a", b.Call(ty.u32(), core::BuiltinFn::kPack4XI8, b.Load(u)));
@@ -2042,7 +2181,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   int4 u = (int(2)).xxxx;
   uint a = uint(pack_s8(u));
 }
@@ -2051,7 +2190,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinUnpack4xI8) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", 2_u);
         b.Let("a", b.Call(ty.vec4<i32>(), core::BuiltinFn::kUnpack4XI8, b.Load(u)));
@@ -2060,7 +2199,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   uint u = 2u;
   int4 a = unpack_s8s32(int8_t4_packed(u));
 }
@@ -2069,7 +2208,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinPack4xU8CorePolyfill) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", b.Splat(ty.vec4<u32>(), 2_u));
         b.Let("a", b.Call(ty.u32(), core::BuiltinFn::kPack4XU8, b.Load(u)));
@@ -2077,10 +2216,11 @@
     });
 
     Options opts{};
+    opts.entry_point_name = "main";
     opts.polyfill_pack_unpack_4x8 = true;
     ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   uint4 u = (2u).xxxx;
   uint4 v = u;
   uint4 v_1 = uint4(0u, 8u, 16u, 24u);
@@ -2092,7 +2232,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinUnpack4xU8CorePolyfill) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", 2_u);
         b.Let("a", b.Call(ty.vec4<u32>(), core::BuiltinFn::kUnpack4XU8, b.Load(u)));
@@ -2100,10 +2240,11 @@
     });
 
     Options opts{};
+    opts.entry_point_name = "main";
     opts.polyfill_pack_unpack_4x8 = true;
     ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   uint u = 2u;
   uint v = u;
   uint4 v_1 = uint4(0u, 8u, 16u, 24u);
@@ -2115,7 +2256,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinPack4xU8) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", b.Splat(ty.vec4<u32>(), 2_u));
         b.Let("a", b.Call(ty.u32(), core::BuiltinFn::kPack4XU8, b.Load(u)));
@@ -2124,7 +2265,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   uint4 u = (2u).xxxx;
   uint a = uint(pack_u8(u));
 }
@@ -2133,7 +2274,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinUnpack4xU8) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", 2_u);
         b.Let("a", b.Call(ty.vec4<u32>(), core::BuiltinFn::kUnpack4XU8, b.Load(u)));
@@ -2142,7 +2283,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   uint u = 2u;
   uint4 a = unpack_u8u32(uint8_t4_packed(u));
 }
@@ -2151,7 +2292,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinDot4U8PackedPolyfill) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", 2_u);
         b.Let("a", b.Call(ty.u32(), core::BuiltinFn::kDot4U8Packed, b.Load(u), u32(3_u)));
@@ -2159,10 +2300,11 @@
     });
 
     Options opts{};
+    opts.entry_point_name = "main";
     opts.polyfill_dot_4x8_packed = true;
     ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   uint u = 2u;
   uint v = u;
   uint4 v_1 = uint4(0u, 8u, 16u, 24u);
@@ -2177,7 +2319,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinDot4U8Packed) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", 2_u);
         b.Let("a", b.Call(ty.u32(), core::BuiltinFn::kDot4U8Packed, b.Load(u), u32(3_u)));
@@ -2186,7 +2328,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   uint u = 2u;
   uint accumulator = 0u;
   uint a = dot4add_u8packed(u, 3u, accumulator);
@@ -2196,7 +2338,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinPack4xU8ClampPolyfill) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", b.Splat(ty.vec4<u32>(), 2_u));
         b.Let("a", b.Call(ty.u32(), core::BuiltinFn::kPack4XU8Clamp, b.Load(u)));
@@ -2205,7 +2347,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   uint4 u = (2u).xxxx;
   uint4 v = u;
   uint4 v_1 = uint4(0u, 8u, 16u, 24u);
@@ -2218,7 +2360,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinPack4xI8ClampPolyfill) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", b.Splat(ty.vec4<i32>(), 2_i));
         b.Let("a", b.Call(ty.u32(), core::BuiltinFn::kPack4XI8Clamp, b.Load(u)));
@@ -2226,10 +2368,11 @@
     });
 
     Options opts{};
+    opts.entry_point_name = "main";
     opts.polyfill_pack_unpack_4x8 = true;
     ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   int4 u = (int(2)).xxxx;
   int4 v = u;
   uint4 v_1 = uint4(0u, 8u, 16u, 24u);
@@ -2243,7 +2386,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinPack4xI8Clamp) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", b.Splat(ty.vec4<i32>(), 2_i));
         b.Let("a", b.Call(ty.u32(), core::BuiltinFn::kPack4XI8Clamp, b.Load(u)));
@@ -2252,7 +2395,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   int4 u = (int(2)).xxxx;
   uint a = uint(pack_clamp_s8(u));
 }
@@ -2261,7 +2404,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinDot4I8PackedPolyfill) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", 2_u);
         b.Let("a", b.Call(ty.i32(), core::BuiltinFn::kDot4I8Packed, b.Load(u), u32(3_u)));
@@ -2269,10 +2412,11 @@
     });
 
     Options opts{};
+    opts.entry_point_name = "main";
     opts.polyfill_dot_4x8_packed = true;
     ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   uint u = 2u;
   uint v = u;
   uint4 v_1 = uint4(24u, 16u, 8u, 0u);
@@ -2287,7 +2431,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinDot4I8Packed) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", 2_u);
         b.Let("a", b.Call(ty.i32(), core::BuiltinFn::kDot4I8Packed, b.Load(u), u32(3_u)));
@@ -2296,7 +2440,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   uint u = 2u;
   int accumulator = int(0);
   int a = dot4add_i8packed(u, 3u, accumulator);
@@ -2306,7 +2450,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinAsinh) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", .25_f);
         b.Let("a", b.Call(ty.f32(), core::BuiltinFn::kAsinh, b.Load(u)));
@@ -2315,7 +2459,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   float u = 0.25f;
   float v = u;
   float a = log((v + sqrt(((v * v) + 1.0f))));
@@ -2325,7 +2469,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinAcosh) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", 1.25_h);
         b.Let("a", b.Call(ty.f16(), core::BuiltinFn::kAcosh, b.Load(u)));
@@ -2334,7 +2478,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   float16_t u = float16_t(1.25h);
   float16_t v = u;
   float16_t a = log((v + sqrt(((v * v) - float16_t(1.0h)))));
@@ -2344,7 +2488,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinAtanh) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* u = b.Var("u", .25_f);
         b.Let("a", b.Call(ty.f32(), core::BuiltinFn::kAtanh, b.Load(u)));
@@ -2353,7 +2497,7 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   float u = 0.25f;
   float v = u;
   float a = (log(((1.0f + v) / (1.0f - v))) * 0.5f);
@@ -2363,7 +2507,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinSubgroupBallot) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
 
     b.Append(func->Block(), [&] {
         b.Let("x", b.Call(ty.vec4<u32>(), core::BuiltinFn::kSubgroupBallot, true));
@@ -2373,7 +2517,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   uint4 x = WaveActiveBallot(true);
 }
 
@@ -2392,7 +2536,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Value(1_f);
 
@@ -2406,7 +2550,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture1D<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float4 x = v.Sample(v_1, 1.0f);
 }
 
@@ -2425,7 +2569,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
 
@@ -2439,7 +2583,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2D<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float4 x = v.Sample(v_1, float2(1.0f, 2.0f));
 }
 
@@ -2458,7 +2602,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* offset = b.Composite<vec2<i32>>(4_i, 5_i);
@@ -2473,7 +2617,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2D<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float4 x = v.Sample(v_1, float2(1.0f, 2.0f), int2(int(4), int(5)));
 }
 
@@ -2492,7 +2636,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* array_idx = b.Value(4_u);
@@ -2507,7 +2651,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2DArray<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float2 v_2 = float2(1.0f, 2.0f);
   float4 x = v.Sample(v_1, float3(v_2, float(4u)));
 }
@@ -2527,7 +2671,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* array_idx = b.Value(4_u);
@@ -2544,7 +2688,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2DArray<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float2 v_2 = float2(1.0f, 2.0f);
   float4 x = v.Sample(v_1, float3(v_2, float(4u)), int2(int(4), int(5)));
 }
@@ -2564,7 +2708,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec3<f32>(), b.Value(1_f), b.Value(2_f), b.Value(3_f));
 
@@ -2578,7 +2722,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture3D<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float4 x = v.Sample(v_1, float3(1.0f, 2.0f, 3.0f));
 }
 
@@ -2597,7 +2741,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec3<f32>(), b.Value(1_f), b.Value(2_f), b.Value(3_f));
         auto* offset = b.Composite<vec3<i32>>(4_i, 5_i, 6_i);
@@ -2612,7 +2756,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture3D<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float4 x = v.Sample(v_1, float3(1.0f, 2.0f, 3.0f), int3(int(4), int(5), int(6)));
 }
 
@@ -2631,7 +2775,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec3<f32>(), b.Value(1_f), b.Value(2_f), b.Value(3_f));
 
@@ -2645,7 +2789,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 TextureCube<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float4 x = v.Sample(v_1, float3(1.0f, 2.0f, 3.0f));
 }
 
@@ -2664,7 +2808,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec3<f32>(), b.Value(1_f), b.Value(2_f), b.Value(3_f));
         auto* array_idx = b.Value(4_u);
@@ -2679,7 +2823,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 TextureCubeArray<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float3 v_2 = float3(1.0f, 2.0f, 3.0f);
   float4 x = v.Sample(v_1, float4(v_2, float(4u)));
 }
@@ -2699,7 +2843,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
 
@@ -2713,7 +2857,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2D<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float4 x = v.SampleBias(v_1, float2(1.0f, 2.0f), clamp(3.0f, -16.0f, 15.9899997711181640625f));
 }
 
@@ -2732,7 +2876,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* offset = b.Composite<vec2<i32>>(4_i, 5_i);
@@ -2748,7 +2892,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2D<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float4 x = v.SampleBias(v_1, float2(1.0f, 2.0f), clamp(3.0f, -16.0f, 15.9899997711181640625f), int2(int(4), int(5)));
 }
 
@@ -2767,7 +2911,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* array_idx = b.Value(4_u);
@@ -2783,7 +2927,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2DArray<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float2 v_2 = float2(1.0f, 2.0f);
   float4 x = v.SampleBias(v_1, float3(v_2, float(4u)), clamp(3.0f, -16.0f, 15.9899997711181640625f));
 }
@@ -2803,7 +2947,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* array_idx = b.Value(4_u);
@@ -2820,7 +2964,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2DArray<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float2 v_2 = float2(1.0f, 2.0f);
   float4 x = v.SampleBias(v_1, float3(v_2, float(4u)), clamp(3.0f, -16.0f, 15.9899997711181640625f), int2(int(4), int(5)));
 }
@@ -2840,7 +2984,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec3<f32>(), b.Value(1_f), b.Value(2_f), b.Value(3_f));
 
@@ -2854,7 +2998,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture3D<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float4 x = v.SampleBias(v_1, float3(1.0f, 2.0f, 3.0f), clamp(3.0f, -16.0f, 15.9899997711181640625f));
 }
 
@@ -2873,7 +3017,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec3<f32>(), b.Value(1_f), b.Value(2_f), b.Value(3_f));
         auto* offset = b.Composite<vec3<i32>>(4_i, 5_i, 6_i);
@@ -2889,7 +3033,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture3D<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float4 x = v.SampleBias(v_1, float3(1.0f, 2.0f, 3.0f), clamp(3.0f, -16.0f, 15.9899997711181640625f), int3(int(4), int(5), int(6)));
 }
 
@@ -2908,7 +3052,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec3<f32>(), b.Value(1_f), b.Value(2_f), b.Value(3_f));
 
@@ -2922,7 +3066,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 TextureCube<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float4 x = v.SampleBias(v_1, float3(1.0f, 2.0f, 3.0f), clamp(3.0f, -16.0f, 15.9899997711181640625f));
 }
 
@@ -2941,7 +3085,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec3<f32>(), b.Value(1_f), b.Value(2_f), b.Value(3_f));
         auto* array_idx = b.Value(4_u);
@@ -2957,7 +3101,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 TextureCubeArray<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float3 v_2 = float3(1.0f, 2.0f, 3.0f);
   float4 x = v.SampleBias(v_1, float4(v_2, float(4u)), clamp(3.0f, -16.0f, 15.9899997711181640625f));
 }
@@ -2976,7 +3120,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
 
@@ -2990,7 +3134,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2D v : register(t0);
 SamplerComparisonState v_1 : register(s1);
-void foo() {
+void main() {
   float x = v.SampleCmp(v_1, float2(1.0f, 2.0f), 3.0f);
 }
 
@@ -3008,7 +3152,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* offset = b.Composite<vec2<i32>>(4_i, 5_i);
@@ -3023,7 +3167,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2D v : register(t0);
 SamplerComparisonState v_1 : register(s1);
-void foo() {
+void main() {
   float x = v.SampleCmp(v_1, float2(1.0f, 2.0f), 3.0f, int2(int(4), int(5)));
 }
 
@@ -3041,7 +3185,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* array_idx = b.Value(4_u);
@@ -3057,7 +3201,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2DArray v : register(t0);
 SamplerComparisonState v_1 : register(s1);
-void foo() {
+void main() {
   float2 v_2 = float2(1.0f, 2.0f);
   float x = v.SampleCmp(v_1, float3(v_2, float(4u)), 3.0f);
 }
@@ -3076,7 +3220,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* array_idx = b.Value(4_u);
@@ -3093,7 +3237,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2DArray v : register(t0);
 SamplerComparisonState v_1 : register(s1);
-void foo() {
+void main() {
   float2 v_2 = float2(1.0f, 2.0f);
   float x = v.SampleCmp(v_1, float3(v_2, float(4u)), 3.0f, int2(int(4), int(5)));
 }
@@ -3112,7 +3256,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec3<f32>(), b.Value(1_f), b.Value(2_f), b.Value(3_f));
 
@@ -3126,7 +3270,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 TextureCube v : register(t0);
 SamplerComparisonState v_1 : register(s1);
-void foo() {
+void main() {
   float x = v.SampleCmp(v_1, float3(1.0f, 2.0f, 3.0f), 3.0f);
 }
 
@@ -3144,7 +3288,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec3<f32>(), b.Value(1_f), b.Value(2_f), b.Value(3_f));
         auto* array_idx = b.Value(4_u);
@@ -3160,7 +3304,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 TextureCubeArray v : register(t0);
 SamplerComparisonState v_1 : register(s1);
-void foo() {
+void main() {
   float3 v_2 = float3(1.0f, 2.0f, 3.0f);
   float x = v.SampleCmp(v_1, float4(v_2, float(4u)), 3.0f);
 }
@@ -3179,7 +3323,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
 
@@ -3193,7 +3337,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2D v : register(t0);
 SamplerComparisonState v_1 : register(s1);
-void foo() {
+void main() {
   float x = v.SampleCmpLevelZero(v_1, float2(1.0f, 2.0f), 3.0f);
 }
 
@@ -3211,7 +3355,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* offset = b.Composite<vec2<i32>>(4_i, 5_i);
@@ -3227,7 +3371,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2D v : register(t0);
 SamplerComparisonState v_1 : register(s1);
-void foo() {
+void main() {
   float x = v.SampleCmpLevelZero(v_1, float2(1.0f, 2.0f), 3.0f, int2(int(4), int(5)));
 }
 
@@ -3245,7 +3389,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* array_idx = b.Value(4_u);
@@ -3261,7 +3405,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2DArray v : register(t0);
 SamplerComparisonState v_1 : register(s1);
-void foo() {
+void main() {
   float2 v_2 = float2(1.0f, 2.0f);
   float x = v.SampleCmpLevelZero(v_1, float3(v_2, float(4u)), 3.0f);
 }
@@ -3280,7 +3424,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* array_idx = b.Value(4_u);
@@ -3297,7 +3441,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2DArray v : register(t0);
 SamplerComparisonState v_1 : register(s1);
-void foo() {
+void main() {
   float2 v_2 = float2(1.0f, 2.0f);
   float x = v.SampleCmpLevelZero(v_1, float3(v_2, float(4u)), 3.0f, int2(int(4), int(5)));
 }
@@ -3316,7 +3460,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec3<f32>(), b.Value(1_f), b.Value(2_f), b.Value(3_f));
 
@@ -3330,7 +3474,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 TextureCube v : register(t0);
 SamplerComparisonState v_1 : register(s1);
-void foo() {
+void main() {
   float x = v.SampleCmpLevelZero(v_1, float3(1.0f, 2.0f, 3.0f), 3.0f);
 }
 
@@ -3348,7 +3492,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec3<f32>(), b.Value(1_f), b.Value(2_f), b.Value(3_f));
         auto* array_idx = b.Value(4_u);
@@ -3364,7 +3508,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 TextureCubeArray v : register(t0);
 SamplerComparisonState v_1 : register(s1);
-void foo() {
+void main() {
   float3 v_2 = float3(1.0f, 2.0f, 3.0f);
   float x = v.SampleCmpLevelZero(v_1, float4(v_2, float(4u)), 3.0f);
 }
@@ -3384,7 +3528,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* ddx = b.Construct(ty.vec2<f32>(), b.Value(3_f), b.Value(4_f));
@@ -3400,7 +3544,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2D<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float2 v_2 = float2(1.0f, 2.0f);
   float2 v_3 = float2(3.0f, 4.0f);
   float4 x = v.SampleGrad(v_1, v_2, v_3, float2(5.0f, 6.0f));
@@ -3421,7 +3565,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* ddx = b.Construct(ty.vec2<f32>(), b.Value(3_f), b.Value(4_f));
@@ -3439,7 +3583,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2D<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float2 v_2 = float2(1.0f, 2.0f);
   float2 v_3 = float2(3.0f, 4.0f);
   float4 x = v.SampleGrad(v_1, v_2, v_3, float2(5.0f, 6.0f), int2(int(4), int(5)));
@@ -3460,7 +3604,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* ddx = b.Construct(ty.vec2<f32>(), b.Value(3_f), b.Value(4_f));
@@ -3478,7 +3622,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2DArray<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float2 v_2 = float2(1.0f, 2.0f);
   float2 v_3 = float2(3.0f, 4.0f);
   float2 v_4 = float2(5.0f, 6.0f);
@@ -3500,7 +3644,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* array_idx = b.Value(4_u);
@@ -3519,7 +3663,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2DArray<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float2 v_2 = float2(1.0f, 2.0f);
   float2 v_3 = float2(3.0f, 4.0f);
   float2 v_4 = float2(5.0f, 6.0f);
@@ -3541,7 +3685,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec3<f32>(), b.Value(1_f), b.Value(2_f), b.Value(3_f));
         auto* ddx = b.Construct(ty.vec3<f32>(), b.Value(3_f), b.Value(4_f), b.Value(5_f));
@@ -3557,7 +3701,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture3D<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float3 v_2 = float3(1.0f, 2.0f, 3.0f);
   float3 v_3 = float3(3.0f, 4.0f, 5.0f);
   float4 x = v.SampleGrad(v_1, v_2, v_3, float3(6.0f, 7.0f, 8.0f));
@@ -3578,7 +3722,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec3<f32>(), b.Value(1_f), b.Value(2_f), b.Value(3_f));
         auto* ddx = b.Construct(ty.vec3<f32>(), b.Value(3_f), b.Value(4_f), b.Value(5_f));
@@ -3596,7 +3740,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture3D<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float3 v_2 = float3(1.0f, 2.0f, 3.0f);
   float3 v_3 = float3(3.0f, 4.0f, 5.0f);
   float4 x = v.SampleGrad(v_1, v_2, v_3, float3(6.0f, 7.0f, 8.0f), int3(int(4), int(5), int(6)));
@@ -3617,7 +3761,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec3<f32>(), b.Value(1_f), b.Value(2_f), b.Value(3_f));
         auto* ddx = b.Construct(ty.vec3<f32>(), b.Value(3_f), b.Value(4_f), b.Value(5_f));
@@ -3633,7 +3777,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 TextureCube<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float3 v_2 = float3(1.0f, 2.0f, 3.0f);
   float3 v_3 = float3(3.0f, 4.0f, 5.0f);
   float4 x = v.SampleGrad(v_1, v_2, v_3, float3(6.0f, 7.0f, 8.0f));
@@ -3654,7 +3798,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec3<f32>(), b.Value(1_f), b.Value(2_f), b.Value(3_f));
         auto* array_idx = b.Value(4_u);
@@ -3672,7 +3816,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 TextureCubeArray<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float3 v_2 = float3(1.0f, 2.0f, 3.0f);
   float3 v_3 = float3(3.0f, 4.0f, 5.0f);
   float3 v_4 = float3(6.0f, 7.0f, 8.0f);
@@ -3693,7 +3837,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
 
@@ -3707,7 +3851,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2D v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float x = v.Sample(v_1, float2(1.0f, 2.0f)).x;
 }
 
@@ -3725,7 +3869,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* offset = b.Composite<vec2<i32>>(4_i, 5_i);
@@ -3740,7 +3884,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2D v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float x = v.Sample(v_1, float2(1.0f, 2.0f), int2(int(4), int(5))).x;
 }
 
@@ -3758,7 +3902,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* array_idx = b.Value(4_u);
@@ -3773,7 +3917,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2DArray v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float2 v_2 = float2(1.0f, 2.0f);
   float x = v.Sample(v_1, float3(v_2, float(4u))).x;
 }
@@ -3792,7 +3936,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* array_idx = b.Value(4_u);
@@ -3808,7 +3952,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2DArray v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float2 v_2 = float2(1.0f, 2.0f);
   float x = v.Sample(v_1, float3(v_2, float(4u)), int2(int(4), int(5))).x;
 }
@@ -3827,7 +3971,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec3<f32>(), b.Value(1_f), b.Value(2_f), b.Value(3_f));
         auto* array_idx = b.Value(4_u);
@@ -3842,7 +3986,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 TextureCubeArray v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float3 v_2 = float3(1.0f, 2.0f, 3.0f);
   float x = v.Sample(v_1, float4(v_2, float(4u))).x;
 }
@@ -3862,7 +4006,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
 
@@ -3876,7 +4020,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2D<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float4 x = v.SampleLevel(v_1, float2(1.0f, 2.0f), 3.0f);
 }
 
@@ -3895,7 +4039,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* offset = b.Composite<vec2<i32>>(4_i, 5_i);
@@ -3911,7 +4055,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2D<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float4 x = v.SampleLevel(v_1, float2(1.0f, 2.0f), 3.0f, int2(int(4), int(5)));
 }
 
@@ -3930,7 +4074,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* array_idx = b.Value(4_u);
@@ -3946,7 +4090,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2DArray<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float2 v_2 = float2(1.0f, 2.0f);
   float4 x = v.SampleLevel(v_1, float3(v_2, float(4u)), 3.0f);
 }
@@ -3966,7 +4110,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* array_idx = b.Value(4_u);
@@ -3983,7 +4127,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2DArray<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float2 v_2 = float2(1.0f, 2.0f);
   float4 x = v.SampleLevel(v_1, float3(v_2, float(4u)), 3.0f, int2(int(4), int(5)));
 }
@@ -4003,7 +4147,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec3<f32>(), b.Value(1_f), b.Value(2_f), b.Value(3_f));
 
@@ -4017,7 +4161,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture3D<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float4 x = v.SampleLevel(v_1, float3(1.0f, 2.0f, 3.0f), 3.0f);
 }
 
@@ -4036,7 +4180,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec3<f32>(), b.Value(1_f), b.Value(2_f), b.Value(3_f));
         auto* offset = b.Composite<vec3<i32>>(4_i, 5_i, 6_i);
@@ -4052,7 +4196,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture3D<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float4 x = v.SampleLevel(v_1, float3(1.0f, 2.0f, 3.0f), 3.0f, int3(int(4), int(5), int(6)));
 }
 
@@ -4071,7 +4215,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec3<f32>(), b.Value(1_f), b.Value(2_f), b.Value(3_f));
 
@@ -4085,7 +4229,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 TextureCube<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float4 x = v.SampleLevel(v_1, float3(1.0f, 2.0f, 3.0f), 3.0f);
 }
 
@@ -4104,7 +4248,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec3<f32>(), b.Value(1_f), b.Value(2_f), b.Value(3_f));
         auto* array_idx = b.Value(4_u);
@@ -4120,7 +4264,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 TextureCubeArray<float4> v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float3 v_2 = float3(1.0f, 2.0f, 3.0f);
   float4 x = v.SampleLevel(v_1, float4(v_2, float(4u)), 3.0f);
 }
@@ -4139,7 +4283,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
 
@@ -4153,7 +4297,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2D v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float2 v_2 = float2(1.0f, 2.0f);
   float x = v.SampleLevel(v_1, v_2, float(int(3))).x;
 }
@@ -4172,7 +4316,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* offset = b.Composite<vec2<i32>>(4_i, 5_i);
@@ -4187,7 +4331,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2D v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float2 v_2 = float2(1.0f, 2.0f);
   float x = v.SampleLevel(v_1, v_2, float(int(3)), int2(int(4), int(5))).x;
 }
@@ -4206,7 +4350,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* array_idx = b.Value(4_u);
@@ -4221,7 +4365,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2DArray v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float2 v_2 = float2(1.0f, 2.0f);
   float3 v_3 = float3(v_2, float(4u));
   float x = v.SampleLevel(v_1, v_3, float(3u)).x;
@@ -4241,7 +4385,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec2<f32>(), b.Value(1_f), b.Value(2_f));
         auto* array_idx = b.Value(4_u);
@@ -4258,7 +4402,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 Texture2DArray v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float2 v_2 = float2(1.0f, 2.0f);
   float3 v_3 = float3(v_2, float(4u));
   float x = v.SampleLevel(v_1, v_3, float(int(3)), int2(int(4), int(5))).x;
@@ -4278,7 +4422,7 @@
         sampler->SetBindingPoint(0, 1);
     });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* coords = b.Construct(ty.vec3<f32>(), b.Value(1_f), b.Value(2_f), b.Value(3_f));
         auto* array_idx = b.Value(4_u);
@@ -4293,7 +4437,7 @@
     EXPECT_EQ(output_.hlsl, R"(
 TextureCubeArray v : register(t0);
 SamplerState v_1 : register(s1);
-void foo() {
+void main() {
   float3 v_2 = float3(1.0f, 2.0f, 3.0f);
   float4 v_3 = float4(v_2, float(4u));
   float x = v.SampleLevel(v_1, v_3, float(3u)).x;
@@ -4303,7 +4447,7 @@
 }
 
 TEST_F(HlslWriterTest, BuiltinReflect_Vec2f32_NoPolyfill) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* vec_ty = ty.vec2<f32>();
         auto* x = b.Let("x", b.MatchWidth(1_f, vec_ty));
@@ -4315,10 +4459,11 @@
     });
 
     tint::hlsl::writer::Options options;
+    options.entry_point_name = "main";
     options.polyfill_reflect_vec2_f32 = false;
     ASSERT_TRUE(Generate(options)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   float2 x = (1.0f).xx;
   float2 y = (2.0f).xx;
   float2 w = reflect(x, y);
@@ -4333,7 +4478,7 @@
 //      x - 2.0 * dot(x,y) * y
 // See crbug.com/tint/1798
 TEST_F(HlslWriterTest, BuiltinReflect_Vec2f32_Polyfill) {
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* vec_ty = ty.vec2<f32>();
         auto* x = b.Let("x", b.MatchWidth(1_f, vec_ty));
@@ -4345,10 +4490,11 @@
     });
 
     tint::hlsl::writer::Options options;
+    options.entry_point_name = "main";
     options.polyfill_reflect_vec2_f32 = true;
     ASSERT_TRUE(Generate(options)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
+void main() {
   float2 x = (1.0f).xx;
   float2 y = (2.0f).xx;
   float2 w = (x + (float2(((-2.0f * dot(x, y))).xx) * y));
diff --git a/src/tint/lang/hlsl/writer/common/options.h b/src/tint/lang/hlsl/writer/common/options.h
index 65c7955..68b8bf6 100644
--- a/src/tint/lang/hlsl/writer/common/options.h
+++ b/src/tint/lang/hlsl/writer/common/options.h
@@ -128,6 +128,9 @@
     /// @returns this Options
     Options& operator=(const Options&);
 
+    /// The entry point to emit
+    std::string entry_point_name = {};
+
     /// An optional remapped name to use when emitting the entry point.
     std::string remapped_entry_point_name = {};
 
@@ -211,6 +214,7 @@
 
     /// Reflect the fields of this class so that it can be used by tint::ForeachField()
     TINT_REFLECT(Options,
+                 entry_point_name,
                  remapped_entry_point_name,
                  strip_all_names,
                  disable_robustness,
diff --git a/src/tint/lang/hlsl/writer/constant_test.cc b/src/tint/lang/hlsl/writer/constant_test.cc
index edc70fd..788d939 100644
--- a/src/tint/lang/hlsl/writer/constant_test.cc
+++ b/src/tint/lang/hlsl/writer/constant_test.cc
@@ -40,6 +40,12 @@
     auto* f = b.Function("a", ty.bool_());
     f->Block()->Append(b.Return(f, false));
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 bool a() {
@@ -47,7 +53,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  bool x = a();
 }
 
 )");
@@ -57,6 +64,12 @@
     auto* f = b.Function("a", ty.bool_());
     f->Block()->Append(b.Return(f, true));
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 bool a() {
@@ -64,7 +77,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  bool x = a();
 }
 
 )");
@@ -74,6 +88,12 @@
     auto* f = b.Function("a", ty.i32());
     f->Block()->Append(b.Return(f, -12345_i));
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 int a() {
@@ -81,7 +101,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  int x = a();
 }
 
 )");
@@ -91,6 +112,12 @@
     auto* f = b.Function("a", ty.u32());
     f->Block()->Append(b.Return(f, 56779_u));
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 uint a() {
@@ -98,7 +125,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  uint x = a();
 }
 
 )");
@@ -109,6 +137,12 @@
     // Use a number close to 1<<30 but whose decimal representation ends in 0.
     f->Block()->Append(b.Return(f, f32((1 << 30) - 4)));
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 float a() {
@@ -116,7 +150,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  float x = a();
 }
 
 )");
@@ -127,6 +162,12 @@
     // Use a number close to 1<<16 but whose decimal representation ends in 0.
     f->Block()->Append(b.Return(f, f16((1 << 15) - 8)));
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 float16_t a() {
@@ -134,7 +175,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  float16_t x = a();
 }
 
 )");
@@ -144,6 +186,12 @@
     auto* f = b.Function("a", ty.vec3<f32>());
     b.Append(f->Block(), [&] { b.Return(f, b.Composite(ty.vec3<f32>(), 1_f, 2_f, 3_f)); });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 float3 a() {
@@ -151,7 +199,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  float3 x = a();
 }
 
 )");
@@ -161,6 +210,12 @@
     auto* f = b.Function("a", ty.vec3<f16>());
     b.Append(f->Block(), [&] { b.Return(f, b.Composite(ty.vec3<f16>(), 1_h, 2_h, 3_h)); });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 vector<float16_t, 3> a() {
@@ -168,7 +223,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  vector<float16_t, 3> x = a();
 }
 
 )");
@@ -178,6 +234,12 @@
     auto* f = b.Function("a", ty.vec3<f32>());
     b.Append(f->Block(), [&] { b.Return(f, b.Zero<vec3<f32>>()); });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 float3 a() {
@@ -185,7 +247,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  float3 x = a();
 }
 
 )");
@@ -195,6 +258,12 @@
     auto* f = b.Function("a", ty.vec3<f16>());
     b.Append(f->Block(), [&] { b.Return(f, b.Zero<vec3<f16>>()); });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 vector<float16_t, 3> a() {
@@ -202,7 +271,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  vector<float16_t, 3> x = a();
 }
 
 )");
@@ -212,6 +282,12 @@
     auto* f = b.Function("a", ty.vec3<f32>());
     b.Append(f->Block(), [&] { b.Return(f, b.Splat(ty.vec3<f32>(), 2_f)); });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 float3 a() {
@@ -219,7 +295,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  float3 x = a();
 }
 
 )");
@@ -229,6 +306,12 @@
     auto* f = b.Function("a", ty.vec3<f16>());
     b.Append(f->Block(), [&] { b.Return(f, b.Splat(ty.vec3<f16>(), 2_h)); });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 vector<float16_t, 3> a() {
@@ -236,7 +319,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  vector<float16_t, 3> x = a();
 }
 
 )");
@@ -246,6 +330,12 @@
     auto* f = b.Function("a", ty.vec3<bool>());
     b.Append(f->Block(), [&] { b.Return(f, b.Splat(ty.vec3<bool>(), true)); });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 bool3 a() {
@@ -253,7 +343,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  bool3 x = a();
 }
 
 )");
@@ -263,6 +354,12 @@
     auto* f = b.Function("a", ty.vec3<i32>());
     b.Append(f->Block(), [&] { b.Return(f, b.Splat(ty.vec3<i32>(), 2_i)); });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 int3 a() {
@@ -270,7 +367,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  int3 x = a();
 }
 
 )");
@@ -280,6 +378,12 @@
     auto* f = b.Function("a", ty.vec3<u32>());
     b.Append(f->Block(), [&] { b.Return(f, b.Splat(ty.vec3<u32>(), 2_u)); });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 uint3 a() {
@@ -287,7 +391,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  uint3 x = a();
 }
 
 )");
@@ -300,6 +405,12 @@
                                 b.Composite(ty.vec3<f32>(), 3_f, 4_f, 5_f)));
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 float2x3 a() {
@@ -307,7 +418,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  float2x3 x = a();
 }
 
 )");
@@ -320,6 +432,12 @@
                                 b.Composite(ty.vec3<f16>(), 3_h, 4_h, 5_h)));
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 matrix<float16_t, 2, 3> a() {
@@ -327,7 +445,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  matrix<float16_t, 2, 3> x = a();
 }
 
 )");
@@ -347,6 +466,12 @@
                                 b.Composite(ty.vec4<f32>(), 42_f, 21_f, 6_f, -5_f)));
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 float4x4 a() {
@@ -354,7 +479,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  float4x4 x = a();
 }
 
 )");
@@ -374,6 +500,12 @@
                                 b.Composite(ty.vec4<f16>(), 42_h, 21_h, 6_h, -5_h)));
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 matrix<float16_t, 4, 4> a() {
@@ -381,7 +513,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  matrix<float16_t, 4, 4> x = a();
 }
 
 )");
@@ -391,6 +524,12 @@
     auto* f = b.Function("a", ty.mat2x3<f32>());
     b.Append(f->Block(), [&] { b.Return(f, b.Zero<mat2x3<f32>>()); });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 float2x3 a() {
@@ -398,7 +537,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  float2x3 x = a();
 }
 
 )");
@@ -408,6 +548,12 @@
     auto* f = b.Function("a", ty.mat2x3<f16>());
     b.Append(f->Block(), [&] { b.Return(f, b.Zero<mat2x3<f16>>()); });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 matrix<float16_t, 2, 3> a() {
@@ -415,7 +561,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  matrix<float16_t, 2, 3> x = a();
 }
 
 )");
@@ -427,7 +574,7 @@
     //  var m_2: mat4x4<f32> = mat4x4<f32>(m_1);
     // }
 
-    auto* f = b.Function("a", ty.void_());
+    auto* f = b.ComputeFunction("main");
     b.Append(f->Block(), [&] {
         auto* m1 = b.Var("m_1", b.Zero<mat4x4<f32>>());
         b.Var("m_2", b.Load(m1));
@@ -436,15 +583,12 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void a() {
+[numthreads(1, 1, 1)]
+void main() {
   float4x4 m_1 = float4x4((0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx, (0.0f).xxxx);
   float4x4 m_2 = m_1;
 }
 
-[numthreads(1, 1, 1)]
-void unused_entry_point() {
-}
-
 )");
 }
 
@@ -454,7 +598,7 @@
     //   var m_2: mat4x4<f16> = mat4x4<f16>(m_1);
     // }
 
-    auto* f = b.Function("a", ty.void_());
+    auto* f = b.ComputeFunction("main");
     b.Append(f->Block(), [&] {
         auto* m1 = b.Var("m_1", b.Zero<mat4x4<f16>>());
         b.Var("m_2", b.Load(m1));
@@ -463,15 +607,12 @@
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void a() {
+[numthreads(1, 1, 1)]
+void main() {
   matrix<float16_t, 4, 4> m_1 = matrix<float16_t, 4, 4>((float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx, (float16_t(0.0h)).xxxx);
   matrix<float16_t, 4, 4> m_2 = m_1;
 }
 
-[numthreads(1, 1, 1)]
-void unused_entry_point() {
-}
-
 )");
 }
 
@@ -484,6 +625,12 @@
                              b.Composite(ty.vec3<f32>(), 7_f, 8_f, 9_f)));
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 typedef float3 ary_ret[3];
@@ -493,7 +640,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  float3 x[3] = a();
 }
 
 )");
@@ -503,6 +651,12 @@
     auto* f = b.Function("a", ty.array<vec3<f32>, 3>());
     b.Append(f->Block(), [&] { b.Return(f, b.Zero<array<vec3<f32>, 3>>()); });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 typedef float3 ary_ret[3];
@@ -512,14 +666,15 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  float3 x[3] = a();
 }
 
 )");
 }
 
 TEST_F(HlslWriterTest, ConstantTypeArray) {
-    auto* f = b.ComputeFunction("a");
+    auto* f = b.ComputeFunction("main");
 
     b.Append(f->Block(), [&] {
         b.Var("v", b.Composite(ty.array<vec3<f32>, 3>(), b.Composite(ty.vec3<f32>(), 1_f, 2_f, 3_f),
@@ -531,7 +686,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void a() {
+void main() {
   float3 v[3] = {float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f)};
 }
 
@@ -539,21 +694,28 @@
 }
 
 TEST_F(HlslWriterTest, ConstantTypeArrayModuleScopeZero) {
-    b.ir.root_block->Append(b.Var<private_>("v", b.Zero<array<f32, 65536>>()));
+    core::ir::Var* v = b.Var<private_>("v", b.Zero<array<f32, 65536>>());
+    b.ir.root_block->Append(v);
+
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", v);
+        b.Return(eb);
+    });
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 static const float v_1[65536] = (float[65536])0;
 static float v[65536] = v_1;
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
 }
 
 )");
 }
 
 TEST_F(HlslWriterTest, ConstantTypeArrayEmpty) {
-    auto* f = b.ComputeFunction("a");
+    auto* f = b.ComputeFunction("main");
 
     b.Append(f->Block(), [&] {
         b.Var("v", b.Zero<array<vec3<f32>, 3>>());
@@ -563,7 +725,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void a() {
+void main() {
   float3 v[3] = (float3[3])0;
 }
 
@@ -592,6 +754,12 @@
     auto* f = b.Function("a", s_strct);
     b.Append(f->Block(), [&] { b.Return(f, b.Zero(s_strct)); });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(struct A {
   int d;
@@ -611,7 +779,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  S x = a();
 }
 
 )");
@@ -635,6 +804,12 @@
         b.Return(f, b.Construct(s_strct, b.Construct(a_strct, b.Splat(ty.vec4<f32>(), 1_f))));
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(struct A {
   float4 e;
@@ -652,7 +827,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  S x = a();
 }
 
 )");
@@ -677,6 +853,12 @@
         b.Return(f, 1_f);
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(struct A {
   float4 e;
@@ -693,7 +875,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  float x = a();
 }
 
 )");
@@ -722,6 +905,12 @@
         b.Return(f, 1_f);
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(struct A {
   float4 e;
@@ -732,16 +921,14 @@
 };
 
 
-static const A v = {(1.0f).xxxx};
-static const S v_1 = {v};
-static S z = v_1;
 float a() {
   S t = {{(1.0f).xxxx}};
   return 1.0f;
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  float x = a();
 }
 
 )");
@@ -763,6 +950,12 @@
     auto* f = b.Function("a", strct);
     b.Append(f->Block(), [&] { b.Return(f, b.Zero(strct)); });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(struct S {
   int a;
@@ -778,7 +971,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  S x = a();
 }
 
 )");
@@ -803,6 +997,12 @@
                                 b.Splat(ty.vec4<f32>(), 3_f)));
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(struct S {
   int a;
@@ -818,7 +1018,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  S x = a();
 }
 
 )");
@@ -844,6 +1045,12 @@
         b.Return(f, 1_f);
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(struct S {
   int a;
@@ -859,7 +1066,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  float x = a();
 }
 
 )");
@@ -872,7 +1080,14 @@
     };
     auto* strct = ty.Struct(b.ir.symbols.New("S"), std::move(members));
 
-    b.Append(b.ir.root_block, [&] { b.Var<private_>("p", b.Zero(strct)); });
+    core::ir::Var* v = nullptr;
+    b.Append(b.ir.root_block, [&] { v = b.Var<private_>("p", b.Zero(strct)); });
+
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", v);
+        b.Return(eb);
+    });
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(struct S {
@@ -883,7 +1098,7 @@
 static const S v = {int(0)};
 static S p = v;
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
 }
 
 )");
@@ -896,7 +1111,14 @@
     };
     auto* strct = ty.Struct(b.ir.symbols.New("S"), std::move(members));
 
-    b.Append(b.ir.root_block, [&] { b.Var<private_>("p", b.Composite(strct, 3_i)); });
+    core::ir::Var* v = nullptr;
+    b.Append(b.ir.root_block, [&] { v = b.Var<private_>("p", b.Composite(strct, 3_i)); });
+
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", v);
+        b.Return(eb);
+    });
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(struct S {
@@ -907,7 +1129,7 @@
 static const S v = {int(3)};
 static S p = v;
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
 }
 
 )");
@@ -925,17 +1147,23 @@
                                                      {mod.symbols.New("a"), a_ty},
                                                  });
 
+    core::ir::Var* v1 = nullptr;
+    core::ir::Var* v2 = nullptr;
+    core::ir::Var* v3 = nullptr;
+    core::ir::Var* v4 = nullptr;
+    core::ir::Var* v5 = nullptr;
     b.Append(b.ir.root_block, [&] {
-        b.Var<private_>("a", b.Composite(a_ty, b.Composite(ty.array<i32, 2>(), 9_i, 10_i)));
-        b.Var<private_>(
+        v1 = b.Var<private_>("a", b.Composite(a_ty, b.Composite(ty.array<i32, 2>(), 9_i, 10_i)));
+        v2 = b.Var<private_>(
             "b",
             b.Composite(b_ty, b.Composite(ty.array<array<i32, 4>, 1>(),
                                           b.Composite(ty.array<i32, 4>(), 5_i, 6_i, 7_i, 8_i))));
-        b.Var<private_>(
+        v3 = b.Var<private_>(
             "c", b.Composite(c_ty, b.Composite(a_ty, b.Composite(ty.array<i32, 2>(), 1_i, 2_i))));
 
-        b.Var<private_>("d", b.Composite(ty.array<i32, 2>(), 11_i, 12_i));
-        b.Var<private_>("e", b.Composite(ty.array<array<array<i32, 3>, 2>, 1>(),
+        v4 = b.Var<private_>("d", b.Composite(ty.array<i32, 2>(), 11_i, 12_i));
+        v5 = b.Var<private_>("e",
+                             b.Composite(ty.array<array<array<i32, 3>, 2>, 1>(),
                                          b.Composite(ty.array<array<i32, 3>, 2>(),
                                                      b.Composite(ty.array<i32, 3>(), 1_i, 2_i, 3_i),
                                                      b.Composite(ty.array<i32, 3>(), 4_i, 5_i, 6_i)
@@ -943,6 +1171,16 @@
                                                          )));
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("t", v1);
+        b.Let("w", v2);
+        b.Let("x", v3);
+        b.Let("y", v4);
+        b.Let("z", v5);
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(struct A {
   int a[2];
@@ -969,7 +1207,7 @@
 static const int v_5[1][2][3] = {{{int(1), int(2), int(3)}, {int(4), int(5), int(6)}}};
 static int e[1][2][3] = v_5;
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
 }
 
 )");
diff --git a/src/tint/lang/hlsl/writer/construct_test.cc b/src/tint/lang/hlsl/writer/construct_test.cc
index d5a0491..4f55643 100644
--- a/src/tint/lang/hlsl/writer/construct_test.cc
+++ b/src/tint/lang/hlsl/writer/construct_test.cc
@@ -40,6 +40,12 @@
         b.Return(f, b.Construct(ty.f32(), v));
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 float a() {
@@ -48,7 +54,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  float x = a();
 }
 
 )");
@@ -61,6 +68,12 @@
         b.Return(f, b.Construct(ty.f16(), v));
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 float16_t a() {
@@ -69,7 +82,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  float16_t x = a();
 }
 
 )");
@@ -82,6 +96,12 @@
         b.Return(f, b.Construct(ty.bool_(), v));
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 bool a() {
@@ -90,7 +110,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  bool x = a();
 }
 
 )");
@@ -103,6 +124,12 @@
         b.Return(f, b.Construct(ty.i32(), v));
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 int a() {
@@ -111,7 +138,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  int x = a();
 }
 
 )");
@@ -124,6 +152,12 @@
         b.Return(f, b.Construct(ty.u32(), v));
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 uint a() {
@@ -132,7 +166,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  uint x = a();
 }
 
 )");
@@ -145,6 +180,12 @@
         b.Return(f, b.Construct(ty.mat2x2<f32>(), v, v, v, v));
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 float2x2 a() {
@@ -154,7 +195,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  float2x2 x = a();
 }
 
 )");
@@ -167,6 +209,12 @@
         b.Return(f, b.Construct(ty.vec3<f32>(), v));
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 float3 a() {
@@ -175,7 +223,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  float3 x = a();
 }
 
 )");
@@ -188,6 +237,12 @@
         b.Return(f, b.Construct(ty.vec3<f16>(), v));
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 vector<float16_t, 3> a() {
@@ -196,7 +251,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  vector<float16_t, 3> x = a();
 }
 
 )");
@@ -209,6 +265,12 @@
         b.Return(f, b.Construct(ty.vec3<bool>(), v));
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 bool3 a() {
@@ -217,14 +279,15 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  bool3 x = a();
 }
 
 )");
 }
 
 TEST_F(HlslWriterTest, ConstructArray) {
-    auto* f = b.ComputeFunction("a");
+    auto* f = b.ComputeFunction("main");
 
     b.Append(f->Block(), [&] {
         b.Var("v", b.Construct(ty.array<vec3<f32>, 3>(), b.Composite(ty.vec3<f32>(), 1_f, 2_f, 3_f),
@@ -236,7 +299,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void a() {
+void main() {
   float3 v[3] = {float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f)};
 }
 
@@ -259,6 +322,12 @@
         b.Return(f, b.Construct(strct, 1_i, 2_f, b.Composite(ty.vec3<i32>(), 3_i, 4_i, 5_i)));
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(struct S {
   int a;
@@ -273,7 +342,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  S x = a();
 }
 
 )");
diff --git a/src/tint/lang/hlsl/writer/convert_test.cc b/src/tint/lang/hlsl/writer/convert_test.cc
index df9a508..46685e3 100644
--- a/src/tint/lang/hlsl/writer/convert_test.cc
+++ b/src/tint/lang/hlsl/writer/convert_test.cc
@@ -40,6 +40,12 @@
         b.Return(f, b.Convert(ty.u32(), v));
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(f));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 uint a() {
@@ -48,7 +54,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  uint x = a();
 }
 
 )");
diff --git a/src/tint/lang/hlsl/writer/function_test.cc b/src/tint/lang/hlsl/writer/function_test.cc
index f77b384..6f360fc 100644
--- a/src/tint/lang/hlsl/writer/function_test.cc
+++ b/src/tint/lang/hlsl/writer/function_test.cc
@@ -42,16 +42,13 @@
 namespace {
 
 TEST_F(HlslWriterTest, FunctionEmpty) {
-    auto* func = b.Function("foo", ty.void_());
+    auto* func = b.ComputeFunction("main");
     func->Block()->Append(b.Return(func));
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
-void foo() {
-}
-
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
 }
 
 )");
@@ -65,13 +62,20 @@
     func->SetParams({b.FunctionParam("a", ty.f32()), b.FunctionParam("b", ty.i32())});
     func->Block()->Append(b.Return(func));
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Call(func, b.Zero(ty.f32()), b.Zero(ty.i32()));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 void my_func(float a, int b) {
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  my_func(0.0f, int(0));
 }
 
 )");
@@ -140,6 +144,13 @@
     func->SetParams({foo});
     b.Append(func->Block(), [&] { b.Return(func, b.Load(foo)); });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        auto* v = b.Var("v", ty.ptr(function, ty.f32()));
+        b.Let("x", b.Call(func, v));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 float f(inout float foo) {
@@ -147,41 +158,43 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  float v = 0.0f;
+  float x = f(v);
 }
 
 )");
 }
 
 TEST_F(HlslWriterTest, FunctionEntryPointWithInAndOutLocations) {
-    // fn frag_main(@location(0) foo : f32) -> @location(1) f32 {
+    // fn main(@location(0) foo : f32) -> @location(1) f32 {
     //   return foo;
     // }
 
     auto* foo = b.FunctionParam("foo", ty.f32());
     foo->SetLocation(0);
 
-    auto* func = b.Function("frag_main", ty.f32(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.f32(), core::ir::Function::PipelineStage::kFragment);
     func->SetParams({foo});
     func->SetReturnLocation(1);
     func->Block()->Append(b.Return(func, foo));
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
-    EXPECT_EQ(output_.hlsl, R"(struct frag_main_outputs {
+    EXPECT_EQ(output_.hlsl, R"(struct main_outputs {
   float tint_symbol : SV_Target1;
 };
 
-struct frag_main_inputs {
+struct main_inputs {
   float foo : TEXCOORD0;
 };
 
 
-float frag_main_inner(float foo) {
+float main_inner(float foo) {
   return foo;
 }
 
-frag_main_outputs frag_main(frag_main_inputs inputs) {
-  frag_main_outputs v = {frag_main_inner(inputs.foo)};
+main_outputs main(main_inputs inputs) {
+  main_outputs v = {main_inner(inputs.foo)};
   return v;
 }
 
@@ -189,14 +202,14 @@
 }
 
 TEST_F(HlslWriterTest, FunctionEntryPointWithInOutBuiltins) {
-    // fn frag_main(@position(0) coord : vec4<f32>) -> @frag_depth f32 {
+    // fn main(@position(0) coord : vec4<f32>) -> @frag_depth f32 {
     //   return coord.x;
     // }
 
     auto* coord = b.FunctionParam("coord", ty.vec4<f32>());
     coord->SetBuiltin(core::BuiltinValue::kPosition);
 
-    auto* func = b.Function("frag_main", ty.f32(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.f32(), core::ir::Function::PipelineStage::kFragment);
     func->SetReturnBuiltin(core::BuiltinValue::kFragDepth);
     func->SetParams({coord});
     b.Append(func->Block(), [&] {
@@ -205,21 +218,21 @@
     });
 
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
-    EXPECT_EQ(output_.hlsl, R"(struct frag_main_outputs {
+    EXPECT_EQ(output_.hlsl, R"(struct main_outputs {
   float tint_symbol : SV_Depth;
 };
 
-struct frag_main_inputs {
+struct main_inputs {
   float4 coord : SV_Position;
 };
 
 
-float frag_main_inner(float4 coord) {
+float main_inner(float4 coord) {
   return coord.x;
 }
 
-frag_main_outputs frag_main(frag_main_inputs inputs) {
-  frag_main_outputs v = {frag_main_inner(float4(inputs.coord.xyz, (1.0f / inputs.coord.w)))};
+main_outputs main(main_inputs inputs) {
+  main_outputs v = {main_inner(float4(inputs.coord.xyz, (1.0f / inputs.coord.w)))};
   return v;
 }
 
@@ -235,7 +248,7 @@
     // fn sub_func(param: f32) -> f32 {
     //   return ubo.coord.x;
     // }
-    // @fragment fn frag_main() {
+    // @fragment fn main() {
     //   var v = sub_func(1f);
     // }
 
@@ -260,8 +273,7 @@
         b.Return(sub_func, b.Load(a));
     });
 
-    auto* frag_func =
-        b.Function("frag_main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* frag_func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(frag_func->Block(), [&] {
         b.Var("v", b.Call(sub_func, 1_f));
         b.Return(frag_func);
@@ -276,7 +288,7 @@
   return asfloat(ubo[0u].x);
 }
 
-void frag_main() {
+void main() {
   float v = sub_func(1.0f);
 }
 
@@ -290,7 +302,7 @@
     //
     // @group(1) @binding(0) var<uniform> ubo: Uniforms;
     //
-    // @fragment fn frag_main() {
+    // @fragment fn main() {
     //   var v = ubo.coord.x;
     // }
 
@@ -306,7 +318,7 @@
     ubo->SetBindingPoint(1, 0);
     b.ir.root_block->Append(ubo);
 
-    auto* func = b.Function("frag_main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {  //
         auto* a = b.Access(ty.ptr<uniform, f32>(), ubo, 0_u, 0_u);
         b.Var("v", b.Load(a));
@@ -318,7 +330,7 @@
 cbuffer cbuffer_ubo : register(b0, space1) {
   uint4 ubo[1];
 };
-void frag_main() {
+void main() {
   float v = asfloat(ubo[0u].x);
 }
 
@@ -332,7 +344,7 @@
     // }
     // @group(1) @binding(0) var<storage, read_write> coord: Data;
     //
-    // @fragment fn frag_main() {
+    // @fragment fn main() {
     //   var v = coord.b;
     // }
 
@@ -346,7 +358,7 @@
     coord->SetBindingPoint(1, 0);
     b.ir.root_block->Append(coord);
 
-    auto* func = b.Function("frag_main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {  //
         auto* a = b.Access(ty.ptr(storage, ty.i32()), coord, 0_u);
         b.Var("v", b.Load(a));
@@ -358,7 +370,7 @@
     EXPECT_EQ(output_.hlsl,
               R"(
 RWByteAddressBuffer coord : register(u0, space1);
-void frag_main() {
+void main() {
   int v = asint(coord.Load(0u));
 }
 
@@ -372,7 +384,7 @@
     // }
     // @group(1) @binding(0) var<storage, read> coord: Data;
     //
-    // @fragment fn frag_main() {
+    // @fragment fn main() {
     //   var v = coord.b;
     // }
 
@@ -386,7 +398,7 @@
     coord->SetBindingPoint(1, 0);
     b.ir.root_block->Append(coord);
 
-    auto* func = b.Function("frag_main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {  //
         auto* a = b.Access(ty.ptr<storage, f32, core::Access::kRead>(), coord, 1_u);
         b.Var("v", b.Load(a));
@@ -397,7 +409,7 @@
     EXPECT_EQ(output_.hlsl,
               R"(
 ByteAddressBuffer coord : register(t0, space1);
-void frag_main() {
+void main() {
   float v = asfloat(coord.Load(4u));
 }
 
@@ -411,7 +423,7 @@
     // }
     // @group(1) @binding(0) var<storage, write> coord: Data;
     //
-    // @fragment fn frag_main() {
+    // @fragment fn main() {
     //   coord.b = 2f;
     // }
 
@@ -425,7 +437,7 @@
     coord->SetBindingPoint(1, 0);
     b.ir.root_block->Append(coord);
 
-    auto* func = b.Function("frag_main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {  //
         b.Store(b.Access(ty.ptr(storage, ty.f32()), coord, 1_u), 2_f);
         b.Return(func);
@@ -435,7 +447,7 @@
     EXPECT_EQ(output_.hlsl,
               R"(
 RWByteAddressBuffer coord : register(u0, space1);
-void frag_main() {
+void main() {
   coord.Store(4u, asuint(2.0f));
 }
 
@@ -449,7 +461,7 @@
     // }
     // @group(1) @binding(0) var<storage, write> coord: Data;
     //
-    // @fragment fn frag_main() {
+    // @fragment fn main() {
     //   coord.b = 2f;
     // }
 
@@ -463,7 +475,7 @@
     coord->SetBindingPoint(1, 0);
     b.ir.root_block->Append(coord);
 
-    auto* func = b.Function("frag_main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {  //
         b.Store(b.Access(ty.ptr(storage, ty.f32()), coord, 1_u), 2_f);
         b.Return(func);
@@ -473,7 +485,7 @@
     EXPECT_EQ(output_.hlsl,
               R"(
 RWByteAddressBuffer coord : register(u0, space1);
-void frag_main() {
+void main() {
   coord.Store(4u, asuint(2.0f));
 }
 
@@ -489,7 +501,7 @@
     // fn sub_func() -> f32 {
     //   return coord.x;
     // }
-    // @fragment fn frag_main() {
+    // @fragment fn main() {
     //   var v = sub_func(1f);
     // }
 
@@ -510,7 +522,7 @@
         b.Return(sub_func, b.Load(a));
     });
 
-    auto* func = b.Function("frag_main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {  //
         b.Var("v", b.Call(sub_func, 1_f));
         b.Return(func);
@@ -525,7 +537,7 @@
   return asfloat(coord[0u].x);
 }
 
-void frag_main() {
+void main() {
   float v = sub_func(1.0f);
 }
 
@@ -541,7 +553,7 @@
     // fn sub_func() -> f32 {
     //   return coord.x;
     // }
-    // @fragment fn frag_main() {
+    // @fragment fn main() {
     //   var v = sub_func();
     // }
 
@@ -559,7 +571,7 @@
         b.Return(sub_func, b.Load(a));
     });
 
-    auto* func = b.Function("frag_main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {  //
         b.Var("v", b.Call(sub_func));
         b.Return(func);
@@ -573,7 +585,7 @@
   return asfloat(coord.Load(0u));
 }
 
-void frag_main() {
+void main() {
   float v = sub_func();
 }
 
@@ -622,13 +634,21 @@
     func->SetParams({p});
     func->Block()->Append(b.Return(func));
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Call(func, b.Zero(ty.array<f32, 5>()));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 void my_func(float a[5]) {
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  float v[5] = (float[5])0;
+  my_func(v);
 }
 
 )");
@@ -642,6 +662,12 @@
     auto* func = b.Function("my_func", ty.array<f32, 5>());
     func->Block()->Append(b.Return(func, b.Zero(ty.array<f32, 5>())));
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(func));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 typedef float ary_ret[5];
@@ -651,7 +677,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  float x[5] = my_func();
 }
 
 )");
@@ -676,7 +703,16 @@
         });
         b.Return(func);
     });
+
+    auto* eb = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(eb->Block(), [&] {
+        b.Call(func, b.Zero(ty.i32()));
+        b.Return(eb);
+    });
+
     tint::hlsl::writer::Options options;
+    options.entry_point_name = "main";
+
     // FXC must use demote to helper transform.
     options.compiler = tint::hlsl::writer::Options::Compiler::kFXC;
     ASSERT_TRUE(Generate(options)) << err_ << output_.hlsl;
@@ -688,8 +724,11 @@
   }
 }
 
-[numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  my_func(int(0));
+  if (!(continue_execution)) {
+    discard;
+  }
 }
 
 )");
@@ -714,7 +753,16 @@
         });
         b.Return(func);
     });
+
+    auto* eb = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(eb->Block(), [&] {
+        b.Call(func, b.Zero(ty.i32()));
+        b.Return(eb);
+    });
+
     tint::hlsl::writer::Options options;
+    options.entry_point_name = "main";
+
     options.compiler = tint::hlsl::writer::Options::Compiler::kDXC;
     ASSERT_TRUE(Generate(options)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
@@ -724,8 +772,8 @@
   }
 }
 
-[numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  my_func(int(0));
 }
 
 )");
@@ -752,7 +800,15 @@
         b.Return(func, 42_i);
     });
 
+    auto* eb = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(eb->Block(), [&] {
+        b.Call(func, b.Zero(ty.i32()));
+        b.Return(eb);
+    });
+
     tint::hlsl::writer::Options options;
+    options.entry_point_name = "main";
+
     // FXC must use demote to helper transform.
     options.compiler = tint::hlsl::writer::Options::Compiler::kFXC;
 
@@ -766,8 +822,11 @@
   return int(42);
 }
 
-[numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  my_func(int(0));
+  if (!(continue_execution)) {
+    discard;
+  }
 }
 
 )");
@@ -794,6 +853,12 @@
         b.Return(func, 42_i);
     });
 
+    auto* eb = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(func, b.Zero(ty.i32())));
+        b.Return(eb);
+    });
+
     tint::hlsl::writer::Options options;
     options.compiler = tint::hlsl::writer::Options::Compiler::kDXC;
     ASSERT_TRUE(Generate(options)) << err_ << output_.hlsl;
@@ -805,8 +870,8 @@
   return int(42);
 }
 
-[numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  int x = my_func(int(0));
 }
 
 )");
@@ -816,9 +881,10 @@
     auto* ret_arr = b.Function("ret_arr", ty.array<vec4<i32>, 4>());
     b.Append(ret_arr->Block(), [&] { b.Return(ret_arr, b.Zero<array<vec4<i32>, 4>>()); });
 
-    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    auto* func = b.Function("main", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         b.Let("src_let", b.Zero<array<vec4<i32>, 4>>());
+        b.Let("x", b.Call(ret_arr));
         b.Return(func);
     });
 
@@ -830,8 +896,9 @@
   return v;
 }
 
-void foo() {
+void main() {
   int4 src_let[4] = (int4[4])0;
+  int4 x[4] = ret_arr();
 }
 
 )");
diff --git a/src/tint/lang/hlsl/writer/helper_test.h b/src/tint/lang/hlsl/writer/helper_test.h
index 92ebbb9..47996c4 100644
--- a/src/tint/lang/hlsl/writer/helper_test.h
+++ b/src/tint/lang/hlsl/writer/helper_test.h
@@ -61,6 +61,10 @@
     /// Run the writer on the IR module and validate the result.
     /// @returns true if generation and validation succeeded
     bool Generate(Options options = {}) {
+        if (options.entry_point_name.empty()) {
+            options.entry_point_name = "main";
+        }
+
         auto result = writer::Generate(mod, options);
         if (result != Success) {
             err_ = result.Failure().reason;
diff --git a/src/tint/lang/hlsl/writer/if_test.cc b/src/tint/lang/hlsl/writer/if_test.cc
index a6e27b4..9fe738c 100644
--- a/src/tint/lang/hlsl/writer/if_test.cc
+++ b/src/tint/lang/hlsl/writer/if_test.cc
@@ -33,7 +33,7 @@
 namespace {
 
 TEST_F(HlslWriterTest, If) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* if_ = b.If(true);
         b.Append(if_->True(), [&] { b.ExitIf(if_); });
@@ -43,7 +43,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   if (true) {
   }
 }
@@ -52,7 +52,7 @@
 }
 
 TEST_F(HlslWriterTest, IfWithElseIf) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* if_ = b.If(true);
         b.Append(if_->True(), [&] { b.ExitIf(if_); });
@@ -67,7 +67,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   if (true) {
   } else {
     if (false) {
@@ -79,7 +79,7 @@
 }
 
 TEST_F(HlslWriterTest, IfWithElse) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* if_ = b.If(true);
         b.Append(if_->True(), [&] { b.ExitIf(if_); });
@@ -90,7 +90,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   if (true) {
   } else {
     return;
@@ -101,7 +101,7 @@
 }
 
 TEST_F(HlslWriterTest, IfBothBranchesReturn) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* if_ = b.If(true);
         b.Append(if_->True(), [&] { b.Return(func); });
@@ -112,7 +112,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   if (true) {
     return;
   } else {
@@ -133,6 +133,12 @@
         b.Unreachable();
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(func));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 uint foo() {
@@ -146,14 +152,15 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  uint x = foo();
 }
 
 )");
 }
 
 TEST_F(HlslWriterTest, IfWithSinglePhi) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* i = b.If(true);
         i->SetResult(b.InstructionResult(ty.i32()));
@@ -169,7 +176,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   int v = int(0);
   if (true) {
     v = int(10);
@@ -182,7 +189,7 @@
 }
 
 TEST_F(HlslWriterTest, IfWithMultiPhi) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* i = b.If(true);
         i->SetResults(b.InstructionResult(ty.i32()), b.InstructionResult(ty.bool_()));
@@ -198,7 +205,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   int v = int(0);
   bool v_1 = false;
   if (true) {
@@ -227,6 +234,12 @@
         b.Return(func, i->Result(0));
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(func));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 int foo() {
@@ -243,7 +256,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  int x = foo();
 }
 
 )");
@@ -263,6 +277,12 @@
         b.Return(func, i->Result(1));
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(func));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 bool foo() {
@@ -279,7 +299,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  bool x = foo();
 }
 
 )");
diff --git a/src/tint/lang/hlsl/writer/loop_test.cc b/src/tint/lang/hlsl/writer/loop_test.cc
index 04d4057..56bad25 100644
--- a/src/tint/lang/hlsl/writer/loop_test.cc
+++ b/src/tint/lang/hlsl/writer/loop_test.cc
@@ -34,7 +34,7 @@
 namespace {
 
 TEST_F(HlslWriterTest, Loop) {
-    auto* func = b.ComputeFunction("a");
+    auto* func = b.ComputeFunction("main");
 
     b.Append(func->Block(), [&] {
         auto* l = b.Loop();
@@ -46,7 +46,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void a() {
+void main() {
   {
     uint2 tint_loop_idx = (4294967295u).xx;
     while(true) {
@@ -62,7 +62,7 @@
 }
 
 TEST_F(HlslWriterTest, LoopContinueAndBreakIf) {
-    auto* func = b.ComputeFunction("a");
+    auto* func = b.ComputeFunction("main");
 
     b.Append(func->Block(), [&] {
         auto* l = b.Loop();
@@ -74,7 +74,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void a() {
+void main() {
   {
     uint2 tint_loop_idx = (4294967295u).xx;
     while(true) {
@@ -97,7 +97,7 @@
 }
 
 TEST_F(HlslWriterTest, LoopBodyVarInContinue) {
-    auto* func = b.ComputeFunction("a");
+    auto* func = b.ComputeFunction("main");
 
     b.Append(func->Block(), [&] {
         auto* l = b.Loop();
@@ -113,7 +113,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void a() {
+void main() {
   {
     uint2 tint_loop_idx = (4294967295u).xx;
     while(true) {
@@ -137,7 +137,7 @@
 }
 
 TEST_F(HlslWriterTest, LoopInitializer) {
-    auto* func = b.ComputeFunction("a");
+    auto* func = b.ComputeFunction("main");
 
     b.Append(func->Block(), [&] {
         auto* l = b.Loop();
@@ -154,7 +154,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void a() {
+void main() {
   {
     uint2 tint_loop_idx = (4294967295u).xx;
     bool v = true;
@@ -186,6 +186,12 @@
         b.Unreachable();
     });
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", b.Call(func));
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 int a() {
@@ -203,7 +209,8 @@
 }
 
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
+  int x = a();
 }
 
 )");
diff --git a/src/tint/lang/hlsl/writer/raise/raise.cc b/src/tint/lang/hlsl/writer/raise/raise.cc
index f759a76..b1565b0 100644
--- a/src/tint/lang/hlsl/writer/raise/raise.cc
+++ b/src/tint/lang/hlsl/writer/raise/raise.cc
@@ -49,6 +49,7 @@
 #include "src/tint/lang/core/ir/transform/rename_conflicts.h"
 #include "src/tint/lang/core/ir/transform/robustness.h"
 #include "src/tint/lang/core/ir/transform/signed_integer_polyfill.h"
+#include "src/tint/lang/core/ir/transform/single_entry_point.h"
 #include "src/tint/lang/core/ir/transform/substitute_overrides.h"
 #include "src/tint/lang/core/ir/transform/value_to_let.h"
 #include "src/tint/lang/core/ir/transform/vectorize_scalar_matrix_constructors.h"
@@ -79,6 +80,8 @@
         }                                \
     } while (false)
 
+    RUN_TRANSFORM(core::ir::transform::SingleEntryPoint, module, options.entry_point_name);
+
     RUN_TRANSFORM(core::ir::transform::SubstituteOverrides, module,
                   options.substitute_overrides_config);
 
diff --git a/src/tint/lang/hlsl/writer/switch_test.cc b/src/tint/lang/hlsl/writer/switch_test.cc
index 777c725..1c8a5d2 100644
--- a/src/tint/lang/hlsl/writer/switch_test.cc
+++ b/src/tint/lang/hlsl/writer/switch_test.cc
@@ -34,7 +34,7 @@
 namespace {
 
 TEST_F(HlslWriterTest, Switch) {
-    auto* f = b.ComputeFunction("foo");
+    auto* f = b.ComputeFunction("main");
 
     b.Append(f->Block(), [&] {
         auto* a = b.Var("a", b.Zero<i32>());
@@ -47,7 +47,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   int a = int(0);
   switch(a) {
     case int(5):
@@ -65,7 +65,7 @@
 }
 
 TEST_F(HlslWriterTest, SwitchMixedDefault) {
-    auto* f = b.ComputeFunction("foo");
+    auto* f = b.ComputeFunction("main");
 
     b.Append(f->Block(), [&] {
         auto* a = b.Var("a", b.Zero<i32>());
@@ -78,7 +78,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   int a = int(0);
   switch(a) {
     case int(5):
@@ -103,7 +103,7 @@
     //   }
     // }
 
-    auto* f = b.ComputeFunction("foo");
+    auto* f = b.ComputeFunction("main");
 
     b.Append(f->Block(), [&] {
         auto* cond = b.Var("cond", b.Zero<i32>());
@@ -119,7 +119,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   int cond = int(0);
   int a = int(0);
   switch(cond) {
@@ -161,7 +161,7 @@
         b.Return(bar, b.Load(global));
     });
 
-    auto* f = b.ComputeFunction("foo");
+    auto* f = b.ComputeFunction("main");
 
     b.Append(f->Block(), [&] {
         auto* cond = b.Call(bar);
@@ -183,7 +183,7 @@
 }
 
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   switch(bar()) {
     default:
     {
@@ -207,7 +207,7 @@
     //   }
     // }
 
-    auto* f = b.ComputeFunction("foo");
+    auto* f = b.ComputeFunction("main");
 
     b.Append(f->Block(), [&] {
         auto* cond = b.Var("cond", b.Zero<i32>());
@@ -226,7 +226,7 @@
     ASSERT_TRUE(Generate(options)) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   int cond = int(0);
   int a = int(0);
   {
@@ -267,7 +267,7 @@
         b.Return(bar, b.Load(global));
     });
 
-    auto* f = b.ComputeFunction("foo");
+    auto* f = b.ComputeFunction("main");
 
     b.Append(f->Block(), [&] {
         auto* cond = b.Call(bar);
@@ -292,7 +292,7 @@
 }
 
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   bar();
   {
     while(true) {
diff --git a/src/tint/lang/hlsl/writer/unary_test.cc b/src/tint/lang/hlsl/writer/unary_test.cc
index 4fed18e..16ed1bb 100644
--- a/src/tint/lang/hlsl/writer/unary_test.cc
+++ b/src/tint/lang/hlsl/writer/unary_test.cc
@@ -36,7 +36,7 @@
 namespace {
 
 TEST_F(HlslWriterTest, UnaryComplement) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* a = b.Var("a", b.Zero<i32>());
         b.Var("b", b.Complement<i32>(b.Load(a)));
@@ -46,7 +46,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   int a = int(0);
   int b = ~(a);
 }
@@ -55,7 +55,7 @@
 }
 
 TEST_F(HlslWriterTest, UnaryNot) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* a = b.Var("a", b.Zero<bool>());
         b.Var("b", b.Not<bool>(b.Load(a)));
@@ -65,7 +65,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   bool a = false;
   bool b = !(a);
 }
@@ -74,7 +74,7 @@
 }
 
 TEST_F(HlslWriterTest, UnaryNegation) {
-    auto* func = b.ComputeFunction("foo");
+    auto* func = b.ComputeFunction("main");
     b.Append(func->Block(), [&] {
         auto* a = b.Var("a", b.Zero<f32>());
         b.Var("b", b.Negation<f32>(b.Load(a)));
@@ -84,7 +84,7 @@
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 [numthreads(1, 1, 1)]
-void foo() {
+void main() {
   float a = 0.0f;
   float b = -(a);
 }
diff --git a/src/tint/lang/hlsl/writer/var_let_test.cc b/src/tint/lang/hlsl/writer/var_let_test.cc
index 07811ac..ba03fad 100644
--- a/src/tint/lang/hlsl/writer/var_let_test.cc
+++ b/src/tint/lang/hlsl/writer/var_let_test.cc
@@ -101,11 +101,17 @@
 
     b.ir.root_block->Append(s);
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", s);
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 SamplerState s : register(s0, space1);
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
 }
 
 )");
@@ -117,11 +123,17 @@
 
     b.ir.root_block->Append(s);
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", s);
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 SamplerComparisonState s : register(s0);
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
 }
 
 )");
@@ -134,11 +146,17 @@
 
     b.ir.root_block->Append(v);
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", v);
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 Texture2D<float4> v[4] : register(t0);
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
 }
 
 )");
@@ -164,10 +182,16 @@
 
     b.ir.root_block->Append(s);
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", s);
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, "\n" + params.result + R"(
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
 }
 
 )");
@@ -191,11 +215,17 @@
 
     b.ir.root_block->Append(s);
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", s);
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 Texture2DMS<float4> tex : register(t1, space2);
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
 }
 
 )");
@@ -237,10 +267,16 @@
 
     b.ir.root_block->Append(s);
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", s);
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, "\n" + params.result + R"(
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
 }
 
 )");
@@ -348,11 +384,17 @@
 
     b.ir.root_block->Append(s);
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", s);
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 Texture2DMS<float4> tex : register(t1, space2);
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
 }
 
 )");
@@ -382,10 +424,16 @@
 
     b.ir.root_block->Append(s);
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", s);
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, "\n" + params.result + R"(
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
 }
 
 )");
@@ -476,13 +524,19 @@
 
     b.ir.root_block->Append(s);
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", s);
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 cbuffer cbuffer_u : register(b1, space2) {
   uint4 u[1];
 };
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
 }
 
 )");
@@ -494,11 +548,17 @@
 
     b.ir.root_block->Append(s);
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", s);
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 ByteAddressBuffer u : register(t1, space2);
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
 }
 
 )");
@@ -510,11 +570,17 @@
 
     b.ir.root_block->Append(s);
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", s);
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 RWByteAddressBuffer u : register(u1, space2);
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
 }
 
 )");
@@ -525,11 +591,17 @@
 
     b.ir.root_block->Append(s);
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", s);
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
     EXPECT_EQ(output_.hlsl, R"(
 static float4 u = (0.0f).xxxx;
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main() {
 }
 
 )");
@@ -540,11 +612,29 @@
 
     b.ir.root_block->Append(s);
 
+    auto* eb = b.ComputeFunction("main");
+    b.Append(eb->Block(), [&] {
+        b.Let("x", s);
+        b.Return(eb);
+    });
+
     ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
-    EXPECT_EQ(output_.hlsl, R"(
+    EXPECT_EQ(output_.hlsl, R"(struct main_inputs {
+  uint tint_local_index : SV_GroupIndex;
+};
+
+
 groupshared float4 u;
+void main_inner(uint tint_local_index) {
+  if ((tint_local_index < 1u)) {
+    u = (0.0f).xxxx;
+  }
+  GroupMemoryBarrierWithGroupSync();
+}
+
 [numthreads(1, 1, 1)]
-void unused_entry_point() {
+void main(main_inputs inputs) {
+  main_inner(inputs.tint_local_index);
 }
 
 )");
diff --git a/src/tint/lang/hlsl/writer/writer.cc b/src/tint/lang/hlsl/writer/writer.cc
index fc2760a..e3cf899 100644
--- a/src/tint/lang/hlsl/writer/writer.cc
+++ b/src/tint/lang/hlsl/writer/writer.cc
@@ -46,9 +46,7 @@
 
 namespace tint::hlsl::writer {
 
-Result<SuccessType> CanGenerate(const core::ir::Module& ir,
-                                const Options& options,
-                                const std::string& ep_name) {
+Result<SuccessType> CanGenerate(const core::ir::Module& ir, const Options& options) {
     // Check for unsupported types.
     for (auto* ty : ir.Types()) {
         if (ty->Is<core::type::SubgroupMatrix>()) {
@@ -75,7 +73,7 @@
         if (!f->IsEntryPoint()) {
             continue;
         }
-        if (ir.NameOf(f).NameView() == ep_name) {
+        if (ir.NameOf(f).NameView() == options.entry_point_name) {
             ep_func = f;
             break;
         }
@@ -107,7 +105,7 @@
         }
     }
 
-    auto user_immediate_res = core::ir::ValidateSingleUserImmediate(ir);
+    auto user_immediate_res = core::ir::ValidateSingleUserImmediate(ir, ep_func);
     if (user_immediate_res != Success) {
         return user_immediate_res.Failure();
     }
diff --git a/src/tint/lang/hlsl/writer/writer.h b/src/tint/lang/hlsl/writer/writer.h
index e42daae..7b6ca87 100644
--- a/src/tint/lang/hlsl/writer/writer.h
+++ b/src/tint/lang/hlsl/writer/writer.h
@@ -44,11 +44,8 @@
 /// Check if the module @p ir is supported by the HLSL backend with @p options.
 /// @param ir the module
 /// @param options the writer options
-/// @param ep_name the entry point
 /// @returns Success or a failure message indicating why HLSL generation would fail
-Result<SuccessType> CanGenerate(const core::ir::Module& ir,
-                                const Options& options,
-                                const std::string& ep_name);
+Result<SuccessType> CanGenerate(const core::ir::Module& ir, const Options& options);
 
 /// Generate HLSL for a program, according to a set of configuration options.
 /// The result will contain the HLSL and supplementary information, or failure.
diff --git a/src/tint/lang/hlsl/writer/writer_fuzz.cc b/src/tint/lang/hlsl/writer/writer_fuzz.cc
index c0bb25c..3b8e50f 100644
--- a/src/tint/lang/hlsl/writer/writer_fuzz.cc
+++ b/src/tint/lang/hlsl/writer/writer_fuzz.cc
@@ -88,6 +88,7 @@
     }
 
     Options options;
+    options.entry_point_name = ep_name;
     options.strip_all_names = fuzzed_options.strip_all_names;
     options.disable_robustness = fuzzed_options.disable_robustness;
     options.enable_integer_range_analysis = fuzzed_options.enable_integer_range_analysis;
@@ -115,7 +116,7 @@
         }
     }
 
-    auto check = CanGenerate(module, options, ep_name);
+    auto check = CanGenerate(module, options);
     if (check != Success) {
         return check.Failure();
     }
diff --git a/src/tint/lang/hlsl/writer/writer_test.cc b/src/tint/lang/hlsl/writer/writer_test.cc
index e717a68..f80bd4a 100644
--- a/src/tint/lang/hlsl/writer/writer_test.cc
+++ b/src/tint/lang/hlsl/writer/writer_test.cc
@@ -106,7 +106,8 @@
     });
 
     Options options;
-    auto result = CanGenerate(mod, options, "main");
+    options.entry_point_name = "main";
+    auto result = CanGenerate(mod, options);
     ASSERT_NE(result, Success);
     EXPECT_THAT(result.Failure().reason,
                 testing::HasSubstr("texel buffers are not supported by the HLSL backend"));