[llvm] [PATCH] AMDGPU: Add pass to lower OpenCL image and sampler arguments.

Zoltan Gilian zoltan.gilian at gmail.com
Tue Jul 21 11:11:32 PDT 2015


The pass adds new kernel arguments for image attributes, and
resolves calls to dummy attribute and resource id getter functions.
---
 lib/Target/AMDGPU/AMDGPU.h                         |   1 +
 .../AMDGPU/AMDGPUOpenCLImageTypeLoweringPass.cpp   | 366 ++++++++++++++++++
 lib/Target/AMDGPU/AMDGPUTargetMachine.cpp          |   2 +
 test/CodeGen/AMDGPU/image-attributes.ll            | 206 +++++++++++
 test/CodeGen/AMDGPU/image-resource-id.ll           | 409 +++++++++++++++++++++
 test/CodeGen/AMDGPU/sampler-resource-id.ll         |  65 ++++
 6 files changed, 1049 insertions(+)
 create mode 100644 lib/Target/AMDGPU/AMDGPUOpenCLImageTypeLoweringPass.cpp
 create mode 100644 test/CodeGen/AMDGPU/image-attributes.ll
 create mode 100644 test/CodeGen/AMDGPU/image-resource-id.ll
 create mode 100644 test/CodeGen/AMDGPU/sampler-resource-id.ll

diff --git a/lib/Target/AMDGPU/AMDGPU.h b/lib/Target/AMDGPU/AMDGPU.h
index 0a05d25..33026f5 100644
--- a/lib/Target/AMDGPU/AMDGPU.h
+++ b/lib/Target/AMDGPU/AMDGPU.h
@@ -64,6 +64,7 @@ FunctionPass *createAMDGPUPromoteAlloca(const AMDGPUSubtarget &ST);
 Pass *createAMDGPUStructurizeCFGPass();
 FunctionPass *createAMDGPUISelDag(TargetMachine &tm);
 ModulePass *createAMDGPUAlwaysInlinePass();
+ModulePass *createAMDGPUOpenCLImageTypeLoweringPass();
 
 void initializeSIFixControlFlowLiveIntervalsPass(PassRegistry&);
 extern char &SIFixControlFlowLiveIntervalsID;
