1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-22 12:33:33 +02:00
llvm-mirror/lib/Target/NVPTX/NVPTXUtilities.cpp
Duncan P. N. Exon Smith 8770505e4e Revert "IR: MDNode => Value"
Instead, we're going to separate metadata from the Value hierarchy.  See
PR21532.

This reverts commit r221375.
This reverts commit r221373.
This reverts commit r221359.
This reverts commit r221167.
This reverts commit r221027.
This reverts commit r221024.
This reverts commit r221023.
This reverts commit r220995.
This reverts commit r220994.

llvm-svn: 221711
2014-11-11 21:30:22 +00:00

544 lines
16 KiB
C++

//===- NVPTXUtilities.cpp - Utility Functions -----------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains miscellaneous utility functions
//===----------------------------------------------------------------------===//
#include "NVPTXUtilities.h"
#include "NVPTX.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Operator.h"
#include <algorithm>
#include <cstring>
#include <map>
#include <string>
#include <vector>
#include "llvm/Support/ManagedStatic.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/Support/MutexGuard.h"
using namespace llvm;
typedef std::map<std::string, std::vector<unsigned> > key_val_pair_t;
typedef std::map<const GlobalValue *, key_val_pair_t> global_val_annot_t;
typedef std::map<const Module *, global_val_annot_t> per_module_annot_t;
ManagedStatic<per_module_annot_t> annotationCache;
static sys::Mutex Lock;
void llvm::clearAnnotationCache(const llvm::Module *Mod) {
MutexGuard Guard(Lock);
annotationCache->erase(Mod);
}
static void cacheAnnotationFromMD(const MDNode *md, key_val_pair_t &retval) {
MutexGuard Guard(Lock);
assert(md && "Invalid mdnode for annotation");
assert((md->getNumOperands() % 2) == 1 && "Invalid number of operands");
// start index = 1, to skip the global variable key
// increment = 2, to skip the value for each property-value pairs
for (unsigned i = 1, e = md->getNumOperands(); i != e; i += 2) {
// property
const MDString *prop = dyn_cast<MDString>(md->getOperand(i));
assert(prop && "Annotation property not a string");
// value
ConstantInt *Val = dyn_cast<ConstantInt>(md->getOperand(i + 1));
assert(Val && "Value operand not a constant int");
std::string keyname = prop->getString().str();
if (retval.find(keyname) != retval.end())
retval[keyname].push_back(Val->getZExtValue());
else {
std::vector<unsigned> tmp;
tmp.push_back(Val->getZExtValue());
retval[keyname] = tmp;
}
}
}
static void cacheAnnotationFromMD(const Module *m, const GlobalValue *gv) {
MutexGuard Guard(Lock);
NamedMDNode *NMD = m->getNamedMetadata(llvm::NamedMDForAnnotations);
if (!NMD)
return;
key_val_pair_t tmp;
for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) {
const MDNode *elem = NMD->getOperand(i);
Value *entity = elem->getOperand(0);
// entity may be null due to DCE
if (!entity)
continue;
if (entity != gv)
continue;
// accumulate annotations for entity in tmp
cacheAnnotationFromMD(elem, tmp);
}
if (tmp.empty()) // no annotations for this gv
return;
if ((*annotationCache).find(m) != (*annotationCache).end())
(*annotationCache)[m][gv] = std::move(tmp);
else {
global_val_annot_t tmp1;
tmp1[gv] = std::move(tmp);
(*annotationCache)[m] = std::move(tmp1);
}
}
bool llvm::findOneNVVMAnnotation(const GlobalValue *gv, std::string prop,
unsigned &retval) {
MutexGuard Guard(Lock);
const Module *m = gv->getParent();
if ((*annotationCache).find(m) == (*annotationCache).end())
cacheAnnotationFromMD(m, gv);
else if ((*annotationCache)[m].find(gv) == (*annotationCache)[m].end())
cacheAnnotationFromMD(m, gv);
if ((*annotationCache)[m][gv].find(prop) == (*annotationCache)[m][gv].end())
return false;
retval = (*annotationCache)[m][gv][prop][0];
return true;
}
bool llvm::findAllNVVMAnnotation(const GlobalValue *gv, std::string prop,
std::vector<unsigned> &retval) {
MutexGuard Guard(Lock);
const Module *m = gv->getParent();
if ((*annotationCache).find(m) == (*annotationCache).end())
cacheAnnotationFromMD(m, gv);
else if ((*annotationCache)[m].find(gv) == (*annotationCache)[m].end())
cacheAnnotationFromMD(m, gv);
if ((*annotationCache)[m][gv].find(prop) == (*annotationCache)[m][gv].end())
return false;
retval = (*annotationCache)[m][gv][prop];
return true;
}
bool llvm::isTexture(const llvm::Value &val) {
if (const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) {
unsigned annot;
if (llvm::findOneNVVMAnnotation(
gv, llvm::PropertyAnnotationNames[llvm::PROPERTY_ISTEXTURE],
annot)) {
assert((annot == 1) && "Unexpected annotation on a texture symbol");
return true;
}
}
return false;
}
bool llvm::isSurface(const llvm::Value &val) {
if (const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) {
unsigned annot;
if (llvm::findOneNVVMAnnotation(
gv, llvm::PropertyAnnotationNames[llvm::PROPERTY_ISSURFACE],
annot)) {
assert((annot == 1) && "Unexpected annotation on a surface symbol");
return true;
}
}
return false;
}
bool llvm::isSampler(const llvm::Value &val) {
if (const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) {
unsigned annot;
if (llvm::findOneNVVMAnnotation(
gv, llvm::PropertyAnnotationNames[llvm::PROPERTY_ISSAMPLER],
annot)) {
assert((annot == 1) && "Unexpected annotation on a sampler symbol");
return true;
}
}
if (const Argument *arg = dyn_cast<Argument>(&val)) {
const Function *func = arg->getParent();
std::vector<unsigned> annot;
if (llvm::findAllNVVMAnnotation(
func, llvm::PropertyAnnotationNames[llvm::PROPERTY_ISSAMPLER],
annot)) {
if (std::find(annot.begin(), annot.end(), arg->getArgNo()) != annot.end())
return true;
}
}
return false;
}
bool llvm::isImageReadOnly(const llvm::Value &val) {
if (const Argument *arg = dyn_cast<Argument>(&val)) {
const Function *func = arg->getParent();
std::vector<unsigned> annot;
if (llvm::findAllNVVMAnnotation(func,
llvm::PropertyAnnotationNames[
llvm::PROPERTY_ISREADONLY_IMAGE_PARAM],
annot)) {
if (std::find(annot.begin(), annot.end(), arg->getArgNo()) != annot.end())
return true;
}
}
return false;
}
bool llvm::isImageWriteOnly(const llvm::Value &val) {
if (const Argument *arg = dyn_cast<Argument>(&val)) {
const Function *func = arg->getParent();
std::vector<unsigned> annot;
if (llvm::findAllNVVMAnnotation(func,
llvm::PropertyAnnotationNames[
llvm::PROPERTY_ISWRITEONLY_IMAGE_PARAM],
annot)) {
if (std::find(annot.begin(), annot.end(), arg->getArgNo()) != annot.end())
return true;
}
}
return false;
}
bool llvm::isImageReadWrite(const llvm::Value &val) {
if (const Argument *arg = dyn_cast<Argument>(&val)) {
const Function *func = arg->getParent();
std::vector<unsigned> annot;
if (llvm::findAllNVVMAnnotation(func,
llvm::PropertyAnnotationNames[
llvm::PROPERTY_ISREADWRITE_IMAGE_PARAM],
annot)) {
if (std::find(annot.begin(), annot.end(), arg->getArgNo()) != annot.end())
return true;
}
}
return false;
}
bool llvm::isImage(const llvm::Value &val) {
return llvm::isImageReadOnly(val) || llvm::isImageWriteOnly(val) ||
llvm::isImageReadWrite(val);
}
bool llvm::isManaged(const llvm::Value &val) {
if(const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) {
unsigned annot;
if(llvm::findOneNVVMAnnotation(gv,
llvm::PropertyAnnotationNames[llvm::PROPERTY_MANAGED],
annot)) {
assert((annot == 1) && "Unexpected annotation on a managed symbol");
return true;
}
}
return false;
}
std::string llvm::getTextureName(const llvm::Value &val) {
assert(val.hasName() && "Found texture variable with no name");
return val.getName();
}
std::string llvm::getSurfaceName(const llvm::Value &val) {
assert(val.hasName() && "Found surface variable with no name");
return val.getName();
}
std::string llvm::getSamplerName(const llvm::Value &val) {
assert(val.hasName() && "Found sampler variable with no name");
return val.getName();
}
bool llvm::getMaxNTIDx(const Function &F, unsigned &x) {
return (llvm::findOneNVVMAnnotation(
&F, llvm::PropertyAnnotationNames[llvm::PROPERTY_MAXNTID_X], x));
}
bool llvm::getMaxNTIDy(const Function &F, unsigned &y) {
return (llvm::findOneNVVMAnnotation(
&F, llvm::PropertyAnnotationNames[llvm::PROPERTY_MAXNTID_Y], y));
}
bool llvm::getMaxNTIDz(const Function &F, unsigned &z) {
return (llvm::findOneNVVMAnnotation(
&F, llvm::PropertyAnnotationNames[llvm::PROPERTY_MAXNTID_Z], z));
}
bool llvm::getReqNTIDx(const Function &F, unsigned &x) {
return (llvm::findOneNVVMAnnotation(
&F, llvm::PropertyAnnotationNames[llvm::PROPERTY_REQNTID_X], x));
}
bool llvm::getReqNTIDy(const Function &F, unsigned &y) {
return (llvm::findOneNVVMAnnotation(
&F, llvm::PropertyAnnotationNames[llvm::PROPERTY_REQNTID_Y], y));
}
bool llvm::getReqNTIDz(const Function &F, unsigned &z) {
return (llvm::findOneNVVMAnnotation(
&F, llvm::PropertyAnnotationNames[llvm::PROPERTY_REQNTID_Z], z));
}
bool llvm::getMinCTASm(const Function &F, unsigned &x) {
return (llvm::findOneNVVMAnnotation(
&F, llvm::PropertyAnnotationNames[llvm::PROPERTY_MINNCTAPERSM], x));
}
bool llvm::isKernelFunction(const Function &F) {
unsigned x = 0;
bool retval = llvm::findOneNVVMAnnotation(
&F, llvm::PropertyAnnotationNames[llvm::PROPERTY_ISKERNEL_FUNCTION], x);
if (retval == false) {
// There is no NVVM metadata, check the calling convention
if (F.getCallingConv() == llvm::CallingConv::PTX_Kernel)
return true;
else
return false;
}
return (x == 1);
}
bool llvm::getAlign(const Function &F, unsigned index, unsigned &align) {
std::vector<unsigned> Vs;
bool retval = llvm::findAllNVVMAnnotation(
&F, llvm::PropertyAnnotationNames[llvm::PROPERTY_ALIGN], Vs);
if (retval == false)
return false;
for (int i = 0, e = Vs.size(); i < e; i++) {
unsigned v = Vs[i];
if ((v >> 16) == index) {
align = v & 0xFFFF;
return true;
}
}
return false;
}
bool llvm::getAlign(const CallInst &I, unsigned index, unsigned &align) {
if (MDNode *alignNode = I.getMetadata("callalign")) {
for (int i = 0, n = alignNode->getNumOperands(); i < n; i++) {
if (const ConstantInt *CI =
dyn_cast<ConstantInt>(alignNode->getOperand(i))) {
unsigned v = CI->getZExtValue();
if ((v >> 16) == index) {
align = v & 0xFFFF;
return true;
}
if ((v >> 16) > index) {
return false;
}
}
}
}
return false;
}
bool llvm::isBarrierIntrinsic(Intrinsic::ID id) {
if ((id == Intrinsic::nvvm_barrier0) ||
(id == Intrinsic::nvvm_barrier0_popc) ||
(id == Intrinsic::nvvm_barrier0_and) ||
(id == Intrinsic::nvvm_barrier0_or) ||
(id == Intrinsic::cuda_syncthreads))
return true;
return false;
}
// Interface for checking all memory space transfer related intrinsics
bool llvm::isMemorySpaceTransferIntrinsic(Intrinsic::ID id) {
if (id == Intrinsic::nvvm_ptr_local_to_gen ||
id == Intrinsic::nvvm_ptr_shared_to_gen ||
id == Intrinsic::nvvm_ptr_global_to_gen ||
id == Intrinsic::nvvm_ptr_constant_to_gen ||
id == Intrinsic::nvvm_ptr_gen_to_global ||
id == Intrinsic::nvvm_ptr_gen_to_shared ||
id == Intrinsic::nvvm_ptr_gen_to_local ||
id == Intrinsic::nvvm_ptr_gen_to_constant ||
id == Intrinsic::nvvm_ptr_gen_to_param) {
return true;
}
return false;
}
// consider several special intrinsics in striping pointer casts, and
// provide an option to ignore GEP indicies for find out the base address only
// which could be used in simple alias disambigurate.
const Value *
llvm::skipPointerTransfer(const Value *V, bool ignore_GEP_indices) {
V = V->stripPointerCasts();
while (true) {
if (const IntrinsicInst *IS = dyn_cast<IntrinsicInst>(V)) {
if (isMemorySpaceTransferIntrinsic(IS->getIntrinsicID())) {
V = IS->getArgOperand(0)->stripPointerCasts();
continue;
}
} else if (ignore_GEP_indices)
if (const GEPOperator *GEP = dyn_cast<GEPOperator>(V)) {
V = GEP->getPointerOperand()->stripPointerCasts();
continue;
}
break;
}
return V;
}
// consider several special intrinsics in striping pointer casts, and
// - ignore GEP indicies for find out the base address only, and
// - tracking PHINode
// which could be used in simple alias disambigurate.
const Value *
llvm::skipPointerTransfer(const Value *V, std::set<const Value *> &processed) {
if (processed.find(V) != processed.end())
return nullptr;
processed.insert(V);
const Value *V2 = V->stripPointerCasts();
if (V2 != V && processed.find(V2) != processed.end())
return nullptr;
processed.insert(V2);
V = V2;
while (true) {
if (const IntrinsicInst *IS = dyn_cast<IntrinsicInst>(V)) {
if (isMemorySpaceTransferIntrinsic(IS->getIntrinsicID())) {
V = IS->getArgOperand(0)->stripPointerCasts();
continue;
}
} else if (const GEPOperator *GEP = dyn_cast<GEPOperator>(V)) {
V = GEP->getPointerOperand()->stripPointerCasts();
continue;
} else if (const PHINode *PN = dyn_cast<PHINode>(V)) {
if (V != V2 && processed.find(V) != processed.end())
return nullptr;
processed.insert(PN);
const Value *common = nullptr;
for (unsigned i = 0; i != PN->getNumIncomingValues(); ++i) {
const Value *pv = PN->getIncomingValue(i);
const Value *base = skipPointerTransfer(pv, processed);
if (base) {
if (!common)
common = base;
else if (common != base)
return PN;
}
}
if (!common)
return PN;
V = common;
}
break;
}
return V;
}
// The following are some useful utilities for debuggung
BasicBlock *llvm::getParentBlock(Value *v) {
if (BasicBlock *B = dyn_cast<BasicBlock>(v))
return B;
if (Instruction *I = dyn_cast<Instruction>(v))
return I->getParent();
return nullptr;
}
Function *llvm::getParentFunction(Value *v) {
if (Function *F = dyn_cast<Function>(v))
return F;
if (Instruction *I = dyn_cast<Instruction>(v))
return I->getParent()->getParent();
if (BasicBlock *B = dyn_cast<BasicBlock>(v))
return B->getParent();
return nullptr;
}
// Dump a block by name
void llvm::dumpBlock(Value *v, char *blockName) {
Function *F = getParentFunction(v);
if (!F)
return;
for (Function::iterator it = F->begin(), ie = F->end(); it != ie; ++it) {
BasicBlock *B = it;
if (strcmp(B->getName().data(), blockName) == 0) {
B->dump();
return;
}
}
}
// Find an instruction by name
Instruction *llvm::getInst(Value *base, char *instName) {
Function *F = getParentFunction(base);
if (!F)
return nullptr;
for (inst_iterator it = inst_begin(F), ie = inst_end(F); it != ie; ++it) {
Instruction *I = &*it;
if (strcmp(I->getName().data(), instName) == 0) {
return I;
}
}
return nullptr;
}
// Dump an instruction by nane
void llvm::dumpInst(Value *base, char *instName) {
Instruction *I = getInst(base, instName);
if (I)
I->dump();
}
// Dump an instruction and all dependent instructions
void llvm::dumpInstRec(Value *v, std::set<Instruction *> *visited) {
if (Instruction *I = dyn_cast<Instruction>(v)) {
if (visited->find(I) != visited->end())
return;
visited->insert(I);
for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i)
dumpInstRec(I->getOperand(i), visited);
I->dump();
}
}
// Dump an instruction and all dependent instructions
void llvm::dumpInstRec(Value *v) {
std::set<Instruction *> visited;
//BasicBlock *B = getParentBlock(v);
dumpInstRec(v, &visited);
}
// Dump the parent for Instruction, block or function
void llvm::dumpParent(Value *v) {
if (Instruction *I = dyn_cast<Instruction>(v)) {
I->getParent()->dump();
return;
}
if (BasicBlock *B = dyn_cast<BasicBlock>(v)) {
B->getParent()->dump();
return;
}
if (Function *F = dyn_cast<Function>(v)) {
F->getParent()->dump();
return;
}
}