Files
wgpu/naga/tests/out/spv/shadow.spvasm
Jamie Nicol b7d1f4c6cf [naga spv-out] Ensure loops generated by SPIRV backend are bounded (#7080)
If it is undefined behaviour for loops to be infinite, then, when
encountering an infinite loop, downstream compilers are able to make
certain optimizations that may be unsafe. For example, omitting bounds
checks. To prevent this, we must ensure that any loops emitted by our
backends are provably bounded. We already do this for both the MSL and
HLSL backends. This patch makes us do so for SPIRV as well.

The construct used is the same as for HLSL and MSL backends: use a
vec2<u32> to emulate a 64-bit counter, which is incremented every
iteration and breaks after 2^64 iterations.

While the implementation is fairly verbose for the SPIRV backend, the
logic is simple enough. The one point of note is that SPIRV requires
`OpVariable` instructions with a `Function` storage class to be
located at the start of the first block of the function. We therefore
remember the IDs generated for each loop counter variable in a
function whilst generating the function body's code. The instructions
to declare these variables are then emitted in `Function::to_words()`
prior to emitting the function's body.

As this may negatively impact shader performance, this workaround can
be disabled using the same mechanism as for other backends: eg calling
Device::create_shader_module_trusted() and setting the
ShaderRuntimeChecks::force_loop_bounding flag to false.
2025-02-25 15:23:44 +01:00

635 lines
17 KiB
Plaintext

; SPIR-V
; Version: 1.2
; Generator: rspirv
; Bound: 294
OpCapability Shader
OpExtension "SPV_KHR_storage_buffer_storage_class"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %85 "vs_main" %75 %78 %80 %82 %84
OpEntryPoint Fragment %143 "fs_main" %134 %137 %140 %142
OpEntryPoint Fragment %228 "fs_main_without_storage" %221 %223 %225 %227
OpExecutionMode %143 OriginUpperLeft
OpExecutionMode %228 OriginUpperLeft
%3 = OpString "shadow.wgsl"
OpSource Unknown 0 %3 "struct Globals {
view_proj: mat4x4<f32>,
num_lights: vec4<u32>,
}
@group(0)
@binding(0)
var<uniform> u_globals: Globals;
struct Entity {
world: mat4x4<f32>,
color: vec4<f32>,
}
@group(1)
@binding(0)
var<uniform> u_entity: Entity;
/* Not useful for testing
@vertex
fn vs_bake(@location(0) position: vec4<i32>) -> @builtin(position) vec4<f32> {
return u_globals.view_proj * u_entity.world * vec4<f32>(position);
}
*/
struct VertexOutput {
@builtin(position) proj_position: vec4<f32>,
@location(0) world_normal: vec3<f32>,
@location(1) world_position: vec4<f32>,
}
@vertex
fn vs_main(
@location(0) position: vec4<i32>,
@location(1) normal: vec4<i32>,
) -> VertexOutput {
let w = u_entity.world;
let world_pos = u_entity.world * vec4<f32>(position);
var out: VertexOutput;
out.world_normal = mat3x3<f32>(w[0].xyz, w[1].xyz, w[2].xyz) * vec3<f32>(normal.xyz);
out.world_position = world_pos;
out.proj_position = u_globals.view_proj * world_pos;
return out;
}
// fragment shader
struct Light {
proj: mat4x4<f32>,
pos: vec4<f32>,
color: vec4<f32>,
}
@group(0)
@binding(1)
var<storage, read> s_lights: array<Light>;
@group(0)
@binding(1)
var<uniform> u_lights: array<Light, 10>; // Used when storage types are not supported
@group(0)
@binding(2)
var t_shadow: texture_depth_2d_array;
@group(0)
@binding(3)
var sampler_shadow: sampler_comparison;
fn fetch_shadow(light_id: u32, homogeneous_coords: vec4<f32>) -> f32 {
if (homogeneous_coords.w <= 0.0) {
return 1.0;
}
// compensate for the Y-flip difference between the NDC and texture coordinates
let flip_correction = vec2<f32>(0.5, -0.5);
// compute texture coordinates for shadow lookup
let proj_correction = 1.0 / homogeneous_coords.w;
let light_local = homogeneous_coords.xy * flip_correction * proj_correction + vec2<f32>(0.5, 0.5);
// do the lookup, using HW PCF and comparison
return textureSampleCompareLevel(t_shadow, sampler_shadow, light_local, i32(light_id), homogeneous_coords.z * proj_correction);
}
const c_ambient: vec3<f32> = vec3<f32>(0.05, 0.05, 0.05);
const c_max_lights: u32 = 10u;
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
let normal = normalize(in.world_normal);
// accumulate color
var color: vec3<f32> = c_ambient;
for(var i = 0u; i < min(u_globals.num_lights.x, c_max_lights); i++) {
let light = s_lights[i];
// project into the light space
let shadow = fetch_shadow(i, light.proj * in.world_position);
// compute Lambertian diffuse term
let light_dir = normalize(light.pos.xyz - in.world_position.xyz);
let diffuse = max(0.0, dot(normal, light_dir));
// add light contribution
color += shadow * diffuse * light.color.xyz;
}
// multiply the light by material color
return vec4<f32>(color, 1.0) * u_entity.color;
}
// The fragment entrypoint used when storage buffers are not available for the lights
@fragment
fn fs_main_without_storage(in: VertexOutput) -> @location(0) vec4<f32> {
let normal = normalize(in.world_normal);
var color: vec3<f32> = c_ambient;
for(var i = 0u; i < min(u_globals.num_lights.x, c_max_lights); i++) {
// This line is the only difference from the entrypoint above. It uses the lights
// uniform instead of the lights storage buffer
let light = u_lights[i];
let shadow = fetch_shadow(i, light.proj * in.world_position);
let light_dir = normalize(light.pos.xyz - in.world_position.xyz);
let diffuse = max(0.0, dot(normal, light_dir));
color += shadow * diffuse * light.color.xyz;
}
return vec4<f32>(color, 1.0) * u_entity.color;
}
"
OpMemberName %9 0 "view_proj"
OpMemberName %9 1 "num_lights"
OpName %9 "Globals"
OpMemberName %10 0 "world"
OpMemberName %10 1 "color"
OpName %10 "Entity"
OpMemberName %12 0 "proj_position"
OpMemberName %12 1 "world_normal"
OpMemberName %12 2 "world_position"
OpName %12 "VertexOutput"
OpMemberName %16 0 "proj"
OpMemberName %16 1 "pos"
OpMemberName %16 2 "color"
OpName %16 "Light"
OpName %24 "c_ambient"
OpName %19 "c_max_lights"
OpName %25 "u_globals"
OpName %28 "u_entity"
OpName %31 "s_lights"
OpName %34 "u_lights"
OpName %37 "t_shadow"
OpName %39 "sampler_shadow"
OpName %42 "light_id"
OpName %43 "homogeneous_coords"
OpName %44 "fetch_shadow"
OpName %75 "position"
OpName %78 "normal"
OpName %80 "proj_position"
OpName %82 "world_normal"
OpName %84 "world_position"
OpName %85 "vs_main"
OpName %92 "out"
OpName %134 "proj_position"
OpName %137 "world_normal"
OpName %140 "world_position"
OpName %143 "fs_main"
OpName %150 "color"
OpName %151 "i"
OpName %166 "loop_bound"
OpName %221 "proj_position"
OpName %223 "world_normal"
OpName %225 "world_position"
OpName %228 "fs_main_without_storage"
OpName %235 "color"
OpName %236 "i"
OpName %244 "loop_bound"
OpMemberDecorate %9 0 Offset 0
OpMemberDecorate %9 0 ColMajor
OpMemberDecorate %9 0 MatrixStride 16
OpMemberDecorate %9 1 Offset 64
OpMemberDecorate %10 0 Offset 0
OpMemberDecorate %10 0 ColMajor
OpMemberDecorate %10 0 MatrixStride 16
OpMemberDecorate %10 1 Offset 64
OpMemberDecorate %12 0 Offset 0
OpMemberDecorate %12 1 Offset 16
OpMemberDecorate %12 2 Offset 32
OpMemberDecorate %16 0 Offset 0
OpMemberDecorate %16 0 ColMajor
OpMemberDecorate %16 0 MatrixStride 16
OpMemberDecorate %16 1 Offset 64
OpMemberDecorate %16 2 Offset 80
OpDecorate %17 ArrayStride 96
OpDecorate %18 ArrayStride 96
OpDecorate %25 DescriptorSet 0
OpDecorate %25 Binding 0
OpDecorate %26 Block
OpMemberDecorate %26 0 Offset 0
OpDecorate %28 DescriptorSet 1
OpDecorate %28 Binding 0
OpDecorate %29 Block
OpMemberDecorate %29 0 Offset 0
OpDecorate %31 NonWritable
OpDecorate %31 DescriptorSet 0
OpDecorate %31 Binding 1
OpDecorate %32 Block
OpMemberDecorate %32 0 Offset 0
OpDecorate %34 DescriptorSet 0
OpDecorate %34 Binding 1
OpDecorate %35 Block
OpMemberDecorate %35 0 Offset 0
OpDecorate %37 DescriptorSet 0
OpDecorate %37 Binding 2
OpDecorate %39 DescriptorSet 0
OpDecorate %39 Binding 3
OpDecorate %75 Location 0
OpDecorate %78 Location 1
OpDecorate %80 BuiltIn Position
OpDecorate %82 Location 0
OpDecorate %84 Location 1
OpDecorate %134 BuiltIn FragCoord
OpDecorate %137 Location 0
OpDecorate %140 Location 1
OpDecorate %142 Location 0
OpDecorate %221 BuiltIn FragCoord
OpDecorate %223 Location 0
OpDecorate %225 Location 1
OpDecorate %227 Location 0
%2 = OpTypeVoid
%4 = OpTypeFloat 32
%6 = OpTypeVector %4 4
%5 = OpTypeMatrix %6 4
%7 = OpTypeInt 32 0
%8 = OpTypeVector %7 4
%9 = OpTypeStruct %5 %8
%10 = OpTypeStruct %5 %6
%11 = OpTypeVector %4 3
%12 = OpTypeStruct %6 %11 %6
%14 = OpTypeInt 32 1
%13 = OpTypeVector %14 4
%15 = OpTypeMatrix %11 3
%16 = OpTypeStruct %5 %6 %6
%17 = OpTypeRuntimeArray %16
%19 = OpConstant %7 10
%18 = OpTypeArray %16 %19
%20 = OpTypeImage %4 2D 1 1 0 1 Unknown
%21 = OpTypeSampler
%22 = OpTypeVector %4 2
%23 = OpConstant %4 0.05
%24 = OpConstantComposite %11 %23 %23 %23
%26 = OpTypeStruct %9
%27 = OpTypePointer Uniform %26
%25 = OpVariable %27 Uniform
%29 = OpTypeStruct %10
%30 = OpTypePointer Uniform %29
%28 = OpVariable %30 Uniform
%32 = OpTypeStruct %17
%33 = OpTypePointer StorageBuffer %32
%31 = OpVariable %33 StorageBuffer
%35 = OpTypeStruct %18
%36 = OpTypePointer Uniform %35
%34 = OpVariable %36 Uniform
%38 = OpTypePointer UniformConstant %20
%37 = OpVariable %38 UniformConstant
%40 = OpTypePointer UniformConstant %21
%39 = OpVariable %40 UniformConstant
%45 = OpTypeFunction %4 %7 %6
%48 = OpConstant %4 0.0
%49 = OpConstant %4 1.0
%50 = OpConstant %4 0.5
%51 = OpConstant %4 -0.5
%52 = OpConstantComposite %22 %50 %51
%53 = OpConstantComposite %22 %50 %50
%56 = OpTypeBool
%69 = OpTypeSampledImage %20
%76 = OpTypePointer Input %13
%75 = OpVariable %76 Input
%78 = OpVariable %76 Input
%81 = OpTypePointer Output %6
%80 = OpVariable %81 Output
%83 = OpTypePointer Output %11
%82 = OpVariable %83 Output
%84 = OpVariable %81 Output
%86 = OpTypeFunction %2
%87 = OpTypePointer Uniform %9
%88 = OpConstant %7 0
%90 = OpTypePointer Uniform %10
%93 = OpTypePointer Function %12
%94 = OpConstantNull %12
%96 = OpTypePointer Uniform %5
%103 = OpTypePointer Function %11
%111 = OpTypeVector %14 3
%115 = OpConstant %7 1
%117 = OpTypePointer Function %6
%118 = OpConstant %7 2
%126 = OpTypePointer Output %4
%135 = OpTypePointer Input %6
%134 = OpVariable %135 Input
%138 = OpTypePointer Input %11
%137 = OpVariable %138 Input
%140 = OpVariable %135 Input
%142 = OpVariable %81 Output
%146 = OpTypePointer StorageBuffer %17
%152 = OpTypePointer Function %7
%160 = OpTypeVector %7 2
%161 = OpTypePointer Function %160
%162 = OpTypeVector %56 2
%163 = OpConstantComposite %160 %88 %88
%164 = OpConstant %7 4294967295
%165 = OpConstantComposite %160 %164 %164
%178 = OpTypePointer Uniform %8
%179 = OpTypePointer Uniform %7
%189 = OpTypePointer StorageBuffer %16
%215 = OpTypePointer Uniform %6
%221 = OpVariable %135 Input
%223 = OpVariable %138 Input
%225 = OpVariable %135 Input
%227 = OpVariable %81 Output
%231 = OpTypePointer Uniform %18
%265 = OpTypePointer Uniform %16
%44 = OpFunction %4 None %45
%42 = OpFunctionParameter %7
%43 = OpFunctionParameter %6
%41 = OpLabel
%46 = OpLoad %20 %37
%47 = OpLoad %21 %39
OpBranch %54
%54 = OpLabel
OpLine %3 68 9
%55 = OpCompositeExtract %4 %43 3
OpLine %3 68 9
%57 = OpFOrdLessThanEqual %56 %55 %48
OpLine %3 68 5
OpSelectionMerge %58 None
OpBranchConditional %57 %59 %58
%59 = OpLabel
OpReturnValue %49
%58 = OpLabel
OpLine %3 72 27
OpLine %3 74 33
%60 = OpCompositeExtract %4 %43 3
OpLine %3 74 27
%61 = OpFDiv %4 %49 %60
OpLine %3 75 23
%62 = OpVectorShuffle %22 %43 %43 0 1
%63 = OpFMul %22 %62 %52
%64 = OpVectorTimesScalar %22 %63 %61
OpLine %3 75 23
%65 = OpFAdd %22 %64 %53
OpLine %3 77 12
%66 = OpBitcast %14 %42
%67 = OpCompositeExtract %4 %43 2
%68 = OpFMul %4 %67 %61
%70 = OpConvertSToF %4 %66
%71 = OpCompositeConstruct %11 %65 %70
%72 = OpSampledImage %69 %46 %47
%73 = OpImageSampleDrefExplicitLod %4 %72 %71 %68 Lod %48
OpReturnValue %73
OpFunctionEnd
%85 = OpFunction %2 None %86
%74 = OpLabel
%92 = OpVariable %93 Function %94
%77 = OpLoad %13 %75
%79 = OpLoad %13 %78
%89 = OpAccessChain %87 %25 %88
%91 = OpAccessChain %90 %28 %88
OpBranch %95
%95 = OpLabel
OpLine %3 37 13
%97 = OpAccessChain %96 %91 %88
%98 = OpLoad %5 %97
OpLine %3 38 21
%99 = OpAccessChain %96 %91 %88
%100 = OpLoad %5 %99
%101 = OpConvertSToF %6 %77
%102 = OpMatrixTimesVector %6 %100 %101
OpLine %3 40 5
OpLine %3 40 36
%104 = OpCompositeExtract %6 %98 0
%105 = OpVectorShuffle %11 %104 %104 0 1 2
OpLine %3 40 46
%106 = OpCompositeExtract %6 %98 1
%107 = OpVectorShuffle %11 %106 %106 0 1 2
OpLine %3 40 24
%108 = OpCompositeExtract %6 %98 2
%109 = OpVectorShuffle %11 %108 %108 0 1 2
%110 = OpCompositeConstruct %15 %105 %107 %109
%112 = OpVectorShuffle %111 %79 %79 0 1 2
%113 = OpConvertSToF %11 %112
%114 = OpMatrixTimesVector %11 %110 %113
OpLine %3 40 5
%116 = OpAccessChain %103 %92 %115
OpStore %116 %114
OpLine %3 41 5
OpLine %3 41 5
%119 = OpAccessChain %117 %92 %118
OpStore %119 %102
OpLine %3 42 5
OpLine %3 42 25
%120 = OpAccessChain %96 %89 %88
%121 = OpLoad %5 %120
%122 = OpMatrixTimesVector %6 %121 %102
OpLine %3 42 5
%123 = OpAccessChain %117 %92 %88
OpStore %123 %122
OpLine %3 1 1
%124 = OpLoad %12 %92
%125 = OpCompositeExtract %6 %124 0
OpStore %80 %125
%127 = OpAccessChain %126 %80 %115
%128 = OpLoad %4 %127
%129 = OpFNegate %4 %128
OpStore %127 %129
%130 = OpCompositeExtract %11 %124 1
OpStore %82 %130
%131 = OpCompositeExtract %6 %124 2
OpStore %84 %131
OpReturn
OpFunctionEnd
%143 = OpFunction %2 None %86
%132 = OpLabel
%150 = OpVariable %103 Function %24
%151 = OpVariable %152 Function %88
%166 = OpVariable %161 Function %163
%136 = OpLoad %6 %134
%139 = OpLoad %11 %137
%141 = OpLoad %6 %140
%133 = OpCompositeConstruct %12 %136 %139 %141
%144 = OpAccessChain %87 %25 %88
%145 = OpAccessChain %90 %28 %88
%147 = OpAccessChain %146 %31 %88
%148 = OpLoad %20 %37
%149 = OpLoad %21 %39
OpBranch %153
%153 = OpLabel
OpLine %3 85 18
%154 = OpCompositeExtract %11 %133 1
%155 = OpExtInst %11 %1 Normalize %154
OpBranch %156
%156 = OpLabel
OpLine %3 88 5
OpLoopMerge %157 %159 None
OpBranch %167
%167 = OpLabel
%168 = OpLoad %160 %166
%169 = OpIEqual %162 %165 %168
%170 = OpAll %56 %169
OpSelectionMerge %171 None
OpBranchConditional %170 %157 %171
%171 = OpLabel
%172 = OpCompositeExtract %7 %168 1
%173 = OpIEqual %56 %172 %164
%174 = OpSelect %7 %173 %115 %88
%175 = OpCompositeConstruct %160 %174 %115
%176 = OpIAdd %160 %168 %175
OpStore %166 %176
OpBranch %158
%158 = OpLabel
OpLine %3 1 1
%177 = OpLoad %7 %151
OpLine %3 88 29
%180 = OpAccessChain %179 %144 %115 %88
%181 = OpLoad %7 %180
OpLine %3 88 21
%182 = OpExtInst %7 %1 UMin %181 %19
%183 = OpULessThan %56 %177 %182
OpLine %3 88 20
OpSelectionMerge %184 None
OpBranchConditional %183 %184 %185
%185 = OpLabel
OpBranch %157
%184 = OpLabel
OpBranch %186
%186 = OpLabel
OpLine %3 89 21
%188 = OpLoad %7 %151
%190 = OpAccessChain %189 %147 %188
%191 = OpLoad %16 %190
OpLine %3 91 38
%192 = OpLoad %7 %151
%193 = OpCompositeExtract %5 %191 0
%194 = OpCompositeExtract %6 %133 2
%195 = OpMatrixTimesVector %6 %193 %194
OpLine %3 91 22
%196 = OpFunctionCall %4 %44 %192 %195
OpLine %3 93 25
%197 = OpCompositeExtract %6 %191 1
%198 = OpVectorShuffle %11 %197 %197 0 1 2
%199 = OpCompositeExtract %6 %133 2
%200 = OpVectorShuffle %11 %199 %199 0 1 2
%201 = OpFSub %11 %198 %200
%202 = OpExtInst %11 %1 Normalize %201
OpLine %3 94 23
%203 = OpDot %4 %155 %202
%204 = OpExtInst %4 %1 FMax %48 %203
OpLine %3 96 9
%205 = OpFMul %4 %196 %204
%206 = OpCompositeExtract %6 %191 2
%207 = OpVectorShuffle %11 %206 %206 0 1 2
%208 = OpVectorTimesScalar %11 %207 %205
%209 = OpLoad %11 %150
%210 = OpFAdd %11 %209 %208
OpLine %3 96 9
OpStore %150 %210
OpBranch %187
%187 = OpLabel
OpBranch %159
%159 = OpLabel
OpLine %3 88 68
%211 = OpLoad %7 %151
%212 = OpIAdd %7 %211 %115
OpLine %3 88 68
OpStore %151 %212
OpBranch %156
%157 = OpLabel
OpLine %3 1 1
%213 = OpLoad %11 %150
OpLine %3 99 12
%214 = OpCompositeConstruct %6 %213 %49
OpLine %3 99 12
%216 = OpAccessChain %215 %145 %115
%217 = OpLoad %6 %216
%218 = OpFMul %6 %214 %217
OpStore %142 %218
OpReturn
OpFunctionEnd
%228 = OpFunction %2 None %86
%219 = OpLabel
%235 = OpVariable %103 Function %24
%236 = OpVariable %152 Function %88
%244 = OpVariable %161 Function %163
%222 = OpLoad %6 %221
%224 = OpLoad %11 %223
%226 = OpLoad %6 %225
%220 = OpCompositeConstruct %12 %222 %224 %226
%229 = OpAccessChain %87 %25 %88
%230 = OpAccessChain %90 %28 %88
%232 = OpAccessChain %231 %34 %88
%233 = OpLoad %20 %37
%234 = OpLoad %21 %39
OpBranch %237
%237 = OpLabel
OpLine %3 105 18
%238 = OpCompositeExtract %11 %220 1
%239 = OpExtInst %11 %1 Normalize %238
OpBranch %240
%240 = OpLabel
OpLine %3 107 5
OpLoopMerge %241 %243 None
OpBranch %245
%245 = OpLabel
%246 = OpLoad %160 %244
%247 = OpIEqual %162 %165 %246
%248 = OpAll %56 %247
OpSelectionMerge %249 None
OpBranchConditional %248 %241 %249
%249 = OpLabel
%250 = OpCompositeExtract %7 %246 1
%251 = OpIEqual %56 %250 %164
%252 = OpSelect %7 %251 %115 %88
%253 = OpCompositeConstruct %160 %252 %115
%254 = OpIAdd %160 %246 %253
OpStore %244 %254
OpBranch %242
%242 = OpLabel
OpLine %3 1 1
%255 = OpLoad %7 %236
OpLine %3 107 29
%256 = OpAccessChain %179 %229 %115 %88
%257 = OpLoad %7 %256
OpLine %3 107 21
%258 = OpExtInst %7 %1 UMin %257 %19
%259 = OpULessThan %56 %255 %258
OpLine %3 107 20
OpSelectionMerge %260 None
OpBranchConditional %259 %260 %261
%261 = OpLabel
OpBranch %241
%260 = OpLabel
OpBranch %262
%262 = OpLabel
OpLine %3 110 21
%264 = OpLoad %7 %236
%266 = OpAccessChain %265 %232 %264
%267 = OpLoad %16 %266
OpLine %3 111 38
%268 = OpLoad %7 %236
%269 = OpCompositeExtract %5 %267 0
%270 = OpCompositeExtract %6 %220 2
%271 = OpMatrixTimesVector %6 %269 %270
OpLine %3 111 22
%272 = OpFunctionCall %4 %44 %268 %271
OpLine %3 112 25
%273 = OpCompositeExtract %6 %267 1
%274 = OpVectorShuffle %11 %273 %273 0 1 2
%275 = OpCompositeExtract %6 %220 2
%276 = OpVectorShuffle %11 %275 %275 0 1 2
%277 = OpFSub %11 %274 %276
%278 = OpExtInst %11 %1 Normalize %277
OpLine %3 113 23
%279 = OpDot %4 %239 %278
%280 = OpExtInst %4 %1 FMax %48 %279
OpLine %3 114 9
%281 = OpFMul %4 %272 %280
%282 = OpCompositeExtract %6 %267 2
%283 = OpVectorShuffle %11 %282 %282 0 1 2
%284 = OpVectorTimesScalar %11 %283 %281
%285 = OpLoad %11 %235
%286 = OpFAdd %11 %285 %284
OpLine %3 114 9
OpStore %235 %286
OpBranch %263
%263 = OpLabel
OpBranch %243
%243 = OpLabel
OpLine %3 107 68
%287 = OpLoad %7 %236
%288 = OpIAdd %7 %287 %115
OpLine %3 107 68
OpStore %236 %288
OpBranch %240
%241 = OpLabel
OpLine %3 1 1
%289 = OpLoad %11 %235
OpLine %3 116 12
%290 = OpCompositeConstruct %6 %289 %49
OpLine %3 116 12
%291 = OpAccessChain %215 %230 %115
%292 = OpLoad %6 %291
%293 = OpFMul %6 %290 %292
OpStore %227 %293
OpReturn
OpFunctionEnd