diff --git a/lib/Target/AMDGPU/AMDGPUOpenCLImageTypeLoweringPass.cpp b/lib/Target/AMDGPU/AMDGPUOpenCLImageTypeLoweringPass.cpp
new file mode 100644
index 0000000..47c50a1
--- /dev/null
+++ b/lib/Target/AMDGPU/AMDGPUOpenCLImageTypeLoweringPass.cpp
@@ -0,0 +1,366 @@
+//===-- AMDGPUOpenCLImageTypeLoweringPass.cpp -----------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// This pass resolves calls to OpenCL image attribute, image resource ID and
+/// sampler resource ID getter functions.
+///
+/// Image attributes (size and format) are expected to be passed to the kernel
+/// as kernel arguments immediately following the image argument itself,
+/// therefore this pass adds image size and format arguments to the kernel
+/// functions in the module. The kernel functions with image arguments are
+/// re-created using the new signature. The new arguments are added to the
+/// kernel metadata with kernel_arg_type set to "image_size" or "image_format".
+/// Note: this pass may invalidate pointers to functions.
+///
+/// Resource IDs of read-only images, write-only images and samplers are
+/// defined to be their index among the kernel arguments of the same
+/// type and access qualifier.
+//===----------------------------------------------------------------------===//
+
+#include "AMDGPU.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Analysis/Passes.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+
+using namespace llvm;
+
+namespace {
+
+StringRef GetImageSizeFunc =         "llvm.OpenCL.image.get.size";
+StringRef GetImageFormatFunc =       "llvm.OpenCL.image.get.format";
+StringRef GetImageResourceIDFunc =   "llvm.OpenCL.image.get.resource.id";
+StringRef GetSamplerResourceIDFunc = "llvm.OpenCL.sampler.get.resource.id";
+
+StringRef KernelsMDNodeName = "opencl.kernels";
+StringRef KernelArgMDNodeNames[] = {
+  "kernel_arg_addr_space",
+  "kernel_arg_access_qual",
+  "kernel_arg_type",
+  "kernel_arg_base_type",
+  "kernel_arg_type_qual"};
+constexpr unsigned NumKernelArgMDNodes = array_lengthof(KernelArgMDNodeNames);
+
+typedef SmallVector<Metadata *, 8> MDVector;
+struct KernelArgMD {
+  MDVector ArgVector[NumKernelArgMDNodes];
+};
+
+} // end anonymous namespace
+
+static inline bool
+IsImageType(StringRef TypeString) {
+  return TypeString == "image2d_t" || TypeString == "image3d_t";
+}
+
+static inline bool
+IsSamplerType(StringRef TypeString) {
+  return TypeString == "sampler_t";
+}
+
+static Function *
+GetFunctionFromMDNode(MDNode *Node) {
+  if (!Node)
+    return nullptr;
+
+  size_t NumOps = Node->getNumOperands();
+  if (NumOps != NumKernelArgMDNodes + 1)
+    return nullptr;
+
+  auto F = mdconst::dyn_extract<Function>(Node->getOperand(0));
+  if (!F)
+    return nullptr;
+
+  // Sanity checks.
+  size_t ExpectNumArgNodeOps = F->arg_size() + 1;
+  for (size_t i = 0; i < NumKernelArgMDNodes; ++i) {
+    MDNode *ArgNode = dyn_cast_or_null<MDNode>(Node->getOperand(i + 1));
+    if (ArgNode->getNumOperands() != ExpectNumArgNodeOps)
+      return nullptr;
+    if (!ArgNode->getOperand(0))
+      return nullptr;
+    assert(cast<MDString>(ArgNode->getOperand(0))->getString() ==
+           KernelArgMDNodeNames[i] && "Wrong kernel arg metadata name");
+  }
+
+  return F;
+}
+
+static StringRef
+AccessQualFromMD(MDNode *KernelMDNode, unsigned ArgIdx) {
+  MDNode *ArgAQNode = cast<MDNode>(KernelMDNode->getOperand(2));
+  return cast<MDString>(ArgAQNode->getOperand(ArgIdx + 1))->getString();
+}
+
+static StringRef
+ArgTypeFromMD(MDNode *KernelMDNode, unsigned ArgIdx) {
+  MDNode *ArgTypeNode = cast<MDNode>(KernelMDNode->getOperand(3));
+  return cast<MDString>(ArgTypeNode->getOperand(ArgIdx + 1))->getString();
+}
+
+static MDVector
+GetArgMD(MDNode *KernelMDNode, unsigned OpIdx) {
+  MDVector Res;
+  for (unsigned i = 0; i < NumKernelArgMDNodes; ++i) {
+    MDNode *Node = cast<MDNode>(KernelMDNode->getOperand(i + 1));
+    Res.push_back(Node->getOperand(OpIdx));
+  }
+  return Res;
+}
+
+static void
+PushArgMD(KernelArgMD &MD, const MDVector &V) {
+  assert(V.size() == NumKernelArgMDNodes);
+  for (unsigned i = 0; i < NumKernelArgMDNodes; ++i) {
+    MD.ArgVector[i].push_back(V[i]);
+  }
+}
+
+namespace {
+
+class AMDGPUOpenCLImageTypeLoweringPass : public ModulePass {
+  static char ID;
+
+  LLVMContext *Context;
+  Type *Int32Type;
+  Type *ImageSizeType;
+  Type *ImageFormatType;
+  SmallVector<Instruction *, 4> InstsToErase;
+
+  bool replaceImageUses(Argument &ImageArg, uint32_t ResourceID,
+                        Argument &ImageSizeArg,
+                        Argument &ImageFormatArg) {
+    bool Modified = false;
+
+    for (auto &Use : ImageArg.uses()) {
+      auto Inst = dyn_cast<CallInst>(Use.getUser());
+      if (!Inst) {
+        continue;
+      }
+
+      Function *F = Inst->getCalledFunction();
+      if (!F)
+        continue;
+
+      Value *Replacement = nullptr;
+      StringRef Name = F->getName();
+      if (Name.startswith(GetImageResourceIDFunc)) {
+        Replacement = ConstantInt::get(Int32Type, ResourceID);
+      } else if (Name.startswith(GetImageSizeFunc)) {
+        Replacement = &ImageSizeArg;
+      } else if (Name.startswith(GetImageFormatFunc)) {
+        Replacement = &ImageFormatArg;
+      } else {
+        continue;
+      }
+
+      Inst->replaceAllUsesWith(Replacement);
+      InstsToErase.push_back(Inst);
+      Modified = true;
+    }
+
+    return Modified;
+  }
+
+  bool replaceSamplerUses(Argument &SamplerArg, uint32_t ResourceID) {
+    bool Modified = false;
+
+    for (const auto &Use : SamplerArg.uses()) {
+      auto Inst = dyn_cast<CallInst>(Use.getUser());
+      if (!Inst) {
+        continue;
+      }
+
+      Function *F = Inst->getCalledFunction();
+      if (!F)
+        continue;
+
+      Value *Replacement = nullptr;
+      StringRef Name = F->getName();
+      if (Name == GetSamplerResourceIDFunc) {
+        Replacement = ConstantInt::get(Int32Type, ResourceID);
+      } else {
+        continue;
+      }
+
+      Inst->replaceAllUsesWith(Replacement);
+      InstsToErase.push_back(Inst);
+      Modified = true;
+    }
+
+    return Modified;
+  }
+
+  bool replaceImageAndSamplerUses(Function *F, MDNode *KernelMDNode) {
+    uint32_t NumReadOnlyImageArgs = 0;
+    uint32_t NumWriteOnlyImageArgs = 0;
+    uint32_t NumSamplerArgs = 0;
+
+    bool Modified = false;
+    InstsToErase.clear();
+    for (auto ArgI = F->arg_begin(); ArgI != F->arg_end(); ++ArgI) {
+      Argument &Arg = *ArgI;
+      StringRef Type = ArgTypeFromMD(KernelMDNode, Arg.getArgNo());
+
+      // Handle image types.
+      if (IsImageType(Type)) {
+        StringRef AccessQual = AccessQualFromMD(KernelMDNode, Arg.getArgNo());
+        uint32_t ResourceID;
+        if (AccessQual == "read_only") {
+          ResourceID = NumReadOnlyImageArgs++;
+        } else if (AccessQual == "write_only") {
+          ResourceID = NumWriteOnlyImageArgs++;
+        } else {
+          llvm_unreachable("Wrong image access qualifier.");
+        }
+
+        Argument &SizeArg = *(++ArgI);
+        Argument &FormatArg = *(++ArgI);
+        Modified |= replaceImageUses(Arg, ResourceID, SizeArg, FormatArg);
+
+      // Handle sampler type.
+      } else if (IsSamplerType(Type)) {
+        uint32_t ResourceID = NumSamplerArgs++;
+        Modified |= replaceSamplerUses(Arg, ResourceID);
+      }
+    }
+    for (unsigned i = 0; i < InstsToErase.size(); ++i) {
+      InstsToErase[i]->eraseFromParent();
+    }
+
+    return Modified;
+  }
+
+  std::tuple<Function *, MDNode *>
+  addImplicitArgs(Function *F, MDNode *KernelMDNode) {
+    bool Modified = false;
+
+    FunctionType *FT = F->getFunctionType();
+    SmallVector<Type *, 8> ArgTypes;
+
+    // Metadata operands for new MDNode.
+    KernelArgMD NewArgMDs;
+    PushArgMD(NewArgMDs, GetArgMD(KernelMDNode, 0));
+
+    // Add implicit arguments to the signature.
+    for (unsigned i = 0; i < FT->getNumParams(); ++i) {
+      ArgTypes.push_back(FT->getParamType(i));
+      MDVector ArgMD = GetArgMD(KernelMDNode, i + 1);
+      PushArgMD(NewArgMDs, ArgMD);
+
+      if (!IsImageType(ArgTypeFromMD(KernelMDNode, i)))
+        continue;
+
+      // Add size implicit argument.
+      ArgTypes.push_back(ImageSizeType);
+      ArgMD[2] = ArgMD[3] = MDString::get(*Context, "image_size");
+      PushArgMD(NewArgMDs, ArgMD);
+
+      // Add format implicit argument.
+      ArgTypes.push_back(ImageFormatType);
+      ArgMD[2] = ArgMD[3] = MDString::get(*Context, "image_format");
+      PushArgMD(NewArgMDs, ArgMD);
+
+      Modified = true;
+    }
+    if (!Modified) {
+      return std::make_tuple(nullptr, nullptr);
+    }
+
+    // Create function with new signature and clone the old body into it.
+    auto NewFT = FunctionType::get(FT->getReturnType(), ArgTypes, false);
+    auto NewF = Function::Create(NewFT, F->getLinkage(), F->getName());
+    ValueToValueMapTy VMap;
+    auto NewFArgIt = NewF->arg_begin();
+    for (auto &Arg: F->args()) {
+      auto ArgName = Arg.getName();
+      NewFArgIt->setName(ArgName);
+      VMap[&Arg] = &(*NewFArgIt++);
+      if (IsImageType(ArgTypeFromMD(KernelMDNode, Arg.getArgNo()))) {
+        (NewFArgIt++)->setName(Twine("__size_") + ArgName);
+        (NewFArgIt++)->setName(Twine("__format_") + ArgName);
+      }
+    }
+    SmallVector<ReturnInst*, 8> Returns;
+    CloneFunctionInto(NewF, F, VMap, /*ModuleLevelChanges=*/false, Returns);
+
+    // Build new MDNode.
+    SmallVector<llvm::Metadata *, 6> KernelMDArgs;
+    KernelMDArgs.push_back(ConstantAsMetadata::get(NewF));
+    for (unsigned i = 0; i < NumKernelArgMDNodes; ++i)
+      KernelMDArgs.push_back(MDNode::get(*Context, NewArgMDs.ArgVector[i]));
+    MDNode *NewMDNode = MDNode::get(*Context, KernelMDArgs);
+
+    return std::make_tuple(NewF, NewMDNode);
+  }
+
+  bool transformKernels(Module &M) {
+    NamedMDNode *KernelsMDNode = M.getNamedMetadata(KernelsMDNodeName);
+    if (!KernelsMDNode)
+      return false;
+
+    bool Modified = false;
+    for (unsigned i = 0; i < KernelsMDNode->getNumOperands(); ++i) {
+      MDNode *KernelMDNode = KernelsMDNode->getOperand(i);
+      Function *F = GetFunctionFromMDNode(KernelMDNode);
+      if (!F)
+        continue;
+
+      Function *NewF;
+      MDNode *NewMDNode;
+      std::tie(NewF, NewMDNode) = addImplicitArgs(F, KernelMDNode);
+      if (NewF) {
+        // Replace old function and metadata with new ones.
+        F->eraseFromParent();
+        M.getFunctionList().push_back(NewF);
+        M.getOrInsertFunction(NewF->getName(), NewF->getFunctionType(),
+                              NewF->getAttributes());
+        KernelsMDNode->setOperand(i, NewMDNode);
+
+        F = NewF;
+        KernelMDNode = NewMDNode;
+        Modified = true;
+      }
+
+      Modified |= replaceImageAndSamplerUses(F, KernelMDNode);
+    }
+
+    return Modified;
+  }
+
+ public:
+  AMDGPUOpenCLImageTypeLoweringPass() : ModulePass(ID) {}
+
+  bool runOnModule(Module &M) override {
+    Context = &M.getContext();
+    Int32Type = Type::getInt32Ty(M.getContext());
+    ImageSizeType = ArrayType::get(Int32Type, 3);
+    ImageFormatType = ArrayType::get(Int32Type, 2);
+
+    return transformKernels(M);
+  }
+
+  const char *getPassName() const override {
+    return "AMDGPU OpenCL Image Type Pass";
+  }
+};
+
+char AMDGPUOpenCLImageTypeLoweringPass::ID = 0;
+
+} // end anonymous namespace
+
+ModulePass *llvm::createAMDGPUOpenCLImageTypeLoweringPass() {
+  return new AMDGPUOpenCLImageTypeLoweringPass();
+}
diff --git a/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp b/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
index 2297b52..9d82be6 100644
--- a/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
+++ b/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
@@ -172,6 +172,8 @@ void AMDGPUPassConfig::addIRPasses() {
   // functions, then we will generate code for the first function
   // without ever running any passes on the second.
   addPass(createBarrierNoopPass());
+  // Handle uses of OpenCL image2d_t, image3d_t and sampler_t arguments.
+  addPass(createAMDGPUOpenCLImageTypeLoweringPass());
   TargetPassConfig::addIRPasses();
 }
 
