mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-24 09:29:42 +00:00
into their new header subdirectory: include/llvm/IR. This matches the directory structure of lib, and begins to correct a long standing point of file layout clutter in LLVM. There are still more header files to move here, but I wanted to handle them in separate commits to make tracking what files make sense at each layer easier. The only really questionable files here are the target intrinsic tablegen files. But that's a battle I'd rather not fight today. I've updated both CMake and Makefile build systems (I think, and my tests think, but I may have missed something). I've also re-sorted the includes throughout the project. I'll be committing updates to Clang, DragonEgg, and Polly momentarily. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@171366 91177308-0d34-0410-b5e6-96231b3b80d8
515 lines
16 KiB
C++
515 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 <iostream>
|
|
#include "llvm/Support/ManagedStatic.h"
|
|
#include "llvm/Support/InstIterator.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 void cacheAnnotationFromMD(const MDNode *md, key_val_pair_t &retval) {
|
|
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) {
|
|
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] = tmp;
|
|
else {
|
|
global_val_annot_t tmp1;
|
|
tmp1[gv] = tmp;
|
|
(*annotationCache)[m] = tmp1;
|
|
}
|
|
}
|
|
|
|
bool llvm::findOneNVVMAnnotation(const GlobalValue *gv, std::string prop,
|
|
unsigned &retval) {
|
|
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) {
|
|
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::isImage(const llvm::Value &val) {
|
|
return llvm::isImageReadOnly(val) || llvm::isImageWriteOnly(val);
|
|
}
|
|
|
|
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 NULL;
|
|
processed.insert(V);
|
|
|
|
const Value *V2 = V->stripPointerCasts();
|
|
if (V2 != V && processed.find(V2) != processed.end())
|
|
return NULL;
|
|
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 NULL;
|
|
processed.insert(PN);
|
|
const Value *common = 0;
|
|
for (unsigned i = 0; i != PN->getNumIncomingValues(); ++i) {
|
|
const Value *pv = PN->getIncomingValue(i);
|
|
const Value *base = skipPointerTransfer(pv, processed);
|
|
if (base) {
|
|
if (common == 0)
|
|
common = base;
|
|
else if (common != base)
|
|
return PN;
|
|
}
|
|
}
|
|
if (common == 0)
|
|
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 0;
|
|
}
|
|
|
|
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 0;
|
|
}
|
|
|
|
// Dump a block by name
|
|
void llvm::dumpBlock(Value *v, char *blockName) {
|
|
Function *F = getParentFunction(v);
|
|
if (F == 0)
|
|
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 == 0)
|
|
return 0;
|
|
|
|
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 0;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
}
|