[llvm] Image attribute access for the R600 backend

Zoltan Gilian zoltan.gilian at gmail.com
Mon Jun 15 23:48:22 PDT 2015


Added an intrinsic to load an image attribute stored as an implicit kernel
argument.
Added a pass to the R600 backend to replace image attribute getter
pseudointrinsics to the new image attribute reader intrinsic.
---
 include/llvm/IR/IntrinsicsR600.td                  |   5 +
 lib/Target/R600/AMDGPU.h                           |   1 +
 lib/Target/R600/AMDGPUTargetMachine.cpp            |   1 +
 lib/Target/R600/R600ISelLowering.cpp               |  15 ++
 .../R600/R600ImageAttributeIntrinsicsReplacer.cpp  | 194 +++++++++++++++++++++
 5 files changed, 216 insertions(+)
 create mode 100644 lib/Target/R600/R600ImageAttributeIntrinsicsReplacer.cpp

diff --git a/include/llvm/IR/IntrinsicsR600.td b/include/llvm/IR/IntrinsicsR600.td
index 5055667..635cf16 100644
--- a/include/llvm/IR/IntrinsicsR600.td
+++ b/include/llvm/IR/IntrinsicsR600.td
@@ -33,6 +33,11 @@ defm int_r600_read_tgid : R600ReadPreloadRegisterIntrinsic_xyz <
                                        "__builtin_r600_read_tgid">;
 defm int_r600_read_tidig : R600ReadPreloadRegisterIntrinsic_xyz <
                                        "__builtin_r600_read_tidig">;
