[llvm] Image attribute access for the R600 backend
Zoltan Gilian
zoltan.gilian at gmail.com
Mon Jun 15 16:05:28 PDT 2015
Added a pass to the R600 backend to replace image attribute getters to
implicit parameter loads.
Added an intrinsics to load an implicit kernel parameter.
---
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