Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Read WorkgroupSize as whole vector from the spec constant value #59

Merged
merged 3 commits into from Sep 19, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 14 additions & 4 deletions lib/DefineOpenCLWorkItemBuiltinsPass.cpp
Expand Up @@ -111,14 +111,22 @@ bool DefineOpenCLWorkItemBuiltinsPass::defineMappedBuiltin(Module &M, StringRef
Value *Select1 =
Builder.CreateSelect(Cond, &*F->arg_begin(), Builder.getInt32(0));

Value *Indices[] = {Builder.getInt32(0), Select1};
Value *GEP = Builder.CreateGEP(GV, Indices);
Value *Load = Builder.CreateLoad(GEP);
Value* Result = nullptr;
if (GlobalVarName == "__spirv_WorkgroupSize") {
// Ugly hack to work around implementation bugs.
// Load the whole vector and extract the result
Value *LoadVec = Builder.CreateLoad(GV);
Result = Builder.CreateExtractElement(LoadVec, Select1);
} else {
Value *Indices[] = {Builder.getInt32(0), Select1};
Value *GEP = Builder.CreateGEP(GV, Indices);
Result = Builder.CreateLoad(GEP);
}

// We also need to select on the result of the load, because if Cond is
// false, we need to return the default value to the user.
Value *Select2 =
Builder.CreateSelect(Cond, Load, Builder.getInt32(DefaultValue));
Builder.CreateSelect(Cond, Result, Builder.getInt32(DefaultValue));
Builder.CreateRet(Select2);

return true;
Expand Down Expand Up @@ -182,6 +190,8 @@ bool DefineOpenCLWorkItemBuiltinsPass::defineGlobalSizeBuiltin(Module &M) {
// false, we need to return the default value (1) to the user.
Value *Select2 = Builder.CreateSelect(Cond, Mul, Builder.getInt32(1));
Builder.CreateRet(Select2);

return true;
}

bool DefineOpenCLWorkItemBuiltinsPass::defineGlobalOffsetBuiltin(Module &M) {
Expand Down
58 changes: 55 additions & 3 deletions lib/SPIRVProducerPass.cpp
Expand Up @@ -118,7 +118,8 @@ struct SPIRVProducerPass final : public ModulePass {
binaryTempOut(binaryTempUnderlyingVector), binaryOut(&out),
descriptorMapOut(descriptor_map_out), outputAsm(outputAsm),
outputCInitList(outputCInitList), patchBoundOffset(0), nextID(1),
OpExtInstImportID(0), HasVariablePointers(false), SamplerTy(nullptr) {}
OpExtInstImportID(0), HasVariablePointers(false), SamplerTy(nullptr),
WorkgroupSizeValueID(0), WorkgroupSizeVarID(0) {}

void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<DominatorTreeWrapperPass>();
Expand Down Expand Up @@ -288,6 +289,17 @@ struct SPIRVProducerPass final : public ModulePass {
// These will require an ArrayStride decoration.
// See SPV_KHR_variable_pointers rev 13.
TypeList PointerTypesNeedingArrayStride;

// This is truly ugly, but works around what look like driver bugs.
// For get_local_size, an earlier part of the flow has created a module-scope
// variable in Private address space to hold the value for the workgroup
// size. Its intializer is a uint3 value marked as builtin WorkgroupSize.
// When this is present, save the IDs of the initializer value and variable
// in these two variables. We only ever do a vector load from it, and
// when we see one of those, substitute just the value of the intializer.
// This mimics what Glslang does, and that's what drivers are used to.
uint32_t WorkgroupSizeValueID;
uint32_t WorkgroupSizeVarID;
};

char SPIRVProducerPass::ID;
Expand Down Expand Up @@ -2432,6 +2444,9 @@ void SPIRVProducerPass::GenerateGlobalVar(GlobalVariable &GV) {
// its value, rather than the variable that we use to access the value.
if (spv::BuiltInWorkgroupSize == BuiltinType) {
ResultID = InitializerID;
// Save both the value and variable IDs for later.
WorkgroupSizeValueID = InitializerID;
WorkgroupSizeVarID = VMap[&GV];
} else {
ResultID = VMap[&GV];
}
Expand Down Expand Up @@ -4271,19 +4286,54 @@ void SPIRVProducerPass::GenerateInstruction(Instruction &I) {
// Generate OpLoad.
//

uint32_t ResTyID = lookupType(LD->getType());
uint32_t PointerID = VMap[LD->getPointerOperand()];

// This is a hack to work around what looks like a driver bug.
// When we're loading from the special variable holding the WorkgroupSize
// builtin value, use an OpBitWiseAnd of the value's ID rather than
// generating a load.
if (PointerID == WorkgroupSizeVarID) {
// Generate a bitwise-and of the original value with itself.
// We should have been able to get away with just an OpCopyObject,
// but we need something more complex to get past certain driver bugs.
// This is ridiculous, but necessary.
// TODO(dneto): Revisit this once drivers fix their bugs.

SPIRVOperandList Ops;

SPIRVOperand *ResTyIDOp =
new SPIRVOperand(SPIRVOperandType::NUMBERID, ResTyID);
Ops.push_back(ResTyIDOp);

SPIRVOperand *ValueIDOp0 =
new SPIRVOperand(SPIRVOperandType::NUMBERID, WorkgroupSizeValueID);
Ops.push_back(ValueIDOp0);

SPIRVOperand *ValueIDOp1 =
new SPIRVOperand(SPIRVOperandType::NUMBERID, WorkgroupSizeValueID);
Ops.push_back(ValueIDOp1);

SPIRVInstruction *Inst =
new SPIRVInstruction(5, spv::OpBitwiseAnd, nextID++, Ops);
SPIRVInstList.push_back(Inst);
break;
}

// This is the normal path. Generate a load.

// Ops[0] = Result Type ID
// Ops[1] = Pointer ID
// Ops[2] ... Ops[n] = Optional Memory Access
//
// TODO: Do we need to implement Optional Memory Access???

SPIRVOperandList Ops;

uint32_t ResTyID = lookupType(LD->getType());
SPIRVOperand *ResTyIDOp =
new SPIRVOperand(SPIRVOperandType::NUMBERID, ResTyID);
Ops.push_back(ResTyIDOp);

uint32_t PointerID = VMap[LD->getPointerOperand()];
SPIRVOperand *PointerIDOp =
new SPIRVOperand(SPIRVOperandType::NUMBERID, PointerID);
Ops.push_back(PointerIDOp);
Expand Down Expand Up @@ -5862,6 +5912,7 @@ void SPIRVProducerPass::WriteSPIRVAssembly() {
case spv::OpCompositeExtract:
case spv::OpVectorExtractDynamic:
case spv::OpCompositeInsert:
case spv::OpCopyObject:
case spv::OpVectorInsertDynamic:
case spv::OpVectorShuffle:
case spv::OpIEqual:
Expand Down Expand Up @@ -6088,6 +6139,7 @@ void SPIRVProducerPass::WriteSPIRVBinary() {
case spv::OpCompositeExtract:
case spv::OpVectorExtractDynamic:
case spv::OpCompositeInsert:
case spv::OpCopyObject:
case spv::OpVectorInsertDynamic:
case spv::OpVectorShuffle:
case spv::OpIEqual:
Expand Down
21 changes: 10 additions & 11 deletions test/VaryingLocalSizes/one_kernel.cl
Expand Up @@ -8,7 +8,7 @@
// CHECK: ; SPIR-V
// CHECK: ; Version: 1.0
// CHECK: ; Generator: Codeplay; 0
// CHECK: ; Bound: 33
// CHECK: ; Bound: 32
// CHECK: ; Schema: 0
// CHECK: OpCapability Shader
// CHECK: OpCapability VariablePointers
Expand All @@ -33,7 +33,6 @@
// CHECK: %[[FOO_TYPE_ID:[a-zA-Z0-9_]*]] = OpTypeFunction %[[VOID_TYPE_ID]]
// CHECK: %[[UINT3_TYPE_ID:[a-zA-Z0-9_]*]] = OpTypeVector %[[UINT_TYPE_ID]] 3
// CHECK: %[[UINT3_PRIVATE_POINTER_TYPE_ID:[a-zA-Z0-9_]*]] = OpTypePointer Private %[[UINT3_TYPE_ID]]
// CHECK: %[[UINT_PRIVATE_POINTER_TYPE_ID:[a-zA-Z0-9_]*]] = OpTypePointer Private %[[UINT_TYPE_ID]]
// CHECK: %[[CONSTANT_0_ID:[a-zA-Z0-9_]*]] = OpConstant %[[UINT_TYPE_ID]] 0
// CHECK: %[[CONSTANT_1_ID:[a-zA-Z0-9_]*]] = OpConstant %[[UINT_TYPE_ID]] 1
// CHECK: %[[CONSTANT_2_ID:[a-zA-Z0-9_]*]] = OpConstant %[[UINT_TYPE_ID]] 2
Expand All @@ -49,19 +48,19 @@
// CHECK: %[[LABEL1_ID:[a-zA-Z0-9_]*]] = OpLabel

// CHECK: %[[ACCESS_CHAIN0_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_GLOBAL_POINTER_TYPE_ID]] %[[ARG0_ID]] %[[CONSTANT_0_ID]] %[[CONSTANT_0_ID]]
// CHECK: %[[LOAD_ACCESS_CHAIN0_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_PRIVATE_POINTER_TYPE_ID]] %[[BUILTIN_VAR_ID]] %[[CONSTANT_0_ID]]
// CHECK: %[[LOAD0_ID:[a-zA-Z0-9_]*]] = OpLoad %[[UINT_TYPE_ID]] %[[LOAD_ACCESS_CHAIN0_ID]]
// CHECK: OpStore %[[ACCESS_CHAIN0_ID]] %[[LOAD0_ID]]
// CHECK: [[hack0:%[a-zA-Z0-9_]+]] = OpBitwiseAnd %[[UINT3_TYPE_ID]] %[[BUILTIN_ID]] %[[BUILTIN_ID]]
// CHECK: [[comp0:%[a-zA-Z0-9_]+]] = OpCompositeExtract %[[UINT_TYPE_ID]] [[hack0]] 0
// CHECK: OpStore %[[ACCESS_CHAIN0_ID]] [[comp0]]

// CHECK: %[[LOAD_ACCESS_CHAIN1_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_PRIVATE_POINTER_TYPE_ID]] %[[BUILTIN_VAR_ID]] %[[CONSTANT_1_ID]]
// CHECK: %[[LOAD1_ID:[a-zA-Z0-9_]*]] = OpLoad %[[UINT_TYPE_ID]] %[[LOAD_ACCESS_CHAIN1_ID]]
// CHECK: [[hack1:%[a-zA-Z0-9_]+]] = OpBitwiseAnd %[[UINT3_TYPE_ID]] %[[BUILTIN_ID]] %[[BUILTIN_ID]]
// CHECK: [[comp1:%[a-zA-Z0-9_]+]] = OpCompositeExtract %[[UINT_TYPE_ID]] [[hack1]]
// CHECK: %[[ACCESS_CHAIN1_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_GLOBAL_POINTER_TYPE_ID]] %[[ARG0_ID]] %[[CONSTANT_0_ID]] %[[CONSTANT_1_ID]]
// CHECK: OpStore %[[ACCESS_CHAIN1_ID]] %[[LOAD1_ID]]
// CHECK: OpStore %[[ACCESS_CHAIN1_ID]] [[comp1]]

// CHECK: %[[LOAD_ACCESS_CHAIN2_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_PRIVATE_POINTER_TYPE_ID]] %[[BUILTIN_VAR_ID]] %[[CONSTANT_2_ID]]
// CHECK: %[[LOAD2_ID:[a-zA-Z0-9_]*]] = OpLoad %[[UINT_TYPE_ID]] %[[LOAD_ACCESS_CHAIN2_ID]]
// CHECK: [[hack2:%[a-zA-Z0-9_]+]] = OpBitwiseAnd %[[UINT3_TYPE_ID]] %[[BUILTIN_ID]] %[[BUILTIN_ID]]
// CHECK: [[comp2:%[a-zA-Z0-9_]+]] = OpCompositeExtract %[[UINT_TYPE_ID]] [[hack2]]
// CHECK: %[[ACCESS_CHAIN2_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_GLOBAL_POINTER_TYPE_ID]] %[[ARG0_ID]] %[[CONSTANT_0_ID]] %[[CONSTANT_2_ID]]
// CHECK: OpStore %[[ACCESS_CHAIN2_ID]] %[[LOAD2_ID]]
// CHECK: OpStore %[[ACCESS_CHAIN2_ID]] [[comp2]]

// CHECK: %[[ACCESS_CHAIN3_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_GLOBAL_POINTER_TYPE_ID]] %[[ARG0_ID]] %[[CONSTANT_0_ID]] %[[CONSTANT_3_ID]]
// CHECK: OpStore %[[ACCESS_CHAIN3_ID]] %[[CONSTANT_1_ID]]
Expand Down
21 changes: 10 additions & 11 deletions test/VaryingLocalSizes/reqd_work_group_size_one_kernel.cl
Expand Up @@ -8,7 +8,7 @@
// CHECK: ; SPIR-V
// CHECK: ; Version: 1.0
// CHECK: ; Generator: Codeplay; 0
// CHECK: ; Bound: 33
// CHECK: ; Bound: 32
// CHECK: ; Schema: 0
// CHECK: OpCapability Shader
// CHECK: OpCapability VariablePointers
Expand All @@ -30,7 +30,6 @@
// CHECK: %[[FOO_TYPE_ID:[a-zA-Z0-9_]*]] = OpTypeFunction %[[VOID_TYPE_ID]]
// CHECK: %[[UINT3_TYPE_ID:[a-zA-Z0-9_]*]] = OpTypeVector %[[UINT_TYPE_ID]] 3
// CHECK: %[[UINT3_PRIVATE_POINTER_TYPE_ID:[a-zA-Z0-9_]*]] = OpTypePointer Private %[[UINT3_TYPE_ID]]
// CHECK: %[[UINT_PRIVATE_POINTER_TYPE_ID:[a-zA-Z0-9_]*]] = OpTypePointer Private %[[UINT_TYPE_ID]]
// CHECK: %[[CONSTANT_42_ID:[a-zA-Z0-9_]*]] = OpConstant %[[UINT_TYPE_ID]] 42
// CHECK: %[[CONSTANT_13_ID:[a-zA-Z0-9_]*]] = OpConstant %[[UINT_TYPE_ID]] 13
// CHECK: %[[CONSTANT_5_ID:[a-zA-Z0-9_]*]] = OpConstant %[[UINT_TYPE_ID]] 5
Expand All @@ -46,19 +45,19 @@
// CHECK: %[[LABEL1_ID:[a-zA-Z0-9_]*]] = OpLabel

// CHECK: %[[ACCESS_CHAIN0_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_GLOBAL_POINTER_TYPE_ID]] %[[ARG0_ID]] %[[CONSTANT_0_ID]] %[[CONSTANT_0_ID]]
// CHECK: %[[LOAD_ACCESS_CHAIN0_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_PRIVATE_POINTER_TYPE_ID]] %[[BUILTIN_VAR_ID]] %[[CONSTANT_0_ID]]
// CHECK: %[[LOAD0_ID:[a-zA-Z0-9_]*]] = OpLoad %[[UINT_TYPE_ID]] %[[LOAD_ACCESS_CHAIN0_ID]]
// CHECK: OpStore %[[ACCESS_CHAIN0_ID]] %[[LOAD0_ID]]
// CHECK: [[hack0:%[a-zA-Z0-9_]+]] = OpBitwiseAnd %[[UINT3_TYPE_ID]] %[[BUILTIN_ID]] %[[BUILTIN_ID]]
// CHECK: [[comp0:%[a-zA-Z0-9_]*]] = OpCompositeExtract %[[UINT_TYPE_ID]] [[hack0]] 0
// CHECK: OpStore %[[ACCESS_CHAIN0_ID]] [[comp0]]

// CHECK: %[[LOAD_ACCESS_CHAIN1_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_PRIVATE_POINTER_TYPE_ID]] %[[BUILTIN_VAR_ID]] %[[CONSTANT_1_ID]]
// CHECK: %[[LOAD1_ID:[a-zA-Z0-9_]*]] = OpLoad %[[UINT_TYPE_ID]] %[[LOAD_ACCESS_CHAIN1_ID]]
// CHECK: [[hack1:%[a-zA-Z0-9_]+]] = OpBitwiseAnd %[[UINT3_TYPE_ID]] %[[BUILTIN_ID]] %[[BUILTIN_ID]]
// CHECK: [[comp1:%[a-zA-Z0-9_]*]] = OpCompositeExtract %[[UINT_TYPE_ID]] [[hack1]] 1
// CHECK: %[[ACCESS_CHAIN1_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_GLOBAL_POINTER_TYPE_ID]] %[[ARG0_ID]] %[[CONSTANT_0_ID]] %[[CONSTANT_1_ID]]
// CHECK: OpStore %[[ACCESS_CHAIN1_ID]] %[[LOAD1_ID]]
// CHECK: OpStore %[[ACCESS_CHAIN1_ID]] [[comp1]]

// CHECK: %[[LOAD_ACCESS_CHAIN2_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_PRIVATE_POINTER_TYPE_ID]] %[[BUILTIN_VAR_ID]] %[[CONSTANT_2_ID]]
// CHECK: %[[LOAD2_ID:[a-zA-Z0-9_]*]] = OpLoad %[[UINT_TYPE_ID]] %[[LOAD_ACCESS_CHAIN2_ID]]
// CHECK: [[hack2:%[a-zA-Z0-9_]+]] = OpBitwiseAnd %[[UINT3_TYPE_ID]] %[[BUILTIN_ID]] %[[BUILTIN_ID]]
// CHECK: [[comp2:%[a-zA-Z0-9_]*]] = OpCompositeExtract %[[UINT_TYPE_ID]] [[hack2]] 2
// CHECK: %[[ACCESS_CHAIN2_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_GLOBAL_POINTER_TYPE_ID]] %[[ARG0_ID]] %[[CONSTANT_0_ID]] %[[CONSTANT_2_ID]]
// CHECK: OpStore %[[ACCESS_CHAIN2_ID]] %[[LOAD2_ID]]
// CHECK: OpStore %[[ACCESS_CHAIN2_ID]] [[comp2]]

// CHECK: %[[ACCESS_CHAIN3_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_GLOBAL_POINTER_TYPE_ID]] %[[ARG0_ID]] %[[CONSTANT_0_ID]] %[[CONSTANT_3_ID]]
// CHECK: OpStore %[[ACCESS_CHAIN3_ID]] %[[CONSTANT_1_ID]]
Expand Down
43 changes: 21 additions & 22 deletions test/VaryingLocalSizes/reqd_work_group_size_two_kernels.cl
Expand Up @@ -8,7 +8,7 @@
// CHECK: ; SPIR-V
// CHECK: ; Version: 1.0
// CHECK: ; Generator: Codeplay; 0
// CHECK: ; Bound: 46
// CHECK: ; Bound: 45
// CHECK: ; Schema: 0
// CHECK: OpCapability Shader
// CHECK: OpCapability VariablePointers
Expand All @@ -34,36 +34,35 @@
// CHECK: %[[FOO_TYPE_ID:[a-zA-Z0-9_]*]] = OpTypeFunction %[[VOID_TYPE_ID]]
// CHECK: %[[UINT3_TYPE_ID:[a-zA-Z0-9_]*]] = OpTypeVector %[[UINT_TYPE_ID]] 3
// CHECK: %[[UINT3_PRIVATE_POINTER_TYPE_ID:[a-zA-Z0-9_]*]] = OpTypePointer Private %[[UINT3_TYPE_ID]]
// CHECK: %[[UINT_PRIVATE_POINTER_TYPE_ID:[a-zA-Z0-9_]*]] = OpTypePointer Private %[[UINT_TYPE_ID]]
// CHECK: %[[CONSTANT_42_ID:[a-zA-Z0-9_]*]] = OpConstant %[[UINT_TYPE_ID]] 42
// CHECK: %[[CONSTANT_13_ID:[a-zA-Z0-9_]*]] = OpConstant %[[UINT_TYPE_ID]] 13
// CHECK: %[[CONSTANT_5_ID:[a-zA-Z0-9_]*]] = OpConstant %[[UINT_TYPE_ID]] 5
// CHECK: %[[CONSTANT_0_ID:[a-zA-Z0-9_]*]] = OpConstant %[[UINT_TYPE_ID]] 0
// CHECK: %[[CONSTANT_1_ID:[a-zA-Z0-9_]*]] = OpConstant %[[UINT_TYPE_ID]] 1
// CHECK: %[[CONSTANT_2_ID:[a-zA-Z0-9_]*]] = OpConstant %[[UINT_TYPE_ID]] 2
// CHECK: %[[CONSTANT_3_ID:[a-zA-Z0-9_]*]] = OpConstant %[[UINT_TYPE_ID]] 3
// CHECK: %[[BUILTIN_FOR_FOO_ID:[a-zA-Z0-9_]*]] = OpConstantComposite %[[UINT3_TYPE_ID]] %[[CONSTANT_42_ID]] %[[CONSTANT_13_ID]] %[[CONSTANT_5_ID]]
// CHECK: %[[BUILTIN_VAR_FOR_FOO_ID:[a-zA-Z0-9_]*]] = OpVariable %[[UINT3_PRIVATE_POINTER_TYPE_ID]] Private %[[BUILTIN_FOR_FOO_ID]]
// CHECK: %[[BUILTIN_ID:[a-zA-Z0-9_]*]] = OpConstantComposite %[[UINT3_TYPE_ID]] %[[CONSTANT_42_ID]] %[[CONSTANT_13_ID]] %[[CONSTANT_5_ID]]
// CHECK: %[[BUILTIN_VAR_FOR_FOO_ID:[a-zA-Z0-9_]*]] = OpVariable %[[UINT3_PRIVATE_POINTER_TYPE_ID]] Private %[[BUILTIN_ID]]
// CHECK: %[[FOO_ARG0_ID]] = OpVariable %[[UINT_ARG0_POINTER_TYPE_ID]] StorageBuffer
// CHECK: %[[BAR_ARG0_ID]] = OpVariable %[[UINT_ARG0_POINTER_TYPE_ID]] StorageBuffer

// CHECK: %[[FOO_ID]] = OpFunction %[[VOID_TYPE_ID]] None %[[FOO_TYPE_ID]]
// CHECK: %[[LABEL1_ID:[a-zA-Z0-9_]*]] = OpLabel

// CHECK: %[[ACCESS_CHAIN0_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_GLOBAL_POINTER_TYPE_ID]] %[[FOO_ARG0_ID]] %[[CONSTANT_0_ID]] %[[CONSTANT_0_ID]]
// CHECK: %[[LOAD_ACCESS_CHAIN0_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_PRIVATE_POINTER_TYPE_ID]] %[[BUILTIN_VAR_FOR_FOO_ID]] %[[CONSTANT_0_ID]]
// CHECK: %[[LOAD0_ID:[a-zA-Z0-9_]*]] = OpLoad %[[UINT_TYPE_ID]] %[[LOAD_ACCESS_CHAIN0_ID]]
// CHECK: OpStore %[[ACCESS_CHAIN0_ID]] %[[LOAD0_ID]]
// CHECK: [[hack0:%[a-zA-Z0-9_]+]] = OpBitwiseAnd %[[UINT3_TYPE_ID]] %[[BUILTIN_ID]] %[[BUILTIN_ID]]
// CHECK: [[foo_comp0:%[a-zA-Z0-9_]*]] = OpCompositeExtract %[[UINT_TYPE_ID]] [[hack0]] 0
// CHECK: OpStore %[[ACCESS_CHAIN0_ID]] [[foo_comp0]]

// CHECK: %[[LOAD_ACCESS_CHAIN1_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_PRIVATE_POINTER_TYPE_ID]] %[[BUILTIN_VAR_FOR_FOO_ID]] %[[CONSTANT_1_ID]]
// CHECK: %[[LOAD1_ID:[a-zA-Z0-9_]*]] = OpLoad %[[UINT_TYPE_ID]] %[[LOAD_ACCESS_CHAIN1_ID]]
// CHECK: [[hack1:%[a-zA-Z0-9_]+]] = OpBitwiseAnd %[[UINT3_TYPE_ID]] %[[BUILTIN_ID]] %[[BUILTIN_ID]]
// CHECK: [[foo_comp1:%[a-zA-Z0-9_]*]] = OpCompositeExtract %[[UINT_TYPE_ID]] [[hack1]] 1
// CHECK: %[[ACCESS_CHAIN1_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_GLOBAL_POINTER_TYPE_ID]] %[[FOO_ARG0_ID]] %[[CONSTANT_0_ID]] %[[CONSTANT_1_ID]]
// CHECK: OpStore %[[ACCESS_CHAIN1_ID]] %[[LOAD1_ID]]
// CHECK: OpStore %[[ACCESS_CHAIN1_ID]] [[foo_comp1]]

// CHECK: %[[LOAD_ACCESS_CHAIN2_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_PRIVATE_POINTER_TYPE_ID]] %[[BUILTIN_VAR_FOR_FOO_ID]] %[[CONSTANT_2_ID]]
// CHECK: %[[LOAD2_ID:[a-zA-Z0-9_]*]] = OpLoad %[[UINT_TYPE_ID]] %[[LOAD_ACCESS_CHAIN2_ID]]
// CHECK: [[hack2:%[a-zA-Z0-9_]+]] = OpBitwiseAnd %[[UINT3_TYPE_ID]] %[[BUILTIN_ID]] %[[BUILTIN_ID]]
// CHECK: [[foo_comp2:%[a-zA-Z0-9_]*]] = OpCompositeExtract %[[UINT_TYPE_ID]] [[hack2]] 2
// CHECK: %[[ACCESS_CHAIN2_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_GLOBAL_POINTER_TYPE_ID]] %[[FOO_ARG0_ID]] %[[CONSTANT_0_ID]] %[[CONSTANT_2_ID]]
// CHECK: OpStore %[[ACCESS_CHAIN2_ID]] %[[LOAD2_ID]]
// CHECK: OpStore %[[ACCESS_CHAIN2_ID]] [[foo_comp2]]

// CHECK: %[[ACCESS_CHAIN3_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_GLOBAL_POINTER_TYPE_ID]] %[[FOO_ARG0_ID]] %[[CONSTANT_0_ID]] %[[CONSTANT_3_ID]]
// CHECK: OpStore %[[ACCESS_CHAIN3_ID]] %[[CONSTANT_1_ID]]
Expand All @@ -83,19 +82,19 @@ void kernel __attribute__((reqd_work_group_size(42, 13, 5))) foo(global uint* a)
// CHECK: %[[LABEL1_ID:[a-zA-Z0-9_]*]] = OpLabel

// CHECK: %[[BAR_ACCESS_CHAIN0_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_GLOBAL_POINTER_TYPE_ID]] %[[BAR_ARG0_ID]] %[[CONSTANT_0_ID]] %[[CONSTANT_0_ID]]
// CHECK: %[[BAR_LOAD_ACCESS_CHAIN0_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_PRIVATE_POINTER_TYPE_ID]] %[[BUILTIN_VAR_FOR_FOO_ID]] %[[CONSTANT_0_ID]]
// CHECK: %[[BAR_LOAD0_ID:[a-zA-Z0-9_]*]] = OpLoad %[[UINT_TYPE_ID]] %[[BAR_LOAD_ACCESS_CHAIN0_ID]]
// CHECK: OpStore %[[BAR_ACCESS_CHAIN0_ID]] %[[BAR_LOAD0_ID]]
// CHECK: [[hack3:%[a-zA-Z0-9_]+]] = OpBitwiseAnd %[[UINT3_TYPE_ID]] %[[BUILTIN_ID]] %[[BUILTIN_ID]]
// CHECK: [[bar_comp0:%[a-zA-Z0-9_]*]] = OpCompositeExtract %[[UINT_TYPE_ID]] [[hack3]] 0
// CHECK: OpStore %[[BAR_ACCESS_CHAIN0_ID]] [[bar_comp0]]

// CHECK: %[[BAR_LOAD_ACCESS_CHAIN1_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_PRIVATE_POINTER_TYPE_ID]] %[[BUILTIN_VAR_FOR_FOO_ID]] %[[CONSTANT_1_ID]]
// CHECK: %[[BAR_LOAD1_ID:[a-zA-Z0-9_]*]] = OpLoad %[[UINT_TYPE_ID]] %[[BAR_LOAD_ACCESS_CHAIN1_ID]]
// CHECK: [[hack4:%[a-zA-Z0-9_]+]] = OpBitwiseAnd %[[UINT3_TYPE_ID]] %[[BUILTIN_ID]] %[[BUILTIN_ID]]
// CHECK: [[bar_comp1:%[a-zA-Z0-9_]*]] = OpCompositeExtract %[[UINT_TYPE_ID]] [[hack4]] 1
// CHECK: %[[BAR_ACCESS_CHAIN1_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_GLOBAL_POINTER_TYPE_ID]] %[[BAR_ARG0_ID]] %[[CONSTANT_0_ID]] %[[CONSTANT_1_ID]]
// CHECK: OpStore %[[BAR_ACCESS_CHAIN1_ID]] %[[BAR_LOAD1_ID]]
// CHECK: OpStore %[[BAR_ACCESS_CHAIN1_ID]] [[bar_comp1]]

// CHECK: %[[BAR_LOAD_ACCESS_CHAIN2_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_PRIVATE_POINTER_TYPE_ID]] %[[BUILTIN_VAR_FOR_FOO_ID]] %[[CONSTANT_2_ID]]
// CHECK: %[[BAR_LOAD2_ID:[a-zA-Z0-9_]*]] = OpLoad %[[UINT_TYPE_ID]] %[[BAR_LOAD_ACCESS_CHAIN2_ID]]
// CHECK: [[hack5:%[a-zA-Z0-9_]+]] = OpBitwiseAnd %[[UINT3_TYPE_ID]] %[[BUILTIN_ID]] %[[BUILTIN_ID]]
// CHECK: [[bar_comp2:%[a-zA-Z0-9_]*]] = OpCompositeExtract %[[UINT_TYPE_ID]] [[hack5]] 2
// CHECK: %[[BAR_ACCESS_CHAIN2_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_GLOBAL_POINTER_TYPE_ID]] %[[BAR_ARG0_ID]] %[[CONSTANT_0_ID]] %[[CONSTANT_2_ID]]
// CHECK: OpStore %[[BAR_ACCESS_CHAIN2_ID]] %[[BAR_LOAD2_ID]]
// CHECK: OpStore %[[BAR_ACCESS_CHAIN2_ID]] [[bar_comp2]]

// CHECK: %[[BAR_ACCESS_CHAIN3_ID:[a-zA-Z0-9_]*]] = OpAccessChain %[[UINT_GLOBAL_POINTER_TYPE_ID]] %[[BAR_ARG0_ID]] %[[CONSTANT_0_ID]] %[[CONSTANT_3_ID]]
// CHECK: OpStore %[[BAR_ACCESS_CHAIN3_ID]] %[[CONSTANT_1_ID]]
Expand Down