llvm-6502/lib/Target/NVPTX/NVPTXUtilities.cpp
Duncan P. N. Exon Smith dad20b2ae2 IR: Split Metadata from Value
Split `Metadata` away from the `Value` class hierarchy, as part of
PR21532.  Assembly and bitcode changes are in the wings, but this is the
bulk of the change for the IR C++ API.

I have a follow-up patch prepared for `clang`.  If this breaks other
sub-projects, I apologize in advance :(.  Help me compile it on Darwin
I'll try to fix it.  FWIW, the errors should be easy to fix, so it may
be simpler to just fix it yourself.

This breaks the build for all metadata-related code that's out-of-tree.
Rest assured the transition is mechanical and the compiler should catch
almost all of the problems.

Here's a quick guide for updating your code:

  - `Metadata` is the root of a class hierarchy with three main classes:
    `MDNode`, `MDString`, and `ValueAsMetadata`.  It is distinct from
    the `Value` class hierarchy.  It is typeless -- i.e., instances do
    *not* have a `Type`.

  - `MDNode`'s operands are all `Metadata *` (instead of `Value *`).

  - `TrackingVH<MDNode>` and `WeakVH` referring to metadata can be
    replaced with `TrackingMDNodeRef` and `TrackingMDRef`, respectively.

    If you're referring solely to resolved `MDNode`s -- post graph
    construction -- just use `MDNode*`.

  - `MDNode` (and the rest of `Metadata`) have only limited support for
    `replaceAllUsesWith()`.

    As long as an `MDNode` is pointing at a forward declaration -- the
    result of `MDNode::getTemporary()` -- it maintains a side map of its
    uses and can RAUW itself.  Once the forward declarations are fully
    resolved RAUW support is dropped on the ground.  This means that
    uniquing collisions on changing operands cause nodes to become
    "distinct".  (This already happened fairly commonly, whenever an
    operand went to null.)

    If you're constructing complex (non self-reference) `MDNode` cycles,
    you need to call `MDNode::resolveCycles()` on each node (or on a
    top-level node that somehow references all of the nodes).  Also,
    don't do that.  Metadata cycles (and the RAUW machinery needed to
    construct them) are expensive.

  - An `MDNode` can only refer to a `Constant` through a bridge called
    `ConstantAsMetadata` (one of the subclasses of `ValueAsMetadata`).

    As a side effect, accessing an operand of an `MDNode` that is known
    to be, e.g., `ConstantInt`, takes three steps: first, cast from
    `Metadata` to `ConstantAsMetadata`; second, extract the `Constant`;
    third, cast down to `ConstantInt`.

    The eventual goal is to introduce `MDInt`/`MDFloat`/etc. and have
    metadata schema owners transition away from using `Constant`s when
    the type isn't important (and they don't care about referring to
    `GlobalValue`s).

    In the meantime, I've added transitional API to the `mdconst`
    namespace that matches semantics with the old code, in order to
    avoid adding the error-prone three-step equivalent to every call
    site.  If your old code was:

        MDNode *N = foo();
        bar(isa             <ConstantInt>(N->getOperand(0)));
        baz(cast            <ConstantInt>(N->getOperand(1)));
        bak(cast_or_null    <ConstantInt>(N->getOperand(2)));
        bat(dyn_cast        <ConstantInt>(N->getOperand(3)));
        bay(dyn_cast_or_null<ConstantInt>(N->getOperand(4)));

    you can trivially match its semantics with:

        MDNode *N = foo();
        bar(mdconst::hasa               <ConstantInt>(N->getOperand(0)));
        baz(mdconst::extract            <ConstantInt>(N->getOperand(1)));
        bak(mdconst::extract_or_null    <ConstantInt>(N->getOperand(2)));
        bat(mdconst::dyn_extract        <ConstantInt>(N->getOperand(3)));
        bay(mdconst::dyn_extract_or_null<ConstantInt>(N->getOperand(4)));

    and when you transition your metadata schema to `MDInt`:

        MDNode *N = foo();
        bar(isa             <MDInt>(N->getOperand(0)));
        baz(cast            <MDInt>(N->getOperand(1)));
        bak(cast_or_null    <MDInt>(N->getOperand(2)));
        bat(dyn_cast        <MDInt>(N->getOperand(3)));
        bay(dyn_cast_or_null<MDInt>(N->getOperand(4)));

  - A `CallInst` -- specifically, intrinsic instructions -- can refer to
    metadata through a bridge called `MetadataAsValue`.  This is a
    subclass of `Value` where `getType()->isMetadataTy()`.

    `MetadataAsValue` is the *only* class that can legally refer to a
    `LocalAsMetadata`, which is a bridged form of non-`Constant` values
    like `Argument` and `Instruction`.  It can also refer to any other
    `Metadata` subclass.

(I'll break all your testcases in a follow-up commit, when I propagate
this change to assembly.)

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@223802 91177308-0d34-0410-b5e6-96231b3b80d8
2014-12-09 18:38:53 +00:00

545 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 = 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(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);
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 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 =
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;
}
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;
}
}