mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-29 16:26:05 +00:00

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
245 lines
8.1 KiB
C++
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; }
|