tint: Refactor Extensions / Enables.
* Extract ast::Enable::ExtensionKind to ast::Extension.
* Move the parsing out of ast::Enable and next to ast/extension.h
* Change the ast::Enable constructor to take the Extension, instead of
a std::string. It's the WGSL parser's responsibility to parse, not the
AST nodes.
* Add ProgramBuilder::Enable() helper.
* Keep ast::Module simple - keep track of the declared AST Enable nodes,
don't do any deduplicating of the enabled extensions.
* Add the de-duplicated ast::Extensions to the sem::Module.
* Remove the kInternalExtensionForTesting enum value - we have kF16
now, which can be used instead for testing.
* Rename kNoExtension to kNone.
Bug: tint:1472
Change-Id: I9af635e95d36991ea468e6e0bf6798bb50937edc
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/90523
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl b/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl
deleted file mode 100644
index 9ed8f61..0000000
--- a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2022 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Enable a void internal extension
-enable InternalExtensionForTesting;
-
-fn bar() {
-}
-
-@stage(fragment)
-fn main() -> @location(0) vec4<f32> {
- var a : vec2<f32> = vec2<f32>();
- bar();
- return vec4<f32>(0.4, 0.4, 0.8, 1.0);
-}
diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.spvasm b/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.spvasm
deleted file mode 100644
index f07e733..0000000
--- a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.spvasm
+++ /dev/null
@@ -1,47 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 25
-; Schema: 0
- OpCapability Shader
- OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %main "main" %value
- OpExecutionMode %main OriginUpperLeft
- OpName %value "value"
- OpName %bar "bar"
- OpName %main_inner "main_inner"
- OpName %a "a"
- OpName %main "main"
- OpDecorate %value Location 0
- %float = OpTypeFloat 32
- %v4float = OpTypeVector %float 4
-%_ptr_Output_v4float = OpTypePointer Output %v4float
- %5 = OpConstantNull %v4float
- %value = OpVariable %_ptr_Output_v4float Output %5
- %void = OpTypeVoid
- %6 = OpTypeFunction %void
- %10 = OpTypeFunction %v4float
- %v2float = OpTypeVector %float 2
- %14 = OpConstantNull %v2float
-%_ptr_Function_v2float = OpTypePointer Function %v2float
-%float_0_400000006 = OpConstant %float 0.400000006
-%float_0_800000012 = OpConstant %float 0.800000012
- %float_1 = OpConstant %float 1
- %21 = OpConstantComposite %v4float %float_0_400000006 %float_0_400000006 %float_0_800000012 %float_1
- %bar = OpFunction %void None %6
- %9 = OpLabel
- OpReturn
- OpFunctionEnd
- %main_inner = OpFunction %v4float None %10
- %12 = OpLabel
- %a = OpVariable %_ptr_Function_v2float Function %14
- OpStore %a %14
- %17 = OpFunctionCall %void %bar
- OpReturnValue %21
- OpFunctionEnd
- %main = OpFunction %void None %6
- %23 = OpLabel
- %24 = OpFunctionCall %v4float %main_inner
- OpStore %value %24
- OpReturn
- OpFunctionEnd
diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.wgsl b/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.wgsl
deleted file mode 100644
index 987fb57..0000000
--- a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.wgsl
+++ /dev/null
@@ -1,11 +0,0 @@
-enable InternalExtensionForTesting;
-
-fn bar() {
-}
-
-@stage(fragment)
-fn main() -> @location(0) vec4<f32> {
- var a : vec2<f32> = vec2<f32>();
- bar();
- return vec4<f32>(0.400000006, 0.400000006, 0.800000012, 1.0);
-}
diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl b/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl
deleted file mode 100644
index c20b453..0000000
--- a/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2022 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Enable a void internal extension for multiple times
-enable InternalExtensionForTesting;
-enable InternalExtensionForTesting;
-enable InternalExtensionForTesting;
-
-fn bar() {
-}
-
-@stage(fragment)
-fn main() -> @location(0) vec4<f32> {
- var a : vec2<f32> = vec2<f32>();
- bar();
- return vec4<f32>(0.4, 0.4, 0.8, 1.0);
-}
diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.glsl b/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.glsl
deleted file mode 100644
index 995583f..0000000
--- a/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.glsl
+++ /dev/null
@@ -1,18 +0,0 @@
-#version 310 es
-precision mediump float;
-
-layout(location = 0) out vec4 value;
-void bar() {
-}
-
-vec4 tint_symbol() {
- vec2 a = vec2(0.0f, 0.0f);
- bar();
- return vec4(0.400000006f, 0.400000006f, 0.800000012f, 1.0f);
-}
-
-void main() {
- vec4 inner_result = tint_symbol();
- value = inner_result;
- return;
-}
diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.hlsl b/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.hlsl
deleted file mode 100644
index 93c7fa7..0000000
--- a/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.hlsl
+++ /dev/null
@@ -1,19 +0,0 @@
-void bar() {
-}
-
-struct tint_symbol {
- float4 value : SV_Target0;
-};
-
-float4 main_inner() {
- float2 a = float2(0.0f, 0.0f);
- bar();
- return float4(0.400000006f, 0.400000006f, 0.800000012f, 1.0f);
-}
-
-tint_symbol main() {
- const float4 inner_result = main_inner();
- tint_symbol wrapper_result = (tint_symbol)0;
- wrapper_result.value = inner_result;
- return wrapper_result;
-}
diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.msl b/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.msl
deleted file mode 100644
index d7fde53..0000000
--- a/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.msl
+++ /dev/null
@@ -1,23 +0,0 @@
-#include <metal_stdlib>
-
-using namespace metal;
-void bar() {
-}
-
-struct tint_symbol_1 {
- float4 value [[color(0)]];
-};
-
-float4 tint_symbol_inner() {
- float2 a = float2();
- bar();
- return float4(0.400000006f, 0.400000006f, 0.800000012f, 1.0f);
-}
-
-fragment tint_symbol_1 tint_symbol() {
- float4 const inner_result = tint_symbol_inner();
- tint_symbol_1 wrapper_result = {};
- wrapper_result.value = inner_result;
- return wrapper_result;
-}
-
diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.spvasm b/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.spvasm
deleted file mode 100644
index f07e733..0000000
--- a/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.spvasm
+++ /dev/null
@@ -1,47 +0,0 @@
-; SPIR-V
-; Version: 1.3
-; Generator: Google Tint Compiler; 0
-; Bound: 25
-; Schema: 0
- OpCapability Shader
- OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %main "main" %value
- OpExecutionMode %main OriginUpperLeft
- OpName %value "value"
- OpName %bar "bar"
- OpName %main_inner "main_inner"
- OpName %a "a"
- OpName %main "main"
- OpDecorate %value Location 0
- %float = OpTypeFloat 32
- %v4float = OpTypeVector %float 4
-%_ptr_Output_v4float = OpTypePointer Output %v4float
- %5 = OpConstantNull %v4float
- %value = OpVariable %_ptr_Output_v4float Output %5
- %void = OpTypeVoid
- %6 = OpTypeFunction %void
- %10 = OpTypeFunction %v4float
- %v2float = OpTypeVector %float 2
- %14 = OpConstantNull %v2float
-%_ptr_Function_v2float = OpTypePointer Function %v2float
-%float_0_400000006 = OpConstant %float 0.400000006
-%float_0_800000012 = OpConstant %float 0.800000012
- %float_1 = OpConstant %float 1
- %21 = OpConstantComposite %v4float %float_0_400000006 %float_0_400000006 %float_0_800000012 %float_1
- %bar = OpFunction %void None %6
- %9 = OpLabel
- OpReturn
- OpFunctionEnd
- %main_inner = OpFunction %v4float None %10
- %12 = OpLabel
- %a = OpVariable %_ptr_Function_v2float Function %14
- OpStore %a %14
- %17 = OpFunctionCall %void %bar
- OpReturnValue %21
- OpFunctionEnd
- %main = OpFunction %void None %6
- %23 = OpLabel
- %24 = OpFunctionCall %v4float %main_inner
- OpStore %value %24
- OpReturn
- OpFunctionEnd
diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.wgsl b/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.wgsl
deleted file mode 100644
index 987fb57..0000000
--- a/test/tint/extensions/InternalExtensionForTesting/simple_with_duplicated_InternalExtensionForTesting.wgsl.expected.wgsl
+++ /dev/null
@@ -1,11 +0,0 @@
-enable InternalExtensionForTesting;
-
-fn bar() {
-}
-
-@stage(fragment)
-fn main() -> @location(0) vec4<f32> {
- var a : vec2<f32> = vec2<f32>();
- bar();
- return vec4<f32>(0.400000006, 0.400000006, 0.800000012, 1.0);
-}
diff --git a/test/tint/extensions/parsing/basic.wgsl b/test/tint/extensions/parsing/basic.wgsl
new file mode 100644
index 0000000..d1d3017
--- /dev/null
+++ b/test/tint/extensions/parsing/basic.wgsl
@@ -0,0 +1,7 @@
+// Enable a void internal extension
+enable f16;
+
+@stage(fragment)
+fn main() -> @location(0) vec4<f32> {
+ return vec4<f32>(0.1, 0.2, 0.3, 0.4);
+}
diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.glsl b/test/tint/extensions/parsing/basic.wgsl.expected.glsl
similarity index 61%
rename from test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.glsl
rename to test/tint/extensions/parsing/basic.wgsl.expected.glsl
index 995583f..b094b6e 100644
--- a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.glsl
+++ b/test/tint/extensions/parsing/basic.wgsl.expected.glsl
@@ -2,13 +2,8 @@
precision mediump float;
layout(location = 0) out vec4 value;
-void bar() {
-}
-
vec4 tint_symbol() {
- vec2 a = vec2(0.0f, 0.0f);
- bar();
- return vec4(0.400000006f, 0.400000006f, 0.800000012f, 1.0f);
+ return vec4(0.100000001f, 0.200000003f, 0.300000012f, 0.400000006f);
}
void main() {
diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.hlsl b/test/tint/extensions/parsing/basic.wgsl.expected.hlsl
similarity index 67%
rename from test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.hlsl
rename to test/tint/extensions/parsing/basic.wgsl.expected.hlsl
index 93c7fa7..1af441a 100644
--- a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.hlsl
+++ b/test/tint/extensions/parsing/basic.wgsl.expected.hlsl
@@ -1,14 +1,9 @@
-void bar() {
-}
-
struct tint_symbol {
float4 value : SV_Target0;
};
float4 main_inner() {
- float2 a = float2(0.0f, 0.0f);
- bar();
- return float4(0.400000006f, 0.400000006f, 0.800000012f, 1.0f);
+ return float4(0.100000001f, 0.200000003f, 0.300000012f, 0.400000006f);
}
tint_symbol main() {
diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.msl b/test/tint/extensions/parsing/basic.wgsl.expected.msl
similarity index 74%
rename from test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.msl
rename to test/tint/extensions/parsing/basic.wgsl.expected.msl
index d7fde53..dc91926 100644
--- a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.msl
+++ b/test/tint/extensions/parsing/basic.wgsl.expected.msl
@@ -1,17 +1,12 @@
#include <metal_stdlib>
using namespace metal;
-void bar() {
-}
-
struct tint_symbol_1 {
float4 value [[color(0)]];
};
float4 tint_symbol_inner() {
- float2 a = float2();
- bar();
- return float4(0.400000006f, 0.400000006f, 0.800000012f, 1.0f);
+ return float4(0.100000001f, 0.200000003f, 0.300000012f, 0.400000006f);
}
fragment tint_symbol_1 tint_symbol() {
diff --git a/test/tint/extensions/parsing/basic.wgsl.expected.spvasm b/test/tint/extensions/parsing/basic.wgsl.expected.spvasm
new file mode 100644
index 0000000..225da82
--- /dev/null
+++ b/test/tint/extensions/parsing/basic.wgsl.expected.spvasm
@@ -0,0 +1,36 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 19
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %value
+ OpExecutionMode %main OriginUpperLeft
+ OpName %value "value"
+ OpName %main_inner "main_inner"
+ OpName %main "main"
+ OpDecorate %value Location 0
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+ %5 = OpConstantNull %v4float
+ %value = OpVariable %_ptr_Output_v4float Output %5
+ %6 = OpTypeFunction %v4float
+%float_0_100000001 = OpConstant %float 0.100000001
+%float_0_200000003 = OpConstant %float 0.200000003
+%float_0_300000012 = OpConstant %float 0.300000012
+%float_0_400000006 = OpConstant %float 0.400000006
+ %13 = OpConstantComposite %v4float %float_0_100000001 %float_0_200000003 %float_0_300000012 %float_0_400000006
+ %void = OpTypeVoid
+ %14 = OpTypeFunction %void
+ %main_inner = OpFunction %v4float None %6
+ %8 = OpLabel
+ OpReturnValue %13
+ OpFunctionEnd
+ %main = OpFunction %void None %14
+ %17 = OpLabel
+ %18 = OpFunctionCall %v4float %main_inner
+ OpStore %value %18
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/extensions/parsing/basic.wgsl.expected.wgsl b/test/tint/extensions/parsing/basic.wgsl.expected.wgsl
new file mode 100644
index 0000000..c084b23
--- /dev/null
+++ b/test/tint/extensions/parsing/basic.wgsl.expected.wgsl
@@ -0,0 +1,6 @@
+enable f16;
+
+@stage(fragment)
+fn main() -> @location(0) vec4<f32> {
+ return vec4<f32>(0.100000001, 0.200000003, 0.300000012, 0.400000006);
+}
diff --git a/test/tint/extensions/parsing/duplicated_extensions.wgsl b/test/tint/extensions/parsing/duplicated_extensions.wgsl
new file mode 100644
index 0000000..d72f18d
--- /dev/null
+++ b/test/tint/extensions/parsing/duplicated_extensions.wgsl
@@ -0,0 +1,9 @@
+// Enable a void internal extension for multiple times
+enable f16;
+enable f16;
+enable f16;
+
+@stage(fragment)
+fn main() -> @location(0) vec4<f32> {
+ return vec4<f32>(0.1, 0.2, 0.3, 0.4);
+}
diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.glsl b/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.glsl
similarity index 61%
copy from test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.glsl
copy to test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.glsl
index 995583f..b094b6e 100644
--- a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.glsl
+++ b/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.glsl
@@ -2,13 +2,8 @@
precision mediump float;
layout(location = 0) out vec4 value;
-void bar() {
-}
-
vec4 tint_symbol() {
- vec2 a = vec2(0.0f, 0.0f);
- bar();
- return vec4(0.400000006f, 0.400000006f, 0.800000012f, 1.0f);
+ return vec4(0.100000001f, 0.200000003f, 0.300000012f, 0.400000006f);
}
void main() {
diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.hlsl b/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.hlsl
similarity index 67%
copy from test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.hlsl
copy to test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.hlsl
index 93c7fa7..1af441a 100644
--- a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.hlsl
+++ b/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.hlsl
@@ -1,14 +1,9 @@
-void bar() {
-}
-
struct tint_symbol {
float4 value : SV_Target0;
};
float4 main_inner() {
- float2 a = float2(0.0f, 0.0f);
- bar();
- return float4(0.400000006f, 0.400000006f, 0.800000012f, 1.0f);
+ return float4(0.100000001f, 0.200000003f, 0.300000012f, 0.400000006f);
}
tint_symbol main() {
diff --git a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.msl b/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.msl
similarity index 74%
copy from test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.msl
copy to test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.msl
index d7fde53..dc91926 100644
--- a/test/tint/extensions/InternalExtensionForTesting/simple_with_InternalExtensionForTesting.wgsl.expected.msl
+++ b/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.msl
@@ -1,17 +1,12 @@
#include <metal_stdlib>
using namespace metal;
-void bar() {
-}
-
struct tint_symbol_1 {
float4 value [[color(0)]];
};
float4 tint_symbol_inner() {
- float2 a = float2();
- bar();
- return float4(0.400000006f, 0.400000006f, 0.800000012f, 1.0f);
+ return float4(0.100000001f, 0.200000003f, 0.300000012f, 0.400000006f);
}
fragment tint_symbol_1 tint_symbol() {
diff --git a/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.spvasm b/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.spvasm
new file mode 100644
index 0000000..225da82
--- /dev/null
+++ b/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.spvasm
@@ -0,0 +1,36 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 19
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %value
+ OpExecutionMode %main OriginUpperLeft
+ OpName %value "value"
+ OpName %main_inner "main_inner"
+ OpName %main "main"
+ OpDecorate %value Location 0
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+ %5 = OpConstantNull %v4float
+ %value = OpVariable %_ptr_Output_v4float Output %5
+ %6 = OpTypeFunction %v4float
+%float_0_100000001 = OpConstant %float 0.100000001
+%float_0_200000003 = OpConstant %float 0.200000003
+%float_0_300000012 = OpConstant %float 0.300000012
+%float_0_400000006 = OpConstant %float 0.400000006
+ %13 = OpConstantComposite %v4float %float_0_100000001 %float_0_200000003 %float_0_300000012 %float_0_400000006
+ %void = OpTypeVoid
+ %14 = OpTypeFunction %void
+ %main_inner = OpFunction %v4float None %6
+ %8 = OpLabel
+ OpReturnValue %13
+ OpFunctionEnd
+ %main = OpFunction %void None %14
+ %17 = OpLabel
+ %18 = OpFunctionCall %v4float %main_inner
+ OpStore %value %18
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.wgsl b/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.wgsl
new file mode 100644
index 0000000..be5f381
--- /dev/null
+++ b/test/tint/extensions/parsing/duplicated_extensions.wgsl.expected.wgsl
@@ -0,0 +1,8 @@
+enable f16;
+enable f16;
+enable f16;
+
+@stage(fragment)
+fn main() -> @location(0) vec4<f32> {
+ return vec4<f32>(0.100000001, 0.200000003, 0.300000012, 0.400000006);
+}