2012-05-04 20:18:50 +00:00
|
|
|
//===- 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"
|
2013-01-02 11:36:10 +00:00
|
|
|
#include "llvm/IR/Constants.h"
|
|
|
|
#include "llvm/IR/Function.h"
|
|
|
|
#include "llvm/IR/GlobalVariable.h"
|
2015-01-14 11:23:27 +00:00
|
|
|
#include "llvm/IR/InstIterator.h"
|
2013-01-02 11:36:10 +00:00
|
|
|
#include "llvm/IR/Module.h"
|
|
|
|
#include "llvm/IR/Operator.h"
|
2015-01-14 11:23:27 +00:00
|
|
|
#include "llvm/Support/ManagedStatic.h"
|
|
|
|
#include "llvm/Support/MutexGuard.h"
|
2012-05-04 20:18:50 +00:00
|
|
|
#include <algorithm>
|
|
|
|
#include <cstring>
|
|
|
|
#include <map>
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
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;
|
2014-04-09 15:38:52 +00:00
|
|
|
static sys::Mutex Lock;
|
|
|
|
|
|
|
|
void llvm::clearAnnotationCache(const llvm::Module *Mod) {
|
|
|
|
MutexGuard Guard(Lock);
|
|
|
|
annotationCache->erase(Mod);
|
|
|
|
}
|
2012-05-04 20:18:50 +00:00
|
|
|
|
|
|
|
static void cacheAnnotationFromMD(const MDNode *md, key_val_pair_t &retval) {
|
2014-04-09 15:38:52 +00:00
|
|
|
MutexGuard Guard(Lock);
|
2012-05-04 20:18:50 +00:00
|
|
|
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
|
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
|
|
|
ConstantInt *Val = mdconst::dyn_extract<ConstantInt>(md->getOperand(i + 1));
|
2012-05-04 20:18:50 +00:00
|
|
|
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) {
|
2014-04-09 15:38:52 +00:00
|
|
|
MutexGuard Guard(Lock);
|
2012-05-04 20:18:50 +00:00
|
|
|
NamedMDNode *NMD = m->getNamedMetadata(llvm::NamedMDForAnnotations);
|
|
|
|
if (!NMD)
|
|
|
|
return;
|
|
|
|
key_val_pair_t tmp;
|
|
|
|
for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) {
|
2014-11-11 21:30:22 +00:00
|
|
|
const MDNode *elem = NMD->getOperand(i);
|
2012-05-04 20:18:50 +00:00
|
|
|
|
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
|
|
|
GlobalValue *entity =
|
|
|
|
mdconst::dyn_extract_or_null<GlobalValue>(elem->getOperand(0));
|
2012-05-04 20:18:50 +00:00
|
|
|
// 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())
|
2014-10-04 16:55:56 +00:00
|
|
|
(*annotationCache)[m][gv] = std::move(tmp);
|
2012-05-04 20:18:50 +00:00
|
|
|
else {
|
|
|
|
global_val_annot_t tmp1;
|
2014-10-04 16:55:56 +00:00
|
|
|
tmp1[gv] = std::move(tmp);
|
|
|
|
(*annotationCache)[m] = std::move(tmp1);
|
2012-05-04 20:18:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool llvm::findOneNVVMAnnotation(const GlobalValue *gv, std::string prop,
|
|
|
|
unsigned &retval) {
|
2014-04-09 15:38:52 +00:00
|
|
|
MutexGuard Guard(Lock);
|
2012-05-04 20:18:50 +00:00
|
|
|
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) {
|
2014-04-09 15:38:52 +00:00
|
|
|
MutexGuard Guard(Lock);
|
2012-05-04 20:18:50 +00:00
|
|
|
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;
|
2013-03-30 14:29:21 +00:00
|
|
|
if (llvm::findOneNVVMAnnotation(
|
|
|
|
gv, llvm::PropertyAnnotationNames[llvm::PROPERTY_ISTEXTURE],
|
|
|
|
annot)) {
|
2012-05-04 20:18:50 +00:00
|
|
|
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;
|
2013-03-30 14:29:21 +00:00
|
|
|
if (llvm::findOneNVVMAnnotation(
|
|
|
|
gv, llvm::PropertyAnnotationNames[llvm::PROPERTY_ISSURFACE],
|
|
|
|
annot)) {
|
2012-05-04 20:18:50 +00:00
|
|
|
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;
|
2013-03-30 14:29:21 +00:00
|
|
|
if (llvm::findOneNVVMAnnotation(
|
|
|
|
gv, llvm::PropertyAnnotationNames[llvm::PROPERTY_ISSAMPLER],
|
|
|
|
annot)) {
|
2012-05-04 20:18:50 +00:00
|
|
|
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;
|
2013-03-30 14:29:21 +00:00
|
|
|
if (llvm::findAllNVVMAnnotation(
|
|
|
|
func, llvm::PropertyAnnotationNames[llvm::PROPERTY_ISSAMPLER],
|
|
|
|
annot)) {
|
2012-05-04 20:18:50 +00:00
|
|
|
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,
|
2013-03-30 14:29:21 +00:00
|
|
|
llvm::PropertyAnnotationNames[
|
|
|
|
llvm::PROPERTY_ISREADONLY_IMAGE_PARAM],
|
|
|
|
annot)) {
|
2012-05-04 20:18:50 +00:00
|
|
|
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,
|
2013-03-30 14:29:21 +00:00
|
|
|
llvm::PropertyAnnotationNames[
|
|
|
|
llvm::PROPERTY_ISWRITEONLY_IMAGE_PARAM],
|
|
|
|
annot)) {
|
2012-05-04 20:18:50 +00:00
|
|
|
if (std::find(annot.begin(), annot.end(), arg->getArgNo()) != annot.end())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-04-09 15:38:52 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-05-04 20:18:50 +00:00
|
|
|
bool llvm::isImage(const llvm::Value &val) {
|
2014-04-09 15:38:52 +00:00
|
|
|
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;
|
2012-05-04 20:18:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2013-03-30 14:29:21 +00:00
|
|
|
return (llvm::findOneNVVMAnnotation(
|
|
|
|
&F, llvm::PropertyAnnotationNames[llvm::PROPERTY_MAXNTID_X], x));
|
2012-05-04 20:18:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool llvm::getMaxNTIDy(const Function &F, unsigned &y) {
|
2013-03-30 14:29:21 +00:00
|
|
|
return (llvm::findOneNVVMAnnotation(
|
|
|
|
&F, llvm::PropertyAnnotationNames[llvm::PROPERTY_MAXNTID_Y], y));
|
2012-05-04 20:18:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool llvm::getMaxNTIDz(const Function &F, unsigned &z) {
|
2013-03-30 14:29:21 +00:00
|
|
|
return (llvm::findOneNVVMAnnotation(
|
|
|
|
&F, llvm::PropertyAnnotationNames[llvm::PROPERTY_MAXNTID_Z], z));
|
2012-05-04 20:18:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool llvm::getReqNTIDx(const Function &F, unsigned &x) {
|
2013-03-30 14:29:21 +00:00
|
|
|
return (llvm::findOneNVVMAnnotation(
|
|
|
|
&F, llvm::PropertyAnnotationNames[llvm::PROPERTY_REQNTID_X], x));
|
2012-05-04 20:18:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool llvm::getReqNTIDy(const Function &F, unsigned &y) {
|
2013-03-30 14:29:21 +00:00
|
|
|
return (llvm::findOneNVVMAnnotation(
|
|
|
|
&F, llvm::PropertyAnnotationNames[llvm::PROPERTY_REQNTID_Y], y));
|
2012-05-04 20:18:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool llvm::getReqNTIDz(const Function &F, unsigned &z) {
|
2013-03-30 14:29:21 +00:00
|
|
|
return (llvm::findOneNVVMAnnotation(
|
|
|
|
&F, llvm::PropertyAnnotationNames[llvm::PROPERTY_REQNTID_Z], z));
|
2012-05-04 20:18:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool llvm::getMinCTASm(const Function &F, unsigned &x) {
|
2013-03-30 14:29:21 +00:00
|
|
|
return (llvm::findOneNVVMAnnotation(
|
|
|
|
&F, llvm::PropertyAnnotationNames[llvm::PROPERTY_MINNCTAPERSM], x));
|
2012-05-04 20:18:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool llvm::isKernelFunction(const Function &F) {
|
|
|
|
unsigned x = 0;
|
2013-03-30 14:29:21 +00:00
|
|
|
bool retval = llvm::findOneNVVMAnnotation(
|
|
|
|
&F, llvm::PropertyAnnotationNames[llvm::PROPERTY_ISKERNEL_FUNCTION], x);
|
2012-05-04 20:18:50 +00:00
|
|
|
if (retval == false) {
|
|
|
|
// There is no NVVM metadata, check the calling convention
|
|
|
|
if (F.getCallingConv() == llvm::CallingConv::PTX_Kernel)
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
2013-03-30 14:29:21 +00:00
|
|
|
return (x == 1);
|
2012-05-04 20:18:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool llvm::getAlign(const Function &F, unsigned index, unsigned &align) {
|
|
|
|
std::vector<unsigned> Vs;
|
2013-03-30 14:29:21 +00:00
|
|
|
bool retval = llvm::findAllNVVMAnnotation(
|
|
|
|
&F, llvm::PropertyAnnotationNames[llvm::PROPERTY_ALIGN], Vs);
|
2012-05-04 20:18:50 +00:00
|
|
|
if (retval == false)
|
|
|
|
return false;
|
2013-03-30 14:29:21 +00:00
|
|
|
for (int i = 0, e = Vs.size(); i < e; i++) {
|
2012-05-04 20:18:50 +00:00
|
|
|
unsigned v = Vs[i];
|
2013-03-30 14:29:21 +00:00
|
|
|
if ((v >> 16) == index) {
|
|
|
|
align = v & 0xFFFF;
|
2012-05-04 20:18:50 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool llvm::getAlign(const CallInst &I, unsigned index, unsigned &align) {
|
2014-11-11 21:30:22 +00:00
|
|
|
if (MDNode *alignNode = I.getMetadata("callalign")) {
|
2013-03-30 14:29:21 +00:00
|
|
|
for (int i = 0, n = alignNode->getNumOperands(); i < n; i++) {
|
2012-05-04 20:18:50 +00:00
|
|
|
if (const ConstantInt *CI =
|
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
|
|
|
mdconst::dyn_extract<ConstantInt>(alignNode->getOperand(i))) {
|
2012-05-04 20:18:50 +00:00
|
|
|
unsigned v = CI->getZExtValue();
|
2013-03-30 14:29:21 +00:00
|
|
|
if ((v >> 16) == index) {
|
2012-05-04 20:18:50 +00:00
|
|
|
align = v & 0xFFFF;
|
|
|
|
return true;
|
|
|
|
}
|
2013-03-30 14:29:21 +00:00
|
|
|
if ((v >> 16) > index) {
|
2012-05-04 20:18:50 +00:00
|
|
|
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.
|
2013-03-30 14:29:21 +00:00
|
|
|
const Value *
|
|
|
|
llvm::skipPointerTransfer(const Value *V, bool ignore_GEP_indices) {
|
2012-05-04 20:18:50 +00:00
|
|
|
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.
|
2013-03-30 14:29:21 +00:00
|
|
|
const Value *
|
|
|
|
llvm::skipPointerTransfer(const Value *V, std::set<const Value *> &processed) {
|
2012-05-04 20:18:50 +00:00
|
|
|
if (processed.find(V) != processed.end())
|
2014-04-25 05:30:21 +00:00
|
|
|
return nullptr;
|
2012-05-04 20:18:50 +00:00
|
|
|
processed.insert(V);
|
|
|
|
|
|
|
|
const Value *V2 = V->stripPointerCasts();
|
|
|
|
if (V2 != V && processed.find(V2) != processed.end())
|
2014-04-25 05:30:21 +00:00
|
|
|
return nullptr;
|
2012-05-04 20:18:50 +00:00
|
|
|
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())
|
2014-04-25 05:30:21 +00:00
|
|
|
return nullptr;
|
2012-05-04 20:18:50 +00:00
|
|
|
processed.insert(PN);
|
2014-04-25 05:30:21 +00:00
|
|
|
const Value *common = nullptr;
|
2012-05-04 20:18:50 +00:00
|
|
|
for (unsigned i = 0; i != PN->getNumIncomingValues(); ++i) {
|
|
|
|
const Value *pv = PN->getIncomingValue(i);
|
|
|
|
const Value *base = skipPointerTransfer(pv, processed);
|
|
|
|
if (base) {
|
2014-04-25 05:30:21 +00:00
|
|
|
if (!common)
|
2012-05-04 20:18:50 +00:00
|
|
|
common = base;
|
|
|
|
else if (common != base)
|
|
|
|
return PN;
|
|
|
|
}
|
|
|
|
}
|
2014-04-25 05:30:21 +00:00
|
|
|
if (!common)
|
2012-05-04 20:18:50 +00:00
|
|
|
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();
|
|
|
|
|
2014-04-25 05:30:21 +00:00
|
|
|
return nullptr;
|
2012-05-04 20:18:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
2014-04-25 05:30:21 +00:00
|
|
|
return nullptr;
|
2012-05-04 20:18:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Dump a block by name
|
|
|
|
void llvm::dumpBlock(Value *v, char *blockName) {
|
|
|
|
Function *F = getParentFunction(v);
|
2014-04-25 05:30:21 +00:00
|
|
|
if (!F)
|
2012-05-04 20:18:50 +00:00
|
|
|
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);
|
2014-04-25 05:30:21 +00:00
|
|
|
if (!F)
|
|
|
|
return nullptr;
|
2012-05-04 20:18:50 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-25 05:30:21 +00:00
|
|
|
return nullptr;
|
2012-05-04 20:18:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|