2017-06-20 06:05:08 +08:00
|
|
|
//===- LLVMContextImpl.cpp - Implement LLVMContextImpl --------------------===//
|
2010-03-22 05:17:34 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// 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
|
2010-03-22 05:17:34 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements the opaque LLVMContextImpl.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "LLVMContextImpl.h"
|
2020-01-21 22:54:48 +08:00
|
|
|
#include "llvm/ADT/SetVector.h"
|
2013-01-02 19:36:10 +08:00
|
|
|
#include "llvm/IR/Module.h"
|
2016-04-23 06:06:11 +08:00
|
|
|
#include "llvm/IR/OptBisect.h"
|
2017-06-20 06:05:08 +08:00
|
|
|
#include "llvm/IR/Type.h"
|
2021-06-24 23:21:24 +08:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
2016-04-23 06:06:11 +08:00
|
|
|
#include "llvm/Support/ManagedStatic.h"
|
2017-06-20 06:05:08 +08:00
|
|
|
#include <cassert>
|
|
|
|
#include <utility>
|
|
|
|
|
2010-04-16 01:08:50 +08:00
|
|
|
using namespace llvm;
|
2010-03-22 05:17:34 +08:00
|
|
|
|
2021-06-24 23:21:24 +08:00
|
|
|
static cl::opt<bool>
|
[OpaquePtr] Forbid mixing typed and opaque pointers
Currently, opaque pointers are supported in two forms: The
-force-opaque-pointers mode, where all pointers are opaque and
typed pointers do not exist. And as a simple ptr type that can
coexist with typed pointers.
This patch removes support for the mixed mode. You either get
typed pointers, or you get opaque pointers, but not both. In the
(current) default mode, using ptr is forbidden. In -opaque-pointers
mode, all pointers are opaque.
The motivation here is that the mixed mode introduces additional
issues that don't exist in fully opaque mode. D105155 is an example
of a design problem. Looking at D109259, it would probably need
additional work to support mixed mode (e.g. to generate GEPs for
typed base but opaque result). Mixed mode will also end up
inserting many casts between i8* and ptr, which would require
significant additional work to consistently avoid.
I don't think the mixed mode is particularly valuable, as it
doesn't align with our end goal. The only thing I've found it to
be moderately useful for is adding some opaque pointer tests in
between typed pointer tests, but I think we can live without that.
Differential Revision: https://reviews.llvm.org/D109290
2021-09-04 18:18:52 +08:00
|
|
|
OpaquePointersCL("opaque-pointers", cl::desc("Use opaque pointers"),
|
|
|
|
cl::init(false));
|
2021-06-24 23:21:24 +08:00
|
|
|
|
2010-03-22 05:17:34 +08:00
|
|
|
LLVMContextImpl::LLVMContextImpl(LLVMContext &C)
|
2021-06-24 23:21:24 +08:00
|
|
|
: DiagHandler(std::make_unique<DiagnosticHandler>()),
|
|
|
|
VoidTy(C, Type::VoidTyID), LabelTy(C, Type::LabelTyID),
|
|
|
|
HalfTy(C, Type::HalfTyID), BFloatTy(C, Type::BFloatTyID),
|
|
|
|
FloatTy(C, Type::FloatTyID), DoubleTy(C, Type::DoubleTyID),
|
|
|
|
MetadataTy(C, Type::MetadataTyID), TokenTy(C, Type::TokenTyID),
|
|
|
|
X86_FP80Ty(C, Type::X86_FP80TyID), FP128Ty(C, Type::FP128TyID),
|
|
|
|
PPC_FP128Ty(C, Type::PPC_FP128TyID), X86_MMXTy(C, Type::X86_MMXTyID),
|
|
|
|
X86_AMXTy(C, Type::X86_AMXTyID), Int1Ty(C, 1), Int8Ty(C, 8),
|
2021-11-05 10:26:25 +08:00
|
|
|
Int16Ty(C, 16), Int32Ty(C, 32), Int64Ty(C, 64), Int128Ty(C, 128) {}
|
2010-03-22 05:17:34 +08:00
|
|
|
|
|
|
|
LLVMContextImpl::~LLVMContextImpl() {
|
2014-04-22 05:27:19 +08:00
|
|
|
// NOTE: We need to delete the contents of OwnedModules, but Module's dtor
|
|
|
|
// will call LLVMContextImpl::removeModule, thus invalidating iterators into
|
|
|
|
// the container. Avoid iterators during this operation:
|
|
|
|
while (!OwnedModules.empty())
|
|
|
|
delete *OwnedModules.begin();
|
2015-01-15 05:58:17 +08:00
|
|
|
|
2018-06-30 04:13:13 +08:00
|
|
|
#ifndef NDEBUG
|
2019-09-14 01:21:24 +08:00
|
|
|
// Check for metadata references from leaked Values.
|
|
|
|
for (auto &Pair : ValueMetadata)
|
2018-06-30 04:13:13 +08:00
|
|
|
Pair.first->dump();
|
2019-09-14 01:21:24 +08:00
|
|
|
assert(ValueMetadata.empty() && "Values with metadata have been leaked");
|
2018-06-30 04:13:13 +08:00
|
|
|
#endif
|
|
|
|
|
2015-01-15 05:58:17 +08:00
|
|
|
// Drop references for MDNodes. Do this before Values get deleted to avoid
|
|
|
|
// unnecessary RAUW when nodes are still unresolved.
|
[DIArgList] Re-unique after changing operands to fix non-determinism
We have a large compile showing occasional non-deterministic behavior
that is due to DIArgList not being properly uniqued in some cases. I
tracked this down to handleChangedOperands, for which there is a custom
implementation for DIArgList, that does not take care of re-uniquing
after updating the DIArgList Args, unlike the default version of
handleChangedOperands for MDNode.
Since the Args in the DIArgList form the key for the store, this seems
to be occasionally breaking the lookup in that DenseSet. Specifically,
when invoking DIArgList::get() from replaceVariableLocationOp, very
occasionally it returns a new DIArgList object, when one already exists
having the same exact Args pointers. This in turn causes a subsequent
call to Instruction::isIdenticalToWhenDefined on those two otherwise
identical DIArgList objects during a later pass to return false, leading
to different IR in those rare cases.
I modified DIArgList::handleChangedOperands to perform similar
re-uniquing as the MDNode version used by other metadata node types.
This also necessitated a change to the context destructor, since in some
cases we end up with DIArgList as distinct nodes: DIArgList is the only
metadata node type to have a custom dropAllReferences, so we need to
invoke that version on DIArgList in the DistinctMDNodes store to clean
it up properly.
Differential Revision: https://reviews.llvm.org/D108968
2021-08-31 11:07:01 +08:00
|
|
|
for (auto *I : DistinctMDNodes) {
|
|
|
|
// We may have DIArgList that were uniqued, and as it has a custom
|
|
|
|
// implementation of dropAllReferences, it needs to be explicitly invoked.
|
|
|
|
if (auto *AL = dyn_cast<DIArgList>(I)) {
|
|
|
|
AL->dropAllReferences();
|
|
|
|
continue;
|
|
|
|
}
|
2015-01-15 05:58:17 +08:00
|
|
|
I->dropAllReferences();
|
[DIArgList] Re-unique after changing operands to fix non-determinism
We have a large compile showing occasional non-deterministic behavior
that is due to DIArgList not being properly uniqued in some cases. I
tracked this down to handleChangedOperands, for which there is a custom
implementation for DIArgList, that does not take care of re-uniquing
after updating the DIArgList Args, unlike the default version of
handleChangedOperands for MDNode.
Since the Args in the DIArgList form the key for the store, this seems
to be occasionally breaking the lookup in that DenseSet. Specifically,
when invoking DIArgList::get() from replaceVariableLocationOp, very
occasionally it returns a new DIArgList object, when one already exists
having the same exact Args pointers. This in turn causes a subsequent
call to Instruction::isIdenticalToWhenDefined on those two otherwise
identical DIArgList objects during a later pass to return false, leading
to different IR in those rare cases.
I modified DIArgList::handleChangedOperands to perform similar
re-uniquing as the MDNode version used by other metadata node types.
This also necessitated a change to the context destructor, since in some
cases we end up with DIArgList as distinct nodes: DIArgList is the only
metadata node type to have a custom dropAllReferences, so we need to
invoke that version on DIArgList in the DistinctMDNodes store to clean
it up properly.
Differential Revision: https://reviews.llvm.org/D108968
2021-08-31 11:07:01 +08:00
|
|
|
}
|
2015-08-04 01:26:41 +08:00
|
|
|
#define HANDLE_MDNODE_LEAF_UNIQUABLE(CLASS) \
|
2015-01-20 09:18:32 +08:00
|
|
|
for (auto *I : CLASS##s) \
|
2015-01-15 05:58:17 +08:00
|
|
|
I->dropAllReferences();
|
2015-01-20 09:18:32 +08:00
|
|
|
#include "llvm/IR/Metadata.def"
|
2015-01-15 05:58:17 +08:00
|
|
|
|
|
|
|
// Also drop references that come from the Value bridges.
|
|
|
|
for (auto &Pair : ValuesAsMetadata)
|
|
|
|
Pair.second->dropUsers();
|
|
|
|
for (auto &Pair : MetadataAsValues)
|
|
|
|
Pair.second->dropUse();
|
|
|
|
|
|
|
|
// Destroy MDNodes.
|
2015-01-20 07:13:14 +08:00
|
|
|
for (MDNode *I : DistinctMDNodes)
|
2015-01-15 05:58:17 +08:00
|
|
|
I->deleteAsSubclass();
|
2015-08-04 01:26:41 +08:00
|
|
|
#define HANDLE_MDNODE_LEAF_UNIQUABLE(CLASS) \
|
|
|
|
for (CLASS * I : CLASS##s) \
|
2015-01-15 05:58:17 +08:00
|
|
|
delete I;
|
2015-01-20 09:18:32 +08:00
|
|
|
#include "llvm/IR/Metadata.def"
|
2015-01-15 05:58:17 +08:00
|
|
|
|
2015-01-23 05:43:01 +08:00
|
|
|
// Free the constants.
|
2016-04-07 01:56:08 +08:00
|
|
|
for (auto *I : ExprConstants)
|
|
|
|
I->dropAllReferences();
|
|
|
|
for (auto *I : ArrayConstants)
|
|
|
|
I->dropAllReferences();
|
|
|
|
for (auto *I : StructConstants)
|
|
|
|
I->dropAllReferences();
|
|
|
|
for (auto *I : VectorConstants)
|
|
|
|
I->dropAllReferences();
|
2010-03-22 05:17:34 +08:00
|
|
|
ExprConstants.freeConstants();
|
|
|
|
ArrayConstants.freeConstants();
|
|
|
|
StructConstants.freeConstants();
|
|
|
|
VectorConstants.freeConstants();
|
|
|
|
InlineAsms.freeConstants();
|
2016-10-11 00:26:13 +08:00
|
|
|
|
|
|
|
CAZConstants.clear();
|
|
|
|
CPNConstants.clear();
|
|
|
|
UVConstants.clear();
|
2020-11-26 15:10:36 +08:00
|
|
|
PVConstants.clear();
|
2016-10-11 00:26:13 +08:00
|
|
|
IntConstants.clear();
|
|
|
|
FPConstants.clear();
|
2012-01-24 06:57:10 +08:00
|
|
|
CDSConstants.clear();
|
2012-09-27 05:07:29 +08:00
|
|
|
|
2013-01-24 08:14:46 +08:00
|
|
|
// Destroy attribute node lists.
|
|
|
|
for (FoldingSetIterator<AttributeSetNode> I = AttrsSetNodes.begin(),
|
|
|
|
E = AttrsSetNodes.end(); I != E; ) {
|
|
|
|
FoldingSetIterator<AttributeSetNode> Elem = I++;
|
|
|
|
delete &*Elem;
|
|
|
|
}
|
|
|
|
|
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.)
llvm-svn: 223802
2014-12-10 02:38:53 +08:00
|
|
|
// Destroy MetadataAsValues.
|
|
|
|
{
|
|
|
|
SmallVector<MetadataAsValue *, 8> MDVs;
|
|
|
|
MDVs.reserve(MetadataAsValues.size());
|
|
|
|
for (auto &Pair : MetadataAsValues)
|
|
|
|
MDVs.push_back(Pair.second);
|
|
|
|
MetadataAsValues.clear();
|
|
|
|
for (auto *V : MDVs)
|
|
|
|
delete V;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Destroy ValuesAsMetadata.
|
|
|
|
for (auto &Pair : ValuesAsMetadata)
|
|
|
|
delete Pair.second;
|
2010-03-22 05:17:34 +08:00
|
|
|
}
|
2011-12-20 10:50:00 +08:00
|
|
|
|
2015-01-21 03:24:59 +08:00
|
|
|
void LLVMContextImpl::dropTriviallyDeadConstantArrays() {
|
2020-08-08 00:30:26 +08:00
|
|
|
SmallSetVector<ConstantArray *, 4> WorkList;
|
|
|
|
|
|
|
|
// When ArrayConstants are of substantial size and only a few in them are
|
|
|
|
// dead, starting WorkList with all elements of ArrayConstants can be
|
|
|
|
// wasteful. Instead, starting WorkList with only elements that have empty
|
|
|
|
// uses.
|
|
|
|
for (ConstantArray *C : ArrayConstants)
|
|
|
|
if (C->use_empty())
|
|
|
|
WorkList.insert(C);
|
2020-01-21 22:54:48 +08:00
|
|
|
|
|
|
|
while (!WorkList.empty()) {
|
|
|
|
ConstantArray *C = WorkList.pop_back_val();
|
|
|
|
if (C->use_empty()) {
|
|
|
|
for (const Use &Op : C->operands()) {
|
|
|
|
if (auto *COp = dyn_cast<ConstantArray>(Op))
|
|
|
|
WorkList.insert(COp);
|
2015-01-21 03:24:59 +08:00
|
|
|
}
|
2020-01-21 22:54:48 +08:00
|
|
|
C->destroyConstant();
|
2015-01-21 03:24:59 +08:00
|
|
|
}
|
2020-01-21 22:54:48 +08:00
|
|
|
}
|
2015-01-21 03:24:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Module::dropTriviallyDeadConstantArrays() {
|
|
|
|
Context.pImpl->dropTriviallyDeadConstantArrays();
|
|
|
|
}
|
|
|
|
|
2015-01-20 06:53:18 +08:00
|
|
|
namespace llvm {
|
2017-06-20 06:05:08 +08:00
|
|
|
|
2018-05-01 23:54:18 +08:00
|
|
|
/// Make MDOperand transparent for hashing.
|
2015-01-20 06:53:18 +08:00
|
|
|
///
|
|
|
|
/// This overload of an implementation detail of the hashing library makes
|
|
|
|
/// MDOperand hash to the same value as a \a Metadata pointer.
|
|
|
|
///
|
|
|
|
/// Note that overloading \a hash_value() as follows:
|
|
|
|
///
|
|
|
|
/// \code
|
|
|
|
/// size_t hash_value(const MDOperand &X) { return hash_value(X.get()); }
|
|
|
|
/// \endcode
|
|
|
|
///
|
|
|
|
/// does not cause MDOperand to be transparent. In particular, a bare pointer
|
|
|
|
/// doesn't get hashed before it's combined, whereas \a MDOperand would.
|
|
|
|
static const Metadata *get_hashable_data(const MDOperand &X) { return X.get(); }
|
2017-06-20 06:05:08 +08:00
|
|
|
|
|
|
|
} // end namespace llvm
|
2015-01-20 06:53:18 +08:00
|
|
|
|
2015-01-20 08:01:43 +08:00
|
|
|
unsigned MDNodeOpsKey::calculateHash(MDNode *N, unsigned Offset) {
|
|
|
|
unsigned Hash = hash_combine_range(N->op_begin() + Offset, N->op_end());
|
2015-01-20 06:53:18 +08:00
|
|
|
#ifndef NDEBUG
|
|
|
|
{
|
2021-01-17 01:40:53 +08:00
|
|
|
SmallVector<Metadata *, 8> MDs(drop_begin(N->operands(), Offset));
|
2015-01-20 06:53:18 +08:00
|
|
|
unsigned RawHash = calculateHash(MDs);
|
|
|
|
assert(Hash == RawHash &&
|
|
|
|
"Expected hash of MDOperand to equal hash of Metadata*");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return Hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned MDNodeOpsKey::calculateHash(ArrayRef<Metadata *> Ops) {
|
|
|
|
return hash_combine_range(Ops.begin(), Ops.end());
|
|
|
|
}
|
|
|
|
|
2015-09-25 03:14:18 +08:00
|
|
|
StringMapEntry<uint32_t> *LLVMContextImpl::getOrInsertBundleTag(StringRef Tag) {
|
|
|
|
uint32_t NewIdx = BundleTagCache.size();
|
|
|
|
return &*(BundleTagCache.insert(std::make_pair(Tag, NewIdx)).first);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LLVMContextImpl::getOperandBundleTags(SmallVectorImpl<StringRef> &Tags) const {
|
|
|
|
Tags.resize(BundleTagCache.size());
|
|
|
|
for (const auto &T : BundleTagCache)
|
|
|
|
Tags[T.second] = T.first();
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t LLVMContextImpl::getOperandBundleTagID(StringRef Tag) const {
|
|
|
|
auto I = BundleTagCache.find(Tag);
|
|
|
|
assert(I != BundleTagCache.end() && "Unknown tag!");
|
|
|
|
return I->second;
|
|
|
|
}
|
|
|
|
|
2017-07-12 06:23:00 +08:00
|
|
|
SyncScope::ID LLVMContextImpl::getOrInsertSyncScopeID(StringRef SSN) {
|
|
|
|
auto NewSSID = SSC.size();
|
|
|
|
assert(NewSSID < std::numeric_limits<SyncScope::ID>::max() &&
|
|
|
|
"Hit the maximum number of synchronization scopes allowed!");
|
|
|
|
return SSC.insert(std::make_pair(SSN, SyncScope::ID(NewSSID))).first->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
void LLVMContextImpl::getSyncScopeNames(
|
|
|
|
SmallVectorImpl<StringRef> &SSNs) const {
|
|
|
|
SSNs.resize(SSC.size());
|
|
|
|
for (const auto &SSE : SSC)
|
|
|
|
SSNs[SSE.second] = SSE.first();
|
|
|
|
}
|
|
|
|
|
2020-12-21 05:47:46 +08:00
|
|
|
/// Gets the OptPassGate for this LLVMContextImpl, which defaults to the
|
|
|
|
/// singleton OptBisect if not explicitly set.
|
2018-04-05 18:29:37 +08:00
|
|
|
OptPassGate &LLVMContextImpl::getOptPassGate() const {
|
|
|
|
if (!OPG)
|
|
|
|
OPG = &(*OptBisector);
|
|
|
|
return *OPG;
|
|
|
|
}
|
|
|
|
|
|
|
|
void LLVMContextImpl::setOptPassGate(OptPassGate& OPG) {
|
|
|
|
this->OPG = &OPG;
|
2016-04-23 06:06:11 +08:00
|
|
|
}
|
2021-11-05 10:26:25 +08:00
|
|
|
|
|
|
|
bool LLVMContextImpl::getOpaquePointers() {
|
|
|
|
if (LLVM_UNLIKELY(!(OpaquePointers.hasValue())))
|
|
|
|
OpaquePointers = OpaquePointersCL;
|
|
|
|
return *OpaquePointers;
|
|
|
|
}
|
|
|
|
|
|
|
|
void LLVMContextImpl::setOpaquePointers(bool OP) { OpaquePointers = OP; }
|