1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-21 20:12:56 +02:00
llvm-mirror/lib/Target/NVPTX/NVPTXUtilities.cpp
Chandler Carruth ae65e281f3 Update the file headers across all of the LLVM projects in the monorepo
to reflect the new license.

We understand that people may be surprised that we're moving the header
entirely to discuss the new license. We checked this carefully with the
Foundation's lawyer and we believe this is the correct approach.

Essentially, all code in the project is now made available by the LLVM
project under our new license, so you will see that the license headers
include that license only. Some of our contributors have contributed
code under our old license, and accordingly, we have retained a copy of
our old license notice in the top-level files in each project and
repository.

llvm-svn: 351636
2019-01-19 08:50:56 +00:00

317 lines
9.2 KiB
C++

//===- NVPTXUtilities.cpp - Utility Functions -----------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// 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/InstIterator.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Operator.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MutexGuard.h"
#include <algorithm>
#include <cstring>
#include <map>
#include <string>
#include <vector>
namespace llvm {
namespace {
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;
} // anonymous namespace
static ManagedStatic<per_module_annot_t> annotationCache;
static sys::Mutex Lock;
void clearAnnotationCache(const 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 = mdconst::dyn_extract<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("nvvm.annotations");
if (!NMD)
return;
key_val_pair_t tmp;
for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) {
const MDNode *elem = NMD->getOperand(i);
GlobalValue *entity =
mdconst::dyn_extract_or_null<GlobalValue>(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 findOneNVVMAnnotation(const GlobalValue *gv, const 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 findAllNVVMAnnotation(const GlobalValue *gv, const 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 isTexture(const Value &val) {
if (const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) {
unsigned annot;
if (findOneNVVMAnnotation(gv, "texture", annot)) {
assert((annot == 1) && "Unexpected annotation on a texture symbol");
return true;
}
}
return false;
}
bool isSurface(const Value &val) {
if (const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) {
unsigned annot;
if (findOneNVVMAnnotation(gv, "surface", annot)) {
assert((annot == 1) && "Unexpected annotation on a surface symbol");
return true;
}
}
return false;
}
bool isSampler(const Value &val) {
const char *AnnotationName = "sampler";
if (const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) {
unsigned annot;
if (findOneNVVMAnnotation(gv, AnnotationName, 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 (findAllNVVMAnnotation(func, AnnotationName, annot)) {
if (is_contained(annot, arg->getArgNo()))
return true;
}
}
return false;
}
bool isImageReadOnly(const Value &val) {
if (const Argument *arg = dyn_cast<Argument>(&val)) {
const Function *func = arg->getParent();
std::vector<unsigned> annot;
if (findAllNVVMAnnotation(func, "rdoimage", annot)) {
if (is_contained(annot, arg->getArgNo()))
return true;
}
}
return false;
}
bool isImageWriteOnly(const Value &val) {
if (const Argument *arg = dyn_cast<Argument>(&val)) {
const Function *func = arg->getParent();
std::vector<unsigned> annot;
if (findAllNVVMAnnotation(func, "wroimage", annot)) {
if (is_contained(annot, arg->getArgNo()))
return true;
}
}
return false;
}
bool isImageReadWrite(const Value &val) {
if (const Argument *arg = dyn_cast<Argument>(&val)) {
const Function *func = arg->getParent();
std::vector<unsigned> annot;
if (findAllNVVMAnnotation(func, "rdwrimage", annot)) {
if (is_contained(annot, arg->getArgNo()))
return true;
}
}
return false;
}
bool isImage(const Value &val) {
return isImageReadOnly(val) || isImageWriteOnly(val) || isImageReadWrite(val);
}
bool isManaged(const Value &val) {
if(const GlobalValue *gv = dyn_cast<GlobalValue>(&val)) {
unsigned annot;
if (findOneNVVMAnnotation(gv, "managed", annot)) {
assert((annot == 1) && "Unexpected annotation on a managed symbol");
return true;
}
}
return false;
}
std::string getTextureName(const Value &val) {
assert(val.hasName() && "Found texture variable with no name");
return val.getName();
}
std::string getSurfaceName(const Value &val) {
assert(val.hasName() && "Found surface variable with no name");
return val.getName();
}
std::string getSamplerName(const Value &val) {
assert(val.hasName() && "Found sampler variable with no name");
return val.getName();
}
bool getMaxNTIDx(const Function &F, unsigned &x) {
return findOneNVVMAnnotation(&F, "maxntidx", x);
}
bool getMaxNTIDy(const Function &F, unsigned &y) {
return findOneNVVMAnnotation(&F, "maxntidy", y);
}
bool getMaxNTIDz(const Function &F, unsigned &z) {
return findOneNVVMAnnotation(&F, "maxntidz", z);
}
bool getReqNTIDx(const Function &F, unsigned &x) {
return findOneNVVMAnnotation(&F, "reqntidx", x);
}
bool getReqNTIDy(const Function &F, unsigned &y) {
return findOneNVVMAnnotation(&F, "reqntidy", y);
}
bool getReqNTIDz(const Function &F, unsigned &z) {
return findOneNVVMAnnotation(&F, "reqntidz", z);
}
bool getMinCTASm(const Function &F, unsigned &x) {
return findOneNVVMAnnotation(&F, "minctasm", x);
}
bool getMaxNReg(const Function &F, unsigned &x) {
return findOneNVVMAnnotation(&F, "maxnreg", x);
}
bool isKernelFunction(const Function &F) {
unsigned x = 0;
bool retval = findOneNVVMAnnotation(&F, "kernel", x);
if (!retval) {
// There is no NVVM metadata, check the calling convention
return F.getCallingConv() == CallingConv::PTX_Kernel;
}
return (x == 1);
}
bool getAlign(const Function &F, unsigned index, unsigned &align) {
std::vector<unsigned> Vs;
bool retval = findAllNVVMAnnotation(&F, "align", Vs);
if (!retval)
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 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 =
mdconst::dyn_extract<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;
}
} // namespace llvm