+
+def int_r600_read_image_attribute
+  : Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>,
+    GCCBuiltin<"__builtin_r600_read_image_attribute">;
+
 } // End TargetPrefix = "r600"
 
 let TargetPrefix = "AMDGPU" in {
diff --git a/lib/Target/R600/AMDGPU.h b/lib/Target/R600/AMDGPU.h
index 0a05d25..4b5c5aa 100644
--- a/lib/Target/R600/AMDGPU.h
+++ b/lib/Target/R600/AMDGPU.h
@@ -27,6 +27,7 @@ class TargetMachine;
 
 // R600 Passes
 FunctionPass *createR600VectorRegMerger(TargetMachine &tm);
+FunctionPass *createR600ImageAttributeIntrinsicsReplacer();
 FunctionPass *createR600TextureIntrinsicsReplacer();
 FunctionPass *createR600ExpandSpecialInstrsPass(TargetMachine &tm);
 FunctionPass *createR600EmitClauseMarkers();
diff --git a/lib/Target/R600/AMDGPUTargetMachine.cpp b/lib/Target/R600/AMDGPUTargetMachine.cpp
index 0e37127..0f09a99 100644
--- a/lib/Target/R600/AMDGPUTargetMachine.cpp
+++ b/lib/Target/R600/AMDGPUTargetMachine.cpp
@@ -202,6 +202,7 @@ bool AMDGPUPassConfig::addInstSelector() {
 
 bool R600PassConfig::addPreISel() {
   AMDGPUPassConfig::addPreISel();
+  addPass(createR600ImageAttributeIntrinsicsReplacer());
   addPass(createR600TextureIntrinsicsReplacer());
   return false;
 }
diff --git a/lib/Target/R600/R600ISelLowering.cpp b/lib/Target/R600/R600ISelLowering.cpp
index 8357b6d..7bea7117 100644
--- a/lib/Target/R600/R600ISelLowering.cpp
+++ b/lib/Target/R600/R600ISelLowering.cpp
@@ -818,6 +818,21 @@ SDValue R600TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const
     case Intrinsic::AMDGPU_read_workdim:
       return LowerImplicitParameter(DAG, VT, DL, MFI->ABIArgOffset / 4);
 
+    case Intrinsic::r600_read_image_attribute:
+      {
+        // operand 0: image index
+        // operand 1: attribute index
+
+        uint64_t DWordOffset = MFI->ABIArgOffset / 4;
+        // Skip grid dim and grid offset.
+        DWordOffset += 4;
+        // There are 5 dword attributes per image.
+        DWordOffset += 5 * Op.getConstantOperandVal(1);
+        // Skip to the requested attribute.
+        DWordOffset += Op.getConstantOperandVal(2);
+        return LowerImplicitParameter(DAG, VT, DL, DWordOffset);
+      }
+
     case Intrinsic::r600_read_tgid_x:
       return CreateLiveInRegister(DAG, &AMDGPU::R600_TReg32RegClass,
                                   AMDGPU::T1_X, VT);
diff --git a/lib/Target/R600/R600ImageAttributeIntrinsicsReplacer.cpp b/lib/Target/R600/R600ImageAttributeIntrinsicsReplacer.cpp
new file mode 100644
index 0000000..0439011
--- /dev/null
+++ b/lib/Target/R600/R600ImageAttributeIntrinsicsReplacer.cpp
@@ -0,0 +1,194 @@
+//===-- R600ImageAttributeIntrinsicsReplacer.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 replaces image attribute getter pseudointrinsics with the
+/// r600_read_image_attribute intrinsic. The pseudointrinsics are used to
+/// implement OpenCL C get_image_* builtins to avoid using mangled names here.
+///
+/// The r600_read_image_attribute intrinsic identifies the image in question
+/// using an index defined by the following ordering of the image arguments:
+/// write-only images are ordered before read-only ones; images having the
+/// same access qualifier follow the order of the image arguments as defined
+/// by the kernel signature. For each call to an attribute getter the pass
+/// determines the index of the image operand and passes it to the
+/// r600_read_image_attribute intrinsic.
+//===----------------------------------------------------------------------===//
+
+#include "AMDGPU.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallBitVector.h"
+#include "llvm/Analysis/Passes.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/InstVisitor.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Metadata.h"
+
+using namespace llvm;
+
+namespace {
+
+// Names of the attribute getter pseudointrinsics.
+const char * ImageAttributeIntrinsics[] = {
+  "llvm.r600.get.image.width",
+  "llvm.r600.get.image.height",
+  "llvm.r600.get.image.depth",
+  "llvm.r600.get.image.channel.data.type",
+  "llvm.r600.get.image.channel.order"
+  };
+const unsigned NumImageAttributes = sizeof(ImageAttributeIntrinsics) /
+                                    sizeof(const char*);
+
+class R600ImageAttributeIntrinsicsReplacer :
+    public FunctionPass,
+    public InstVisitor<R600ImageAttributeIntrinsicsReplacer> {
+  static char ID;
+
+  struct AccessQualInfo {
+    unsigned NumWriteOnlyArgs;
+    SmallBitVector IsWriteOnly;
+    AccessQualInfo(unsigned NumWriteOnlyArgs_, SmallBitVector IsWriteOnly_):
+        NumWriteOnlyArgs(NumWriteOnlyArgs_), IsWriteOnly(IsWriteOnly_) {}
+  };
+
+  // Per-module state.
+  Type *Int32Type;
+  Function *ReadImageAttributeFun;
+  DenseMap<const Function*, AccessQualInfo> FunctionAccessQualInfo;
+
+  // Per-function state for visitCallInst.
+  bool modified;
+  DenseMap<const Value*, unsigned> ImageArgIndices;
+
+public:
+  R600ImageAttributeIntrinsicsReplacer():
+    FunctionPass(ID) {
+  }
+
+  bool doInitialization(Module &M) override {
+    Int32Type = Type::getInt32Ty(M.getContext());
+
+    // Collect image access qualifier metadata.
+    auto KernelsMD = M.getNamedMetadata("opencl.kernels");
+    if (!KernelsMD) return false;
+    for (const MDNode* Op: KernelsMD->operands()) {
+
+      // Get the access qualifier metadata node.
+      auto KernelFun = mdconst::dyn_extract<Function>(Op->getOperand(0));
+      if (!KernelFun) continue;
+      auto AccessQualMD = cast<MDNode>(Op->getOperand(2));
+      auto MDName = cast<MDString>(AccessQualMD->getOperand(0));
+      assert(MDName && MDName->getString() == "kernel_arg_access_qual");
+
+      // Create a bit vector of write only args and count them.
+      unsigned NumArgs = AccessQualMD->getNumOperands() - 1;
+      SmallBitVector WriteOnlyArgs(NumArgs);
+      unsigned NumWriteOnlyArgs = 0;
+      for (unsigned i = 0; i < NumArgs; ++i) {
+        auto AccessQual = cast<MDString>(AccessQualMD->getOperand(i + 1));
+        bool WriteOnly = AccessQual->getString() == "write_only";
+        if (WriteOnly) NumWriteOnlyArgs++;
+        WriteOnlyArgs[i] = WriteOnly;
+      }
+      auto Info = AccessQualInfo(NumWriteOnlyArgs, WriteOnlyArgs);
+      FunctionAccessQualInfo.insert(std::make_pair(KernelFun, Info));
+    }
+
+    // Create Function for the image attribute reading intrinsic.
+    ReadImageAttributeFun = Intrinsic::getDeclaration(&M,
+        Intrinsic::r600_read_image_attribute);
+
+    return true;
+  }
+
+  bool runOnFunction(Function &F) override {
+
+    // Try to get access qualifier info.
+    auto InfoIt = FunctionAccessQualInfo.find(&F);
+    if (InfoIt == FunctionAccessQualInfo.end()) return false;
+    auto Info = InfoIt->second;
+
+    modified = false;
+
+    // Store indices of image arguments.
+    ImageArgIndices.clear();
+    unsigned NumWriteOnlyArgsSoFar = 0, NumReadOnlyArgsSoFar = 0, i = 0;
+    for (auto arg = F.arg_begin(), E = F.arg_end(); arg != E; ++arg, ++i) {
+
+      // Skip non-image types.
+      Type *arg_type = arg->getType();
+      if (!arg_type->isPointerTy()) continue;
+      Type *elem_type = arg_type->getPointerElementType();
+      if (!elem_type->isStructTy()) continue;
+      const llvm::StringRef &type_name = elem_type->getStructName();
+      if (!type_name.startswith("opencl.image2d_t") &&
+          !type_name.startswith("opencl.image3d_t")) continue;
+
+      // Calculate and save image index.
+      // Offset read only image indices by the number of write only ones.
+      unsigned Index = 0;
+      if (Info.IsWriteOnly[i]) {
+        Index = NumWriteOnlyArgsSoFar++;
+      } else {
+        Index = Info.NumWriteOnlyArgs + NumReadOnlyArgsSoFar++;
+      }
+      ImageArgIndices[arg] = Index;
+    }
+
+    visit(F);
+
+    return modified;
+  }
+
+  void visitCallInst(CallInst &I) {
+    Function* F = I.getCalledFunction();
+    if (!F)
+      return;
+
+    // Find out if this is a call to one of the pseudointrinsics.
+    StringRef Name = I.getCalledFunction()->getName();
+    unsigned Attribute;
+    for (Attribute = 0; Attribute < NumImageAttributes; Attribute++) {
+      if (Name.startswith(ImageAttributeIntrinsics[Attribute])) {
+        break;
+      }
+    }
+    if (Attribute >= NumImageAttributes) {
+      // Not an image attribute getter pseudointrinsic.
+      return;
+    }
+
+    // Get image argument index.
+    auto ImageArg = I.getArgOperand(0);
+    auto ImageArgIt = ImageArgIndices.find(ImageArg);
+    assert(ImageArgIt != ImageArgIndices.end());
+    auto ImageArgIndex = ImageArgIt->second;
+
+    // Replace instuction with call to r600_read_image_attribute intrinsic.
+    IRBuilder<> Builder(&I);
+    Value* Args[] = { ConstantInt::get(Int32Type, ImageArgIndex),
+                      ConstantInt::get(Int32Type, Attribute) };
+    I.replaceAllUsesWith(Builder.CreateCall(ReadImageAttributeFun, Args));
+    I.eraseFromParent();
+    modified = true;
+  }
+
+  const char *getPassName() const override {
+    return "R600 Image Attribute Intrinsics Replacer";
+  }
+};
+
+char R600ImageAttributeIntrinsicsReplacer::ID = 0;
+
+}
+
+FunctionPass *llvm::createR600ImageAttributeIntrinsicsReplacer() {
+  return new R600ImageAttributeIntrinsicsReplacer();
+}
-- 
2.4.2




More information about the llvm-commits mailing list