diff --git a/test/CodeGen/AMDGPU/image-attributes.ll b/test/CodeGen/AMDGPU/image-attributes.ll
new file mode 100644
index 0000000..7a5a734
--- /dev/null
+++ b/test/CodeGen/AMDGPU/image-attributes.ll
@@ -0,0 +1,206 @@
+; RUN: llc -march=r600 -mcpu=juniper < %s | FileCheck -check-prefix=EG -check-prefix=FUNC %s
+
+; === WIDTH ==================================================================
+; 9 implicit args = 9 dwords to first image argument.
+; First width at dword index 9+1 -> KC0[2].Z
+
+; FUNC-LABEL: {{^}}width_2d:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], KC0[2].Z
+define void @width_2d (%opencl.image2d_t addrspace(1)* %in,
+                       i32 addrspace(1)* %out) {
+entry:
+  %0 = call [3 x i32] @llvm.OpenCL.image.get.size.2d(
+      %opencl.image2d_t addrspace(1)* %in) #0
+  %1 = extractvalue [3 x i32] %0, 0
+  store i32 %1, i32 addrspace(1)* %out
+  ret void
+}
+
+; FUNC-LABEL: {{^}}width_3d:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], KC0[2].Z
+define void @width_3d (%opencl.image3d_t addrspace(1)* %in,
+                       i32 addrspace(1)* %out) {
+entry:
+  %0 = call [3 x i32] @llvm.OpenCL.image.get.size.3d(
+      %opencl.image3d_t addrspace(1)* %in) #0
+  %1 = extractvalue [3 x i32] %0, 0
+  store i32 %1, i32 addrspace(1)* %out
+  ret void
+}
+
+
+; === HEIGHT =================================================================
+; First height at dword index 9+2 -> KC0[2].W
+
+; FUNC-LABEL: {{^}}height_2d:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], KC0[2].W
+define void @height_2d (%opencl.image2d_t addrspace(1)* %in,
+                        i32 addrspace(1)* %out) {
+entry:
+  %0 = call [3 x i32] @llvm.OpenCL.image.get.size.2d(
+      %opencl.image2d_t addrspace(1)* %in) #0
+  %1 = extractvalue [3 x i32] %0, 1
+  store i32 %1, i32 addrspace(1)* %out
+  ret void
+}
+
+; FUNC-LABEL: {{^}}height_3d:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], KC0[2].W
+define void @height_3d (%opencl.image3d_t addrspace(1)* %in,
+                        i32 addrspace(1)* %out) {
+entry:
+  %0 = call [3 x i32] @llvm.OpenCL.image.get.size.3d(
+      %opencl.image3d_t addrspace(1)* %in) #0
+  %1 = extractvalue [3 x i32] %0, 1
+  store i32 %1, i32 addrspace(1)* %out
+  ret void
+}
+
+
+; === DEPTH ==================================================================
+; First depth at dword index 9+3 -> KC0[3].X
+
+; FUNC-LABEL: {{^}}depth_3d:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], KC0[3].X
+define void @depth_3d (%opencl.image3d_t addrspace(1)* %in,
+                       i32 addrspace(1)* %out) {
+entry:
+  %0 = call [3 x i32] @llvm.OpenCL.image.get.size.3d(
+      %opencl.image3d_t addrspace(1)* %in) #0
+  %1 = extractvalue [3 x i32] %0, 2
+  store i32 %1, i32 addrspace(1)* %out
+  ret void
+}
+
+
+; === CHANNEL DATA TYPE ======================================================
+; First channel data type at dword index 9+4 -> KC0[3].Y
+
+; FUNC-LABEL: {{^}}data_type_2d:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], KC0[3].Y
+define void @data_type_2d (%opencl.image2d_t addrspace(1)* %in,
+                           i32 addrspace(1)* %out) {
+entry:
+  %0 = call [2 x i32] @llvm.OpenCL.image.get.format.2d(
+      %opencl.image2d_t addrspace(1)* %in) #0
+  %1 = extractvalue [2 x i32] %0, 0
+  store i32 %1, i32 addrspace(1)* %out
+  ret void
+}
+
+; FUNC-LABEL: {{^}}data_type_3d:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], KC0[3].Y
+define void @data_type_3d (%opencl.image3d_t addrspace(1)* %in,
+                                     i32 addrspace(1)* %out) {
+entry:
+  %0 = call [2 x i32] @llvm.OpenCL.image.get.format.3d(
+      %opencl.image3d_t addrspace(1)* %in) #0
+  %1 = extractvalue [2 x i32] %0, 0
+  store i32 %1, i32 addrspace(1)* %out
+  ret void
+}
+
+
+; === CHANNEL ORDER ==========================================================
+; First channel order at dword index 9+5 -> KC0[3].Z
+
+; FUNC-LABEL: {{^}}channel_order_2d:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], KC0[3].Z
+define void @channel_order_2d (%opencl.image2d_t addrspace(1)* %in,
+                               i32 addrspace(1)* %out) {
+entry:
+  %0 = call [2 x i32] @llvm.OpenCL.image.get.format.2d(
+      %opencl.image2d_t addrspace(1)* %in) #0
+  %1 = extractvalue [2 x i32] %0, 1
+  store i32 %1, i32 addrspace(1)* %out
+  ret void
+}
+
+; FUNC-LABEL: {{^}}channel_order_3d:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], KC0[3].Z
+define void @channel_order_3d (%opencl.image3d_t addrspace(1)* %in,
+                                         i32 addrspace(1)* %out) {
+entry:
+  %0 = call [2 x i32] @llvm.OpenCL.image.get.format.3d(
+      %opencl.image3d_t addrspace(1)* %in) #0
+  %1 = extractvalue [2 x i32] %0, 1
+  store i32 %1, i32 addrspace(1)* %out
+  ret void
+}
+
+
+; === 2ND IMAGE ==============================================================
+; 9 implicit args + 2 explicit args + 5 implicit args for 1st image argument
+;   = 16 dwords to 2nd image argument.
+; Height of the second image is at 16+2 -> KC0[4].Z
+;
+; FUNC-LABEL: {{^}}image_arg_2nd:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], KC0[4].Z
+define void @image_arg_2nd (%opencl.image3d_t addrspace(1)* %in1,
+                            i32 %x,
+                            %opencl.image2d_t addrspace(1)* %in2,
+                            i32 addrspace(1)* %out) {
+entry:
+  %0 = call [3 x i32] @llvm.OpenCL.image.get.size.2d(
+      %opencl.image2d_t addrspace(1)* %in2) #0
+  %1 = extractvalue [3 x i32] %0, 1
+  store i32 %1, i32 addrspace(1)* %out
+  ret void
+}
+
+%opencl.image2d_t = type opaque
+%opencl.image3d_t = type opaque
+
+declare [3 x i32] @llvm.OpenCL.image.get.size.2d(%opencl.image2d_t addrspace(1)*) #0
+declare [3 x i32] @llvm.OpenCL.image.get.size.3d(%opencl.image3d_t addrspace(1)*) #0
+declare [2 x i32] @llvm.OpenCL.image.get.format.2d(%opencl.image2d_t addrspace(1)*) #0
+declare [2 x i32] @llvm.OpenCL.image.get.format.3d(%opencl.image3d_t addrspace(1)*) #0
+
+attributes #0 = { readnone }
+
+!opencl.kernels = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
+!0 = !{void (%opencl.image2d_t addrspace(1)*, i32 addrspace(1)*)* @width_2d,
+       !10, !20, !30, !40, !50}
+!1 = !{void (%opencl.image3d_t addrspace(1)*, i32 addrspace(1)*)* @width_3d,
+       !10, !21, !31, !41, !50}
+!2 = !{void (%opencl.image2d_t addrspace(1)*, i32 addrspace(1)*)* @height_2d,
+       !10, !20, !30, !40, !50}
+!3 = !{void (%opencl.image3d_t addrspace(1)*, i32 addrspace(1)*)* @height_3d,
+       !10, !21, !31, !41, !50}
+!4 = !{void (%opencl.image3d_t addrspace(1)*, i32 addrspace(1)*)* @depth_3d,
+       !10, !21, !31, !41, !50}
+!5 = !{void (%opencl.image2d_t addrspace(1)*, i32 addrspace(1)*)* @data_type_2d,
+       !10, !20, !30, !40, !50}
+!6 = !{void (%opencl.image3d_t addrspace(1)*, i32 addrspace(1)*)* @data_type_3d,
+       !10, !21, !31, !41, !50}
+!7 = !{void (%opencl.image2d_t addrspace(1)*, i32 addrspace(1)*)* @channel_order_2d,
+       !10, !20, !30, !40, !50}
+!8 = !{void (%opencl.image3d_t addrspace(1)*, i32 addrspace(1)*)* @channel_order_3d,
+       !10, !21, !31, !41, !50}
+!9 = !{void (%opencl.image3d_t addrspace(1)*, i32, %opencl.image2d_t addrspace(1)*,
+      i32 addrspace(1)*)* @image_arg_2nd, !12, !22, !32, !42, !52}
+
+!10 = !{!"kernel_arg_addr_space", i32 1, i32 1}
+!20 = !{!"kernel_arg_access_qual", !"read_only", !"none"}
+!21 = !{!"kernel_arg_access_qual", !"read_only", !"none"}
+!30 = !{!"kernel_arg_type", !"image2d_t", !"int*"}
+!31 = !{!"kernel_arg_type", !"image3d_t", !"int*"}
+!40 = !{!"kernel_arg_base_type", !"image2d_t", !"int*"}
+!41 = !{!"kernel_arg_base_type", !"image3d_t", !"int*"}
+!50 = !{!"kernel_arg_type_qual", !"", !""}
+
+!12 = !{!"kernel_arg_addr_space", i32 1, i32 0, i32 1, i32 1}
+!22 = !{!"kernel_arg_access_qual", !"read_only", !"none", !"write_only", !"none"}
+!32 = !{!"kernel_arg_type", !"image3d_t", !"sampler_t", !"image2d_t", !"int*"}
+!42 = !{!"kernel_arg_base_type", !"image3d_t", !"sampler_t", !"image2d_t", !"int*"}
+!52 = !{!"kernel_arg_type_qual", !"", !"", !"", !""}
diff --git a/test/CodeGen/AMDGPU/image-resource-id.ll b/test/CodeGen/AMDGPU/image-resource-id.ll
new file mode 100644
index 0000000..d4cf349
--- /dev/null
+++ b/test/CodeGen/AMDGPU/image-resource-id.ll
@@ -0,0 +1,409 @@
+; RUN: llc -march=r600 -mcpu=juniper < %s | FileCheck -check-prefix=EG -check-prefix=FUNC %s
+
+; === 1 image arg, read_only ===================================================
+
+; FUNC-LABEL: {{^}}test_2d_rd_1_0:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], literal.x
+; EG-NEXT: LSHR
+; EG-NEXT: 0(
+define void @test_2d_rd_1_0(%opencl.image2d_t addrspace(1)* %in, ; read_only
+                            i32 addrspace(1)* %out) {
+entry:
+  %0 = call i32 @llvm.OpenCL.image.get.resource.id.2d(
+      %opencl.image2d_t addrspace(1)* %in) #0
+  store i32 %0, i32 addrspace(1)* %out
+  ret void
+}
+
+; FUNC-LABEL: {{^}}test_3d_rd_1_0:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], literal.x
+; EG-NEXT: LSHR
+; EG-NEXT: 0(
+define void @test_3d_rd_1_0(%opencl.image3d_t addrspace(1)* %in, ; read_only
+                            i32 addrspace(1)* %out) {
+entry:
+  %0 = call i32 @llvm.OpenCL.image.get.resource.id.3d(
+      %opencl.image3d_t addrspace(1)* %in) #0
+  store i32 %0, i32 addrspace(1)* %out
+  ret void
+}
+
+; === 1 image arg, write_only ==================================================
+
+; FUNC-LABEL: {{^}}test_2d_wr_1_0:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], literal.x
+; EG-NEXT: LSHR
+; EG-NEXT: 0(
+define void @test_2d_wr_1_0(%opencl.image2d_t addrspace(1)* %in, ; write_only
+                            i32 addrspace(1)* %out) {
+entry:
+  %0 = call i32 @llvm.OpenCL.image.get.resource.id.2d(
+      %opencl.image2d_t addrspace(1)* %in) #0
+  store i32 %0, i32 addrspace(1)* %out
+  ret void
+}
+
+; FUNC-LABEL: {{^}}test_3d_wr_1_0:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], literal.x
+; EG-NEXT: LSHR
+; EG-NEXT: 0(
+define void @test_3d_wr_1_0(%opencl.image3d_t addrspace(1)* %in, ; write_only
+                            i32 addrspace(1)* %out) {
+entry:
+  %0 = call i32 @llvm.OpenCL.image.get.resource.id.3d(
+      %opencl.image3d_t addrspace(1)* %in) #0
+  store i32 %0, i32 addrspace(1)* %out
+  ret void
+}
+
+; === 2 image args, read_only ==================================================
+
+; FUNC-LABEL: {{^}}test_2d_rd_2_0:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], literal.x
+; EG-NEXT: LSHR
+; EG-NEXT: 0(
+define void @test_2d_rd_2_0(%opencl.image2d_t addrspace(1)* %in1, ; read_only
+                            %opencl.image2d_t addrspace(1)* %in2, ; read_only
+                            i32 addrspace(1)* %out) {
+entry:
+  %0 = call i32 @llvm.OpenCL.image.get.resource.id.2d(
+      %opencl.image2d_t addrspace(1)* %in1) #0
+  store i32 %0, i32 addrspace(1)* %out
+  ret void
+}
+
+; FUNC-LABEL: {{^}}test_2d_rd_2_1:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], literal.x
+; EG-NEXT: LSHR
+; EG-NEXT: 1(
+define void @test_2d_rd_2_1(%opencl.image2d_t addrspace(1)* %in1, ; read_only
+                            %opencl.image2d_t addrspace(1)* %in2, ; read_only
+                            i32 addrspace(1)* %out) {
+entry:
+  %0 = call i32 @llvm.OpenCL.image.get.resource.id.2d(
+      %opencl.image2d_t addrspace(1)* %in2) #0
+  store i32 %0, i32 addrspace(1)* %out
+  ret void
+}
+
+; FUNC-LABEL: {{^}}test_3d_rd_2_0:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], literal.x
+; EG-NEXT: LSHR
+; EG-NEXT: 0(
+define void @test_3d_rd_2_0(%opencl.image3d_t addrspace(1)* %in1, ; read_only
+                            %opencl.image3d_t addrspace(1)* %in2, ; read_only
+                            i32 addrspace(1)* %out) {
+entry:
+  %0 = call i32 @llvm.OpenCL.image.get.resource.id.3d(
+      %opencl.image3d_t addrspace(1)* %in1) #0
+  store i32 %0, i32 addrspace(1)* %out
+  ret void
+}
+
+; FUNC-LABEL: {{^}}test_3d_rd_2_1:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], literal.x
+; EG-NEXT: LSHR
+; EG-NEXT: 1(
+define void @test_3d_rd_2_1(%opencl.image3d_t addrspace(1)* %in1, ; read_only
+                            %opencl.image3d_t addrspace(1)* %in2, ; read_only
+                            i32 addrspace(1)* %out) {
+entry:
+  %0 = call i32 @llvm.OpenCL.image.get.resource.id.3d(
+      %opencl.image3d_t addrspace(1)* %in2) #0
+  store i32 %0, i32 addrspace(1)* %out
+  ret void
+}
+
+; === 2 image args, write_only =================================================
+
+; FUNC-LABEL: {{^}}test_2d_wr_2_0:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], literal.x
+; EG-NEXT: LSHR
+; EG-NEXT: 0(
+define void @test_2d_wr_2_0(%opencl.image2d_t addrspace(1)* %in1, ; write_only
+                            %opencl.image2d_t addrspace(1)* %in2, ; write_only
+                            i32 addrspace(1)* %out) {
+entry:
+  %0 = call i32 @llvm.OpenCL.image.get.resource.id.2d(
+      %opencl.image2d_t addrspace(1)* %in1) #0
+  store i32 %0, i32 addrspace(1)* %out
+  ret void
+}
+
+; FUNC-LABEL: {{^}}test_2d_wr_2_1:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], literal.x
+; EG-NEXT: LSHR
+; EG-NEXT: 1(
+define void @test_2d_wr_2_1(%opencl.image2d_t addrspace(1)* %in1, ; write_only
+                            %opencl.image2d_t addrspace(1)* %in2, ; write_only
+                            i32 addrspace(1)* %out) {
+entry:
+  %0 = call i32 @llvm.OpenCL.image.get.resource.id.2d(
+      %opencl.image2d_t addrspace(1)* %in2) #0
+  store i32 %0, i32 addrspace(1)* %out
+  ret void
+}
+
+; FUNC-LABEL: {{^}}test_3d_wr_2_0:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], literal.x
+; EG-NEXT: LSHR
+; EG-NEXT: 0(
+define void @test_3d_wr_2_0(%opencl.image3d_t addrspace(1)* %in1, ; write_only
+                            %opencl.image3d_t addrspace(1)* %in2, ; write_only
+                            i32 addrspace(1)* %out) {
+entry:
+  %0 = call i32 @llvm.OpenCL.image.get.resource.id.3d(
+      %opencl.image3d_t addrspace(1)* %in1) #0
+  store i32 %0, i32 addrspace(1)* %out
+  ret void
+}
+
+; FUNC-LABEL: {{^}}test_3d_wr_2_1:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], literal.x
+; EG-NEXT: LSHR
+; EG-NEXT: 1(
+define void @test_3d_wr_2_1(%opencl.image3d_t addrspace(1)* %in1, ; write_only
+                            %opencl.image3d_t addrspace(1)* %in2, ; write_only
+                            i32 addrspace(1)* %out) {
+entry:
+  %0 = call i32 @llvm.OpenCL.image.get.resource.id.3d(
+      %opencl.image3d_t addrspace(1)* %in2) #0
+  store i32 %0, i32 addrspace(1)* %out
+  ret void
+}
+
+; === 3 image args, read_only ==================================================
+
+; FUNC-LABEL: {{^}}test_2d_rd_3_0:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], literal.x
+; EG-NEXT: LSHR
+; EG-NEXT: 2(
+define void @test_2d_rd_3_0(%opencl.image2d_t addrspace(1)* %in1, ; read_only
+                            %opencl.image3d_t addrspace(1)* %in2, ; read_only
+                            %opencl.image2d_t addrspace(1)* %in3, ; read_only
+                            i32 addrspace(1)* %out) {
+entry:
+  %0 = call i32 @llvm.OpenCL.image.get.resource.id.2d(
+      %opencl.image2d_t addrspace(1)* %in3) #0
+  store i32 %0, i32 addrspace(1)* %out
+  ret void
+}
+
+
+; FUNC-LABEL: {{^}}test_3d_rd_3_0:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], literal.x
+; EG-NEXT: LSHR
+; EG-NEXT: 2(
+define void @test_3d_rd_3_0(%opencl.image3d_t addrspace(1)* %in1, ; read_only
+                            %opencl.image2d_t addrspace(1)* %in2, ; read_only
+                            %opencl.image3d_t addrspace(1)* %in3, ; read_only
+                            i32 addrspace(1)* %out) {
+entry:
+  %0 = call i32 @llvm.OpenCL.image.get.resource.id.3d(
+      %opencl.image3d_t addrspace(1)* %in3) #0
+  store i32 %0, i32 addrspace(1)* %out
+  ret void
+}
+
+; === 3 image args, write_only =================================================
+
+; FUNC-LABEL: {{^}}test_2d_wr_3_0:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], literal.x
+; EG-NEXT: LSHR
+; EG-NEXT: 2(
+define void @test_2d_wr_3_0(%opencl.image2d_t addrspace(1)* %in1, ; write_only
+                            %opencl.image3d_t addrspace(1)* %in2, ; write_only
+                            %opencl.image2d_t addrspace(1)* %in3, ; write_only
+                            i32 addrspace(1)* %out) {
+entry:
+  %0 = call i32 @llvm.OpenCL.image.get.resource.id.2d(
+      %opencl.image2d_t addrspace(1)* %in3) #0
+  store i32 %0, i32 addrspace(1)* %out
+  ret void
+}
+
+
+; FUNC-LABEL: {{^}}test_3d_wr_3_0:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], literal.x
+; EG-NEXT: LSHR
+; EG-NEXT: 2(
+define void @test_3d_wr_3_0(%opencl.image3d_t addrspace(1)* %in1, ; write_only
+                            %opencl.image2d_t addrspace(1)* %in2, ; write_only
+                            %opencl.image3d_t addrspace(1)* %in3, ; write_only
+                            i32 addrspace(1)* %out) {
+entry:
+  %0 = call i32 @llvm.OpenCL.image.get.resource.id.3d(
+      %opencl.image3d_t addrspace(1)* %in3) #0
+  store i32 %0, i32 addrspace(1)* %out
+  ret void
+}
+
+; === 3 image args, mixed ======================================================
+
+; FUNC-LABEL: {{^}}test_2d_mix_3_0:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], literal.x
+; EG-NEXT: LSHR
+; EG-NEXT: 1(
+define void @test_2d_mix_3_0(%opencl.image2d_t addrspace(1)* %in1, ; write_only
+                             %opencl.image3d_t addrspace(1)* %in2, ; read_only
+                             %opencl.image2d_t addrspace(1)* %in3, ; read_only
+                             i32 addrspace(1)* %out) {
+entry:
+  %0 = call i32 @llvm.OpenCL.image.get.resource.id.2d(
+      %opencl.image2d_t addrspace(1)* %in3) #0
+  store i32 %0, i32 addrspace(1)* %out
+  ret void
+}
+
+; FUNC-LABEL: {{^}}test_3d_mix_3_0:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], literal.x
+; EG-NEXT: LSHR
+; EG-NEXT: 1(
+define void @test_3d_mix_3_0(%opencl.image3d_t addrspace(1)* %in1, ; write_only
+                             %opencl.image2d_t addrspace(1)* %in2, ; read_only
+                             %opencl.image3d_t addrspace(1)* %in3, ; read_only
+                             i32 addrspace(1)* %out) {
+entry:
+  %0 = call i32 @llvm.OpenCL.image.get.resource.id.3d(
+      %opencl.image3d_t addrspace(1)* %in3) #0
+  store i32 %0, i32 addrspace(1)* %out
+  ret void
+}
+
+; FUNC-LABEL: {{^}}test_2d_mix_3_1:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], literal.x
+; EG-NEXT: LSHR
+; EG-NEXT: 1(
+define void @test_2d_mix_3_1(%opencl.image2d_t addrspace(1)* %in1, ; write_only
+                             %opencl.image3d_t addrspace(1)* %in2, ; read_only
+                             %opencl.image2d_t addrspace(1)* %in3, ; write_only
+                             i32 addrspace(1)* %out) {
+entry:
+  %0 = call i32 @llvm.OpenCL.image.get.resource.id.2d(
+      %opencl.image2d_t addrspace(1)* %in3) #0
+  store i32 %0, i32 addrspace(1)* %out
+  ret void
+}
+
+; FUNC-LABEL: {{^}}test_3d_mix_3_1:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], literal.x
+; EG-NEXT: LSHR
+; EG-NEXT: 1(
+define void @test_3d_mix_3_1(%opencl.image3d_t addrspace(1)* %in1, ; write_only
+                             %opencl.image2d_t addrspace(1)* %in2, ; read_only
+                             %opencl.image3d_t addrspace(1)* %in3, ; write_only
+                             i32 addrspace(1)* %out) {
+entry:
+  %0 = call i32 @llvm.OpenCL.image.get.resource.id.3d(
+      %opencl.image3d_t addrspace(1)* %in3) #0
+  store i32 %0, i32 addrspace(1)* %out
+  ret void
+}
+
+
+%opencl.image2d_t = type opaque
+%opencl.image3d_t = type opaque
+
+declare i32 @llvm.OpenCL.image.get.resource.id.2d(%opencl.image2d_t addrspace(1)*) #0
+declare i32 @llvm.OpenCL.image.get.resource.id.3d(%opencl.image3d_t addrspace(1)*) #0
+
+attributes #0 = { readnone }
+
+!opencl.kernels = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11, !12, !13,
+                    !14, !15, !16, !17, !18, !19}
+!0 = !{void (%opencl.image2d_t addrspace(1)*, i32 addrspace(1)*)* @test_2d_rd_1_0,
+       !110, !120, !130, !140, !150}
+!1 = !{void (%opencl.image3d_t addrspace(1)*, i32 addrspace(1)*)* @test_3d_rd_1_0,
+       !110, !120, !131, !141, !150}
+!2 = !{void (%opencl.image2d_t addrspace(1)*, i32 addrspace(1)*)* @test_2d_wr_1_0,
+       !110, !121, !130, !140, !150}
+!3 = !{void (%opencl.image3d_t addrspace(1)*, i32 addrspace(1)*)* @test_3d_wr_1_0,
+       !110, !121, !131, !141, !150}
+!110 = !{!"kernel_arg_addr_space", i32 1, i32 1}
+!120 = !{!"kernel_arg_access_qual", !"read_only", !"none"}
+!121 = !{!"kernel_arg_access_qual", !"write_only", !"none"}
+!130 = !{!"kernel_arg_type", !"image2d_t", !"int*"}
+!131 = !{!"kernel_arg_type", !"image3d_t", !"int*"}
+!140 = !{!"kernel_arg_base_type", !"image2d_t", !"int*"}
+!141 = !{!"kernel_arg_base_type", !"image3d_t", !"int*"}
+!150 = !{!"kernel_arg_type_qual", !"", !""}
+
+!4  = !{void (%opencl.image2d_t addrspace(1)*, %opencl.image2d_t addrspace(1)*,
+              i32 addrspace(1)*)* @test_2d_rd_2_0, !112, !122, !132, !142, !152}
+!5  = !{void (%opencl.image2d_t addrspace(1)*, %opencl.image2d_t addrspace(1)*,
+              i32 addrspace(1)*)* @test_2d_rd_2_1, !112, !122, !132, !142, !152}
+!6  = !{void (%opencl.image3d_t addrspace(1)*, %opencl.image3d_t addrspace(1)*,
+              i32 addrspace(1)*)* @test_3d_rd_2_0, !112, !122, !133, !143, !152}
+!7  = !{void (%opencl.image3d_t addrspace(1)*, %opencl.image3d_t addrspace(1)*,
+              i32 addrspace(1)*)* @test_3d_rd_2_1, !112, !122, !133, !143, !152}
+!8  = !{void (%opencl.image2d_t addrspace(1)*, %opencl.image2d_t addrspace(1)*,
+              i32 addrspace(1)*)* @test_2d_wr_2_0, !112, !123, !132, !142, !152}
+!9  = !{void (%opencl.image2d_t addrspace(1)*, %opencl.image2d_t addrspace(1)*,
+              i32 addrspace(1)*)* @test_2d_wr_2_1, !112, !123, !132, !142, !152}
+!10 = !{void (%opencl.image3d_t addrspace(1)*, %opencl.image3d_t addrspace(1)*,
+              i32 addrspace(1)*)* @test_3d_wr_2_0, !112, !123, !133, !143, !152}
+!11 = !{void (%opencl.image3d_t addrspace(1)*, %opencl.image3d_t addrspace(1)*,
+              i32 addrspace(1)*)* @test_3d_wr_2_1, !112, !123, !133, !143, !152}
+!112 = !{!"kernel_arg_addr_space", i32 1, i32 1, i32 1}
+!122 = !{!"kernel_arg_access_qual", !"read_only", !"read_only", !"none"}
+!123 = !{!"kernel_arg_access_qual", !"write_only", !"write_only", !"none"}
+!132 = !{!"kernel_arg_type", !"image2d_t", !"image2d_t", !"int*"}
+!133 = !{!"kernel_arg_type", !"image3d_t", !"image3d_t", !"int*"}
+!142 = !{!"kernel_arg_base_type", !"image2d_t", !"image2d_t", !"int*"}
+!143 = !{!"kernel_arg_base_type", !"image3d_t", !"image3d_t", !"int*"}
+!152 = !{!"kernel_arg_type_qual", !"", !"", !""}
+
+!12 = !{void (%opencl.image2d_t addrspace(1)*, %opencl.image3d_t addrspace(1)*,
+              %opencl.image2d_t addrspace(1)*, i32 addrspace(1)*)* @test_2d_rd_3_0,
+              !114, !124, !134, !144, !154}
+!13 = !{void (%opencl.image3d_t addrspace(1)*, %opencl.image2d_t addrspace(1)*,
+              %opencl.image3d_t addrspace(1)*, i32 addrspace(1)*)* @test_3d_rd_3_0,
+              !114, !124, !135, !145, !154}
+!14 = !{void (%opencl.image2d_t addrspace(1)*, %opencl.image3d_t addrspace(1)*,
+              %opencl.image2d_t addrspace(1)*, i32 addrspace(1)*)* @test_2d_wr_3_0,
+              !114, !125, !134, !144, !154}
+!15 = !{void (%opencl.image3d_t addrspace(1)*, %opencl.image2d_t addrspace(1)*,
+              %opencl.image3d_t addrspace(1)*, i32 addrspace(1)*)* @test_3d_wr_3_0,
+              !114, !125, !135, !145, !154}
+!16 = !{void (%opencl.image2d_t addrspace(1)*, %opencl.image3d_t addrspace(1)*,
+              %opencl.image2d_t addrspace(1)*, i32 addrspace(1)*)* @test_2d_mix_3_0,
+              !114, !126, !134, !144, !154}
+!17 = !{void (%opencl.image3d_t addrspace(1)*, %opencl.image2d_t addrspace(1)*,
+              %opencl.image3d_t addrspace(1)*, i32 addrspace(1)*)* @test_3d_mix_3_0,
+              !114, !126, !135, !145, !154}
+!18 = !{void (%opencl.image2d_t addrspace(1)*, %opencl.image3d_t addrspace(1)*,
+              %opencl.image2d_t addrspace(1)*, i32 addrspace(1)*)* @test_2d_mix_3_1,
+              !114, !127, !134, !144, !154}
+!19 = !{void (%opencl.image3d_t addrspace(1)*, %opencl.image2d_t addrspace(1)*,
+              %opencl.image3d_t addrspace(1)*, i32 addrspace(1)*)* @test_3d_mix_3_1,
+              !114, !127, !135, !145, !154}
+!114 = !{!"kernel_arg_addr_space", i32 1, i32 1, i32 1, i32 1}
+!124 = !{!"kernel_arg_access_qual", !"read_only", !"read_only", !"read_only", !"none"}
+!125 = !{!"kernel_arg_access_qual", !"write_only", !"write_only", !"write_only", !"none"}
+!126 = !{!"kernel_arg_access_qual", !"write_only", !"read_only", !"read_only", !"none"}
+!127 = !{!"kernel_arg_access_qual", !"write_only", !"read_only", !"write_only", !"none"}
+!134 = !{!"kernel_arg_type", !"image2d_t", !"image3d_t", !"image2d_t", !"int*"}
+!135 = !{!"kernel_arg_type", !"image3d_t", !"image2d_t", !"image3d_t", !"int*"}
+!144 = !{!"kernel_arg_base_type", !"image2d_t", !"image3d_t", !"image2d_t", !"int*"}
+!145 = !{!"kernel_arg_base_type", !"image3d_t", !"image2d_t", !"image3d_t", !"int*"}
+!154 = !{!"kernel_arg_type_qual", !"", !"", !"", !""}
diff --git a/test/CodeGen/AMDGPU/sampler-resource-id.ll b/test/CodeGen/AMDGPU/sampler-resource-id.ll
new file mode 100644
index 0000000..c41d345
--- /dev/null
+++ b/test/CodeGen/AMDGPU/sampler-resource-id.ll
@@ -0,0 +1,65 @@
+; RUN: llc -march=r600 -mcpu=juniper < %s | FileCheck -check-prefix=EG -check-prefix=FUNC %s
+
+; FUNC-LABEL: {{^}}test_0:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], literal.x
+; EG-NEXT: LSHR
+; EG-NEXT: 0(
+define void @test_0(i32 %in0, i32 addrspace(1)* %out) {
+entry:
+  %0 = call i32 @llvm.OpenCL.sampler.get.resource.id(i32 %in0) #0
+  store i32 %0, i32 addrspace(1)* %out
+  ret void
+}
+
+; FUNC-LABEL: {{^}}test_1:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], literal.x
+; EG-NEXT: LSHR
+; EG-NEXT: 1(
+define void @test_1(i32 %in0, i32 %in1, i32 addrspace(1)* %out) {
+entry:
+  %0 = call i32 @llvm.OpenCL.sampler.get.resource.id(i32 %in1) #0
+  store i32 %0, i32 addrspace(1)* %out
+  ret void
+}
+
+; FUNC-LABEL: {{^}}test_2:
+; EG: MEM_RAT_CACHELESS STORE_RAW [[VAL:T[0-9]+\.X]]
+; EG: MOV [[VAL]], literal.x
+; EG-NEXT: LSHR
+; EG-NEXT: 2(
+define void @test_2(i32 %in0, i32 %in1, i32 %in2, i32 addrspace(1)* %out) {
+entry:
+  %0 = call i32 @llvm.OpenCL.sampler.get.resource.id(i32 %in2) #0
+  store i32 %0, i32 addrspace(1)* %out
+  ret void
+}
+
+
+declare i32 @llvm.OpenCL.sampler.get.resource.id(i32) #0
+
+attributes #0 = { readnone }
+
+!opencl.kernels = !{!0, !1, !2}
+
+!0 = !{void (i32, i32 addrspace(1)*)* @test_0, !10, !20, !30, !40, !50}
+!10 = !{!"kernel_arg_addr_space", i32 0, i32 1}
+!20 = !{!"kernel_arg_access_qual", !"none", !"none"}
+!30 = !{!"kernel_arg_type", !"sampler_t", !"int*"}
+!40 = !{!"kernel_arg_base_type", !"sampler_t", !"int*"}
+!50 = !{!"kernel_arg_type_qual", !"", !""}
+
+!1 = !{void (i32, i32, i32 addrspace(1)*)* @test_1, !11, !21, !31, !41, !51}
+!11 = !{!"kernel_arg_addr_space", i32 0, i32 0, i32 1}
+!21 = !{!"kernel_arg_access_qual", !"none", !"none", !"none"}
+!31 = !{!"kernel_arg_type", !"sampler_t", !"sampler_t", !"int*"}
+!41 = !{!"kernel_arg_base_type", !"sampler_t", !"sampler_t", !"int*"}
+!51 = !{!"kernel_arg_type_qual", !"", !"", !""}
+
+!2 = !{void (i32, i32, i32, i32 addrspace(1)*)* @test_2, !12, !22, !32, !42, !52}
+!12 = !{!"kernel_arg_addr_space", i32 0, i32 0, i32 0, i32 1}
+!22 = !{!"kernel_arg_access_qual", !"none", !"none", !"none", !"none"}
+!32 = !{!"kernel_arg_type", !"sampler_t", !"sampler_t", !"sampler_t", !"int*"}
+!42 = !{!"kernel_arg_base_type", !"sampler_t", !"sampler_t", !"sampler_t", !"int*"}
+!52 = !{!"kernel_arg_type_qual", !"", !"", !"", !""}
-- 
2.4.6




More information about the llvm-commits mailing list