Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions lib/SPIRV/SPIRVBuiltinHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,18 @@ Type *BuiltinCallHelper::adjustImageType(Type *T, StringRef OldImageKind,
}
return TypedPointerType::get(StructTy, TypedPtrTy->getAddressSpace());
}

if (auto *TargetTy = dyn_cast<TargetExtType>(T)) {
StringRef Name = TargetTy->getName();
if (!Name.consume_front(kSPIRVTypeName::PrefixAndDelim) ||
Name != OldImageKind)
report_fatal_error("Type did not have expected image kind");
return TargetExtType::get(
TargetTy->getContext(),
(Twine(kSPIRVTypeName::PrefixAndDelim) + NewImageKind).str(),
TargetTy->type_params(), TargetTy->int_params());
}

report_fatal_error("Expected type to be a SPIRV image type");
}

Expand Down Expand Up @@ -294,6 +306,19 @@ Type *BuiltinCallHelper::getSPIRVType(spv::Op TypeOpcode,
StringRef InnerTypeName,
ArrayRef<unsigned> Parameters,
bool UseRealType) {
if (UseTargetTypes) {
std::string BaseName = (Twine(kSPIRVTypeName::PrefixAndDelim) +
SPIRVOpaqueTypeOpCodeMap::rmap(TypeOpcode))
.str();
SmallVector<Type *, 1> TypeParams;
if (!InnerTypeName.empty()) {
TypeParams.push_back(getLLVMTypeForSPIRVImageSampledTypePostfix(
InnerTypeName, M->getContext()));
}
return TargetExtType::get(M->getContext(), BaseName, TypeParams,
Parameters);
}

std::string FullName;
{
raw_string_ostream OS(FullName);
Expand All @@ -315,6 +340,23 @@ Type *BuiltinCallHelper::getSPIRVType(spv::Op TypeOpcode,
: TypedPointerType::get(STy, AddrSpace);
}

void BuiltinCallHelper::initialize(llvm::Module &M) {
this->M = &M;
// We want to use pointers-to-opaque-structs for the special types if:
// * We are translating from SPIR-V to LLVM IR (which means we are using
// OpenCL mangling rules)
// * There are %opencl.* or %spirv.* struct type names already present.
UseTargetTypes = Rules != ManglingRules::OpenCL;
for (StructType *Ty : M.getIdentifiedStructTypes()) {
if (!Ty->isOpaque() || !Ty->hasName())
continue;
StringRef Name = Ty->getName();
if (Name.startswith("opencl.") || Name.startswith("spirv.")) {
UseTargetTypes = false;
}
}
}

BuiltinCallMutator::ValueTypePair
BuiltinCallHelper::getCallValue(CallInst *CI, unsigned ArgNo) {
Function *CalledFunc = CI->getCalledFunction();
Expand Down
3 changes: 2 additions & 1 deletion lib/SPIRV/SPIRVBuiltinHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ class BuiltinCallHelper {

protected:
llvm::Module *M = nullptr;
bool UseTargetTypes = false;

public:
/// Initialize details about how to mangle and demangle builtins correctly.
Expand All @@ -265,7 +266,7 @@ class BuiltinCallHelper {

/// Initialize the module that will be operated on. This method must be called
/// before future methods.
void initialize(llvm::Module &M) { this->M = &M; }
void initialize(llvm::Module &M);

/// Return a mutator that will replace the given call instruction with a call
/// to the given function name. The function name will have its name mangled
Expand Down
21 changes: 20 additions & 1 deletion lib/SPIRV/SPIRVUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -855,7 +855,7 @@ bool getParameterTypes(Function *F, SmallVectorImpl<Type *> &ArgTys,
LLVM_DEBUG(dbgs() << "Failed to recover type of argument " << *ArgTy
<< " of function " << F->getName() << "\n");
DemangledSuccessfully = false;
} else if (!DemangledTy)
} else if (ArgTy->isTargetExtTy() || !DemangledTy)
DemangledTy = ArgTy;
*ArgIter++ = DemangledTy;
}
Expand Down Expand Up @@ -1306,6 +1306,25 @@ static SPIR::RefParamType transTypeDesc(Type *Ty,
}
return SPIR::RefParamType(new SPIR::UserDefinedType(Name.str()));
}
if (auto *TargetTy = dyn_cast<TargetExtType>(Ty)) {
std::string FullName;
{
raw_string_ostream OS(FullName);
StringRef Name = TargetTy->getName();
if (Name.consume_front(kSPIRVTypeName::PrefixAndDelim)) {
OS << "__spirv_" << Name;
} else {
OS << Name;
}
if (!TargetTy->int_params().empty())
OS << "_";
for (Type *InnerTy : TargetTy->type_params())
OS << "_" << convertTypeToPostfix(InnerTy);
for (unsigned Param : TargetTy->int_params())
OS << "_" << Param;
}
return SPIR::RefParamType(new SPIR::UserDefinedType(FullName));
}

if (auto *TPT = dyn_cast<TypedPointerType>(Ty)) {
auto *ET = TPT->getElementType();
Expand Down
46 changes: 45 additions & 1 deletion lib/SPIRV/SPIRVWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,47 @@ SPIRVType *LLVMToSPIRVBase::transType(Type *T) {
return mapType(T, getSPIRVFunctionType(RT, PT));
}

if (auto *TargetTy = dyn_cast<TargetExtType>(T)) {
StringRef Name = TargetTy->getName();
if (Name.consume_front(kSPIRVTypeName::PrefixAndDelim)) {
auto Opcode = SPIRVOpaqueTypeOpCodeMap::map(Name.str());
auto CastAccess = [](unsigned Val) {
return static_cast<SPIRVAccessQualifierKind>(Val);
};
switch (Opcode) {
case OpTypePipe: {
auto *PipeT = BM->addPipeType();
PipeT->setPipeAcessQualifier(CastAccess(TargetTy->getIntParameter(0)));
return mapType(T, PipeT);
}
case OpTypeImage: {
auto *SampledTy = transType(TargetTy->getTypeParameter(0));
ArrayRef<unsigned> Ops = TargetTy->int_params();
SPIRVTypeImageDescriptor Desc(static_cast<SPIRVImageDimKind>(Ops[0]),
Ops[1], Ops[2], Ops[3], Ops[4], Ops[5]);
return mapType(T,
BM->addImageType(SampledTy, Desc, CastAccess(Ops[6])));
}
case OpTypeSampledImage: {
auto *ImageTy = static_cast<SPIRVTypeImage *>(transType(adjustImageType(
T, kSPIRVTypeName::SampledImg, kSPIRVTypeName::Image)));
return mapType(T, BM->addSampledImageType(ImageTy));
}
case OpTypeVmeImageINTEL: {
auto *ImageTy = static_cast<SPIRVTypeImage *>(transType(adjustImageType(
T, kSPIRVTypeName::VmeImageINTEL, kSPIRVTypeName::Image)));
return mapType(T, BM->addVmeImageINTELType(ImageTy));
}
case OpTypeQueue:
return mapType(T, BM->addQueueType());
case OpTypeDeviceEvent:
return mapType(T, BM->addDeviceEventType());
default:
return mapType(T, BM->addOpaqueGenericType(Opcode));
}
}
}

llvm_unreachable("Not implemented!");
return 0;
}
Expand Down Expand Up @@ -1062,6 +1103,9 @@ SPIRVValue *LLVMToSPIRVBase::transConstant(Value *V) {
return BM->addNullConstant(
bcast<SPIRVTypePointer>(transType(CPNull->getType())));

if (isa<ConstantTargetNone>(V))
return BM->addNullConstant(transType(V->getType()));

if (auto CAZero = dyn_cast<ConstantAggregateZero>(V)) {
Type *AggType = CAZero->getType();
if (const StructType *ST = dyn_cast<StructType>(AggType))
Expand Down Expand Up @@ -2722,7 +2766,7 @@ SPIRVValue *LLVMToSPIRVBase::oclTransSpvcCastSampler(CallInst *CI,
auto FT = F->getFunctionType();
auto RT = FT->getReturnType();
assert(FT->getNumParams() == 1);
if (!RT->isOpaquePointerTy()) {
if (RT->isPointerTy() && !RT->isOpaquePointerTy()) {
StructType *ST = dyn_cast<StructType>(RT->getNonOpaquePointerElementType());
(void)ST;
assert(isSPIRVStructType(ST, kSPIRVTypeName::Sampler) ||
Expand Down
194 changes: 194 additions & 0 deletions test/transcoding/spirv-target-types.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
;; Test SPIR-V opaque types
;;
; RUN: llvm-as %s -o %t.bc
; RUN: llvm-spirv %t.bc -spirv-text -o %t.spv.txt
; RUN: FileCheck < %t.spv.txt %s --check-prefix=CHECK-SPIRV
; RUN: llvm-spirv %t.bc -o %t.from-llvm.spv
; RUN: llvm-spirv -to-binary %t.spv.txt -o %t.from-text.spv
; RUN: llvm-spirv %t.bc -o %t.spv
; RUN: spirv-val %t.spv
; RUN: llvm-spirv -r %t.spv -o %t.rev.bc
; RUN: llvm-dis -opaque-pointers=0 %t.rev.bc
; RUN: FileCheck < %t.rev.ll %s --check-prefix=CHECK-LLVM
; RUN: llvm-spirv --spirv-target-env=SPV-IR -r %t.spv -o %t.rev.bc
; RUN: llvm-dis -opaque-pointers=0 %t.rev.bc
; RUN: FileCheck < %t.rev.ll %s --check-prefix=CHECK-LLVM-SPIRV

; Check that produced SPIR-V friendly IR is correctly recognized
; RUN: llvm-spirv %t.rev.bc -opaque-pointers=0 -spirv-text -o %t.spv.txt
; RUN: FileCheck < %t.spv.txt %s --check-prefix=CHECK-SPIRV

; CHECK-SPIRV: 2 Capability Float16
; CHECK-SPIRV: 2 Capability ImageBasic
; CHECK-SPIRV: 2 Capability ImageReadWrite
; CHECK-SPIRV: 2 Capability Pipes
; CHECK-SPIRV: 2 Capability DeviceEnqueue

; CHECK-SPIRV-DAG: 2 TypeVoid [[VOID:[0-9]+]]
; CHECK-SPIRV-DAG: 4 TypeInt [[INT:[0-9]+]] 32 0
; CHECK-SPIRV-DAG: 3 TypeFloat [[HALF:[0-9]+]] 16
; CHECK-SPIRV-DAG: 3 TypeFloat [[FLOAT:[0-9]+]] 32
; CHECK-SPIRV-DAG: 3 TypePipe [[PIPE_RD:[0-9]+]] 0
; CHECK-SPIRV-DAG: 3 TypePipe [[PIPE_WR:[0-9]+]] 1
; CHECK-SPIRV-DAG: 10 TypeImage [[IMG1D_RD:[0-9]+]] [[VOID]] 0 0 0 0 0 0 0
; CHECK-SPIRV-DAG: 10 TypeImage [[IMG2D_RD:[0-9]+]] [[INT]] 1 0 0 0 0 0 0
; CHECK-SPIRV-DAG: 10 TypeImage [[IMG3D_RD:[0-9]+]] [[INT]] 2 0 0 0 0 0 0
; CHECK-SPIRV-DAG: 10 TypeImage [[IMG2DD_RD:[0-9]+]] [[FLOAT]] 1 1 0 0 0 0 0
; CHECK-SPIRV-DAG: 10 TypeImage [[IMG2DA_RD:[0-9]+]] [[HALF]] 1 0 1 0 0 0 0
; CHECK-SPIRV-DAG: 10 TypeImage [[IMG1DB_RD:[0-9]+]] [[FLOAT]] 5 0 0 0 0 0 0
; CHECK-SPIRV-DAG: 10 TypeImage [[IMG1D_WR:[0-9]+]] [[VOID]] 0 0 0 0 0 0 1
; CHECK-SPIRV-DAG: 10 TypeImage [[IMG2D_RW:[0-9]+]] [[VOID]] 1 0 0 0 0 0 2
; CHECK-SPIRV-DAG: 2 TypeDeviceEvent [[DEVEVENT:[0-9]+]]
; CHECK-SPIRV-DAG: 2 TypeEvent [[EVENT:[0-9]+]]
; CHECK-SPIRV-DAG: 2 TypeQueue [[QUEUE:[0-9]+]]
; CHECK-SPIRV-DAG: 2 TypeReserveId [[RESID:[0-9]+]]
; CHECK-SPIRV-DAG: 2 TypeSampler [[SAMP:[0-9]+]]
; CHECK-SPIRV-DAG: 3 TypeSampledImage [[SAMPIMG:[0-9]+]] [[IMG2DD_RD]]

; ModuleID = 'cl-types.cl'
target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
target triple = "spir-unknown-unknown"

; CHECK-LLVM-DAG: %opencl.pipe_ro_t = type opaque
; CHECK-LLVM-DAG: %opencl.pipe_wo_t = type opaque
; CHECK-LLVM-DAG: %opencl.image3d_ro_t = type opaque
; CHECK-LLVM-DAG: %opencl.image2d_depth_ro_t = type opaque
; CHECK-LLVM-DAG: %opencl.image2d_array_ro_t = type opaque
; CHECK-LLVM-DAG: %opencl.image1d_buffer_ro_t = type opaque
; CHECK-LLVM-DAG: %opencl.image1d_ro_t = type opaque
; CHECK-LLVM-DAG: %opencl.image1d_wo_t = type opaque
; CHECK-LLVM-DAG: %opencl.image2d_ro_t = type opaque
; CHECK-LLVM-DAG: %opencl.image2d_rw_t = type opaque
; CHECK-LLVM-DAG: %opencl.clk_event_t = type opaque
; CHECK-LLVM-DAG: %opencl.event_t = type opaque
; CHECK-LLVM-DAG: %opencl.queue_t = type opaque
; CHECK-LLVM-DAG: %opencl.reserve_id_t = type opaque

; CHECK-LLVM-SPIRV-DAG: %spirv.Pipe._0 = type opaque
; CHECK-LLVM-SPIRV-DAG: %spirv.Pipe._1 = type opaque

; CHECK-LLVM-SPIRV-DAG: %spirv.Image._void_0_0_0_0_0_0_0 = type opaque
; CHECK-LLVM-SPIRV-DAG: %spirv.Image._uint_1_0_0_0_0_0_0 = type opaque
; CHECK-LLVM-SPIRV-DAG: %spirv.Image._uint_2_0_0_0_0_0_0 = type opaque
; CHECK-LLVM-SPIRV-DAG: %spirv.Image._float_1_1_0_0_0_0_0 = type opaque
; CHECK-LLVM-SPIRV-DAG: %spirv.Image._half_1_0_1_0_0_0_0 = type opaque
; CHECK-LLVM-SPIRV-DAG: %spirv.Image._float_5_0_0_0_0_0_0 = type opaque
; CHECK-LLVM-SPIRV-DAG: %spirv.Image._void_0_0_0_0_0_0_1 = type opaque
; CHECK-LLVM-SPIRV-DAG: %spirv.Image._void_1_0_0_0_0_0_2 = type opaque
; CHECK-LLVM-SPIRV-DAG: %spirv.DeviceEvent = type opaque
; CHECK-LLVM-SPIRV-DAG: %spirv.Event = type opaque
; CHECK-LLVM-SPIRV-DAG: %spirv.Queue = type opaque
; CHECK-LLVM-SPIRV-DAG: %spirv.ReserveId = type opaque
; CHECK-LLVM-SPIRV-DAG: %spirv.Sampler = type opaque
; CHECK-LLVM-SPIRV-DAG: %spirv.SampledImage._float_1_1_0_0_0_0_0 = type opaque

; CHECK-SPIRV: {{[0-9]+}} Function
; CHECK-SPIRV: 3 FunctionParameter [[PIPE_RD]] {{[0-9]+}}
; CHECK-SPIRV: 3 FunctionParameter [[PIPE_WR]] {{[0-9]+}}
; CHECK-SPIRV: 3 FunctionParameter [[IMG1D_RD]] {{[0-9]+}}
; CHECK-SPIRV: 3 FunctionParameter [[IMG2D_RD]] {{[0-9]+}}
; CHECK-SPIRV: 3 FunctionParameter [[IMG3D_RD]] {{[0-9]+}}
; CHECK-SPIRV: 3 FunctionParameter [[IMG2DA_RD]] {{[0-9]+}}
; CHECK-SPIRV: 3 FunctionParameter [[IMG1DB_RD]] {{[0-9]+}}
; CHECK-SPIRV: 3 FunctionParameter [[IMG1D_WR]] {{[0-9]+}}
; CHECK-SPIRV: 3 FunctionParameter [[IMG2D_RW]] {{[0-9]+}}

; CHECK-LLVM: define spir_kernel void @foo(
; CHECK-LLVM-SAME: %opencl.pipe_ro_t addrspace(1)* %a,
; CHECK-LLVM-SAME: %opencl.pipe_wo_t addrspace(1)* %b,
; CHECK-LLVM-SAME: %opencl.image1d_ro_t addrspace(1)* %c1,
; CHECK-LLVM-SAME: %opencl.image2d_ro_t addrspace(1)* %d1,
; CHECK-LLVM-SAME: %opencl.image3d_ro_t addrspace(1)* %e1,
; CHECK-LLVM-SAME: %opencl.image2d_array_ro_t addrspace(1)* %f1,
; CHECK-LLVM-SAME: %opencl.image1d_buffer_ro_t addrspace(1)* %g1,
; CHECK-LLVM-SAME: %opencl.image1d_wo_t addrspace(1)* %c2,
; CHECK-LLVM-SAME: %opencl.image2d_rw_t addrspace(1)* %d3)
; CHECK-LLVM-SAME: !kernel_arg_addr_space [[AS:![0-9]+]]
; CHECK-LLVM-SAME: !kernel_arg_access_qual [[AQ:![0-9]+]]
; CHECK-LLVM-SAME: !kernel_arg_type [[TYPE:![0-9]+]]
; CHECK-LLVM-SAME: !kernel_arg_type_qual [[TQ:![0-9]+]]
; CHECK-LLVM-SAME: !kernel_arg_base_type [[TYPE]]

; Function Attrs: nounwind readnone
define spir_kernel void @foo(
target("spirv.Pipe", 0) %a,
target("spirv.Pipe", 1) %b,
target("spirv.Image", void, 0, 0, 0, 0, 0, 0, 0) %c1,
target("spirv.Image", i32, 1, 0, 0, 0, 0, 0, 0) %d1,
target("spirv.Image", i32, 2, 0, 0, 0, 0, 0, 0) %e1,
target("spirv.Image", half, 1, 0, 1, 0, 0, 0, 0) %f1,
target("spirv.Image", float, 5, 0, 0, 0, 0, 0, 0) %g1,
target("spirv.Image", void, 0, 0, 0, 0, 0, 0, 1) %c2,
target("spirv.Image", void, 1, 0, 0, 0, 0, 0, 2) %d3) #0 !kernel_arg_addr_space !1 !kernel_arg_access_qual !2 !kernel_arg_type !3 !kernel_arg_base_type !4 !kernel_arg_type_qual !5 {
entry:
ret void
}

; CHECK-SPIRV: {{[0-9]+}} Function
; CHECK-SPIRV: 3 FunctionParameter [[DEVEVENT]] {{[0-9]+}}
; CHECK-SPIRV: 3 FunctionParameter [[EVENT]] {{[0-9]+}}
; CHECK-SPIRV: 3 FunctionParameter [[QUEUE]] {{[0-9]+}}
; CHECK-SPIRV: 3 FunctionParameter [[RESID]] {{[0-9]+}}

; CHECK-LLVM: define spir_func void @bar(
; CHECK-LLVM: %opencl.clk_event_t* %a,
; CHECK-LLVM: %opencl.event_t* %b,
; CHECK-LLVM: %opencl.queue_t* %c,
; CHECK-LLVM: %opencl.reserve_id_t* %d)

define spir_func void @bar(
target("spirv.DeviceEvent") %a,
target("spirv.Event") %b,
target("spirv.Queue") %c,
target("spirv.ReserveId") %d) {
ret void
}

; CHECK-SPIRV: {{[0-9]+}} Function
; CHECK-SPIRV: 3 FunctionParameter [[IMG2DD_RD]] [[IMG_ARG:[0-9]+]]
; CHECK-SPIRV: 3 FunctionParameter [[SAMP]] [[SAMP_ARG:[0-9]+]]
; CHECK-SPIRV: 5 SampledImage [[SAMPIMG]] [[SAMPIMG_VAR:[0-9]+]] [[IMG_ARG]] [[SAMP_ARG]]
; CHECK-SPIRV: 7 ImageSampleExplicitLod {{[0-9]+}} {{[0-9]+}} [[SAMPIMG_VAR]]

; CHECK-LLVM: define spir_func void @test_sampler(
; CHECK-LLVM: %opencl.image2d_depth_ro_t addrspace(1)* %srcimg.coerce,
; CHECK-LLVM: %opencl.sampler_t addrspace(2)* %s.coerce)
; CHECK-LLVM: call spir_func float @_Z11read_imagef20ocl_image2d_depth_ro11ocl_samplerDv4_if(%opencl.image2d_depth_ro_t addrspace(1)* %srcimg.coerce, %opencl.sampler_t addrspace(2)* %s.coerce, <4 x i32> zeroinitializer, float 1.000000e+00)

; CHECK-LLVM-SPIRV: call spir_func %spirv.SampledImage._float_1_1_0_0_0_0_0 addrspace(1)* @_Z20__spirv_SampledImagePU3AS134__spirv_Image__float_1_1_0_0_0_0_0PU3AS215__spirv_Sampler(%spirv.Image._float_1_1_0_0_0_0_0 addrspace(1)* %srcimg.coerce, %spirv.Sampler addrspace(2)* %s.coerce)
; CHECK-LLVM-SPIRV: call spir_func <4 x float> @_Z38__spirv_ImageSampleExplicitLod_Rfloat4PU3AS141__spirv_SampledImage__float_1_1_0_0_0_0_0Dv4_iif(%spirv.SampledImage._float_1_1_0_0_0_0_0 addrspace(1)* %1, <4 x i32> zeroinitializer, i32 2, float 1.000000e+00)

define spir_func void @test_sampler(target("spirv.Image", float, 1, 1, 0, 0, 0, 0, 0) %srcimg.coerce,
target("spirv.Sampler") %s.coerce) {
%1 = tail call spir_func target("spirv.SampledImage", float, 1, 1, 0, 0, 0, 0, 0) @_Z20__spirv_SampledImagePU3AS1K34__spirv_Image__float_1_1_0_0_0_0_0PU3AS1K15__spirv_Sampler(target("spirv.Image", float, 1, 1, 0, 0, 0, 0, 0) %srcimg.coerce, target("spirv.Sampler") %s.coerce) #1
%2 = tail call spir_func <4 x float> @_Z38__spirv_ImageSampleExplicitLod_Rfloat4PU3AS120__spirv_SampledImageDv4_iif(target("spirv.SampledImage", float, 1, 1, 0, 0, 0, 0, 0) %1, <4 x i32> zeroinitializer, i32 2, float 1.000000e+00) #1
ret void
}

declare spir_func target("spirv.SampledImage", float, 1, 1, 0, 0, 0, 0, 0) @_Z20__spirv_SampledImagePU3AS1K34__spirv_Image__float_1_1_0_0_0_0_0PU3AS1K15__spirv_Sampler(target("spirv.Image", float, 1, 1, 0, 0, 0, 0, 0), target("spirv.Sampler"))

declare spir_func <4 x float> @_Z38__spirv_ImageSampleExplicitLod_Rfloat4PU3AS120__spirv_SampledImageDv4_iif(target("spirv.SampledImage", float, 1, 1, 0, 0, 0, 0, 0), <4 x i32>, i32, float)

attributes #0 = { nounwind readnone "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }

!opencl.enable.FP_CONTRACT = !{}
!opencl.spir.version = !{!6}
!opencl.ocl.version = !{!7}
!opencl.used.extensions = !{!8}
!opencl.used.optional.core.features = !{!9}
!opencl.compiler.options = !{!8}

; CHECK-LLVM-DAG: [[AS]] = !{i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1}
; CHECK-LLVM-DAG: [[AQ]] = !{!"read_only", !"write_only", !"read_only", !"read_only", !"read_only", !"read_only", !"read_only", !"write_only", !"read_write"}
; CHECK-LLVM-DAG: [[TYPE]] = !{!"pipe", !"pipe", !"image1d_t", !"image2d_t", !"image3d_t", !"image2d_array_t", !"image1d_buffer_t", !"image1d_t", !"image2d_t"}
; CHECK-LLVM-DAG: [[TQ]] = !{!"pipe", !"pipe", !"", !"", !"", !"", !"", !"", !""}

!1 = !{i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1}
!2 = !{!"read_only", !"write_only", !"read_only", !"read_only", !"read_only", !"read_only", !"read_only", !"write_only", !"read_write"}
!3 = !{!"int", !"int", !"image1d_t", !"image2d_t", !"image3d_t", !"image2d_array_t", !"image1d_buffer_t", !"image1d_t", !"image2d_t"}
!4 = !{!"int", !"int", !"image1d_t", !"image2d_t", !"image3d_t", !"image2d_array_t", !"image1d_buffer_t", !"image1d_t", !"image2d_t"}
!5 = !{!"pipe", !"pipe", !"", !"", !"", !"", !"", !"", !""}
!6 = !{i32 1, i32 2}
!7 = !{i32 2, i32 0}
!8 = !{!"cl_khr_fp16"}
!9 = !{!"cl_images"}