llvm-project/llvm/lib/IR/LLVMContextImpl.cpp
Scott Linder ee76525698 [DebugInfo] Enforce implicit constraints on distinct MDNodes
Add UNIQUED and DISTINCT properties in Metadata.def and use them to
implement restrictions on the `distinct` property of MDNodes:

* DIExpression can currently be parsed from IR or read from bitcode
  as `distinct`, but this property is silently dropped when printing
  to IR. This causes accepted IR to fail to round-trip. As DIExpression
  appears inline at each use in the canonical form of IR, it cannot
  actually be `distinct` anyway, as there is no syntax to describe it.
* Similarly, DIArgList is conceptually always uniqued. It is currently
  restricted to only appearing in contexts where there is no syntax for
  `distinct`, but for consistency it is treated equivalently to
  DIExpression in this patch.
* DICompileUnit is already restricted to always being `distinct`, but
  along with adding general support for the inverse restriction I went
  ahead and described this in Metadata.def and updated the parser to be
  general. Future nodes which have this restriction can share this
  support.

The new UNIQUED property applies to DIExpression and DIArgList, and
forbids them to be `distinct`. It also implies they are canonically
printed inline at each use, rather than via MDNode ID.

The new DISTINCT property applies to DICompileUnit, and requires it to
be `distinct`.

A potential alternative change is to forbid the non-inline syntax for
DIExpression entirely, as is done with DIArgList implicitly by requiring
it appear in the context of a function. For example, we would forbid:

    !named = !{!0}
    !0 = !DIExpression()

Instead we would only accept the equivalent inlined version:

    !named = !{!DIExpression()}

This essentially removes the ability to create a `distinct` DIExpression
by construction, as there is no syntax for `distinct` inline. If this
patch is accepted as-is, the result would be that the non-canonical
version is accepted, but the following would be an error and produce a diagnostic:

    !named = !{!0}
    ; error: 'distinct' not allowed for !DIExpression()
    !0 = distinct !DIExpression()

Also update some documentation to consistently use the inline syntax for
DIExpression, and to describe the restrictions on `distinct` for nodes
where applicable.

Reviewed By: StephenTozer, t-tye

Differential Revision: https://reviews.llvm.org/D104827
2021-11-09 18:19:11 +00:00

245 lines
8.1 KiB
C++

//===- LLVMContextImpl.cpp - Implement LLVMContextImpl --------------------===//
//
// 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 implements the opaque LLVMContextImpl.
//
//===----------------------------------------------------------------------===//
#include "LLVMContextImpl.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/OptBisect.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ManagedStatic.h"
#include <cassert>
#include <utility>
using namespace llvm;
static cl::opt<bool>
OpaquePointersCL("opaque-pointers", cl::desc("Use opaque pointers"),
cl::init(false));
LLVMContextImpl::LLVMContextImpl(LLVMContext &C)
: 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),
Int16Ty(C, 16), Int32Ty(C, 32), Int64Ty(C, 64), Int128Ty(C, 128) {}
LLVMContextImpl::~LLVMContextImpl() {
// 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();
#ifndef NDEBUG
// Check for metadata references from leaked Values.
for (auto &Pair : ValueMetadata)
Pair.first->dump();
assert(ValueMetadata.empty() && "Values with metadata have been leaked");
#endif
// Drop references for MDNodes. Do this before Values get deleted to avoid
// unnecessary RAUW when nodes are still unresolved.
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;
}
I->dropAllReferences();
}
#define HANDLE_MDNODE_LEAF_UNIQUABLE(CLASS) \
for (auto *I : CLASS##s) \
I->dropAllReferences();
#define HANDLE_MDNODE_LEAF_UNIQUED(CLASS) HANDLE_MDNODE_LEAF_UNIQUABLE(CLASS)
#include "llvm/IR/Metadata.def"
// 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.
for (MDNode *I : DistinctMDNodes)
I->deleteAsSubclass();
#define HANDLE_MDNODE_LEAF_UNIQUABLE(CLASS) \
for (CLASS * I : CLASS##s) \
delete I;
#define HANDLE_MDNODE_LEAF_UNIQUED(CLASS) HANDLE_MDNODE_LEAF_UNIQUABLE(CLASS)
#include "llvm/IR/Metadata.def"
// Free the constants.
for (auto *I : ExprConstants)
I->dropAllReferences();
for (auto *I : ArrayConstants)
I->dropAllReferences();
for (auto *I : StructConstants)
I->dropAllReferences();
for (auto *I : VectorConstants)
I->dropAllReferences();
ExprConstants.freeConstants();
ArrayConstants.freeConstants();
StructConstants.freeConstants();
VectorConstants.freeConstants();
InlineAsms.freeConstants();
CAZConstants.clear();
CPNConstants.clear();
UVConstants.clear();
PVConstants.clear();
IntConstants.clear();
FPConstants.clear();
CDSConstants.clear();
// Destroy attribute node lists.
for (FoldingSetIterator<AttributeSetNode> I = AttrsSetNodes.begin(),
E = AttrsSetNodes.end(); I != E; ) {
FoldingSetIterator<AttributeSetNode> Elem = I++;
delete &*Elem;
}
// 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;
}
void LLVMContextImpl::dropTriviallyDeadConstantArrays() {
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);
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);
}
C->destroyConstant();
}
}
}
void Module::dropTriviallyDeadConstantArrays() {
Context.pImpl->dropTriviallyDeadConstantArrays();
}
namespace llvm {
/// Make MDOperand transparent for hashing.
///
/// 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(); }
} // end namespace llvm
unsigned MDNodeOpsKey::calculateHash(MDNode *N, unsigned Offset) {
unsigned Hash = hash_combine_range(N->op_begin() + Offset, N->op_end());
#ifndef NDEBUG
{
SmallVector<Metadata *, 8> MDs(drop_begin(N->operands(), Offset));
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());
}
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;
}
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();
}
/// Gets the OptPassGate for this LLVMContextImpl, which defaults to the
/// singleton OptBisect if not explicitly set.
OptPassGate &LLVMContextImpl::getOptPassGate() const {
if (!OPG)
OPG = &(*OptBisector);
return *OPG;
}
void LLVMContextImpl::setOptPassGate(OptPassGate& OPG) {
this->OPG = &OPG;
}
bool LLVMContextImpl::getOpaquePointers() {
if (LLVM_UNLIKELY(!(OpaquePointers.hasValue())))
OpaquePointers = OpaquePointersCL;
return *OpaquePointers;
}
void LLVMContextImpl::setOpaquePointers(bool OP) { OpaquePointers = OP; }