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

Zoltán Gilián zoltan.gilian at gmail.com
Mon Jul 27 05:10:54 PDT 2015


On Tue, Jul 21, 2015 at 8:11 PM, Zoltan Gilian <zoltan.gilian at gmail.com> wrote:
> 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");

Changing the name "image_size" to "__llvm_image_size" to avoid name collisions.

> +      PushArgMD(NewArgMDs, ArgMD);
> +
> +      // Add format implicit argument.
> +      ArgTypes.push_back(ImageFormatType);
> +      ArgMD[2] = ArgMD[3] = MDString::get(*Context, "image_format");

Similar modification is required here.

> +      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