[llvm] [CAS] LLVMCAS implementation (PR #68448)
Alexandre Ganea via llvm-commits
llvm-commits at lists.llvm.org
Fri Feb 9 15:23:31 PST 2024
================
@@ -0,0 +1,207 @@
+//===- llvm/CAS/CASReference.h ----------------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CAS_CASREFERENCE_H
+#define LLVM_CAS_CASREFERENCE_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm {
+
+class raw_ostream;
+
+namespace cas {
+
+class ObjectStore;
+
+class ObjectHandle;
+class ObjectRef;
+
+/// Base class for references to things in \a ObjectStore.
+class ReferenceBase {
+protected:
+ struct DenseMapEmptyTag {};
+ struct DenseMapTombstoneTag {};
+ static constexpr uint64_t getDenseMapEmptyRef() { return -1ULL; }
+ static constexpr uint64_t getDenseMapTombstoneRef() { return -2ULL; }
+
+public:
+ /// Get an internal reference.
+ uint64_t getInternalRef(const ObjectStore &ExpectedCAS) const {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ assert(CAS == &ExpectedCAS && "Extracting reference for the wrong CAS");
+#endif
+ return InternalRef;
+ }
+
+ unsigned getDenseMapHash() const {
+ return (unsigned)llvm::hash_value(InternalRef);
+ }
+ bool isDenseMapEmpty() const { return InternalRef == getDenseMapEmptyRef(); }
+ bool isDenseMapTombstone() const {
+ return InternalRef == getDenseMapTombstoneRef();
+ }
+ bool isDenseMapSentinel() const {
+ return isDenseMapEmpty() || isDenseMapTombstone();
+ }
+
+protected:
+ void print(raw_ostream &OS, const ObjectHandle &This) const;
+ void print(raw_ostream &OS, const ObjectRef &This) const;
+
+ bool hasSameInternalRef(const ReferenceBase &RHS) const {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ assert(
+ (isDenseMapSentinel() || RHS.isDenseMapSentinel() || CAS == RHS.CAS) &&
+ "Cannot compare across CAS instances");
+#endif
+ return InternalRef == RHS.InternalRef;
+ }
+
+protected:
+ friend class ObjectStore;
+ ReferenceBase(const ObjectStore *CAS, uint64_t InternalRef, bool IsHandle)
+ : InternalRef(InternalRef) {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ this->CAS = CAS;
+#endif
+ assert(InternalRef != getDenseMapEmptyRef() && "Reserved for DenseMapInfo");
+ assert(InternalRef != getDenseMapTombstoneRef() &&
+ "Reserved for DenseMapInfo");
+ }
+ explicit ReferenceBase(DenseMapEmptyTag)
+ : InternalRef(getDenseMapEmptyRef()) {}
+ explicit ReferenceBase(DenseMapTombstoneTag)
+ : InternalRef(getDenseMapTombstoneRef()) {}
+
+private:
+ uint64_t InternalRef;
+
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ const ObjectStore *CAS = nullptr;
+#endif
+};
+
+/// Reference to an object in a \a ObjectStore instance.
+///
+/// If you have an ObjectRef, you know the object exists, and you can point at
+/// it from new nodes with \a ObjectStore::store(), but you don't know anything
+/// about it. "Loading" the object is a separate step that may not have
+/// happened yet, and which can fail (due to filesystem corruption) or
+/// introduce latency (if downloading from a remote store).
+///
+/// \a ObjectStore::store() takes a list of these, and these are returned by \a
+/// ObjectStore::forEachRef() and \a ObjectStore::readRef(), which are accessors
+/// for nodes, and \a ObjectStore::getReference().
+///
+/// \a ObjectStore::load() will load the referenced object, and returns \a
+/// ObjectHandle, a variant that knows what kind of entity it is. \a
+/// ObjectStore::getReferenceKind() can expect the type of reference without
+/// asking for unloaded objects to be loaded.
+///
+/// This is a wrapper around a \c uint64_t (and a \a ObjectStore instance when
+/// assertions are on). If necessary, it can be deconstructed and reconstructed
+/// using \a Reference::getInternalRef() and \a
+/// Reference::getFromInternalRef(), but clients aren't expected to need to do
+/// this. These both require the right \a ObjectStore instance.
+class ObjectRef : public ReferenceBase {
+ struct DenseMapTag {};
+
+public:
+ friend bool operator==(const ObjectRef &LHS, const ObjectRef &RHS) {
+ return LHS.hasSameInternalRef(RHS);
+ }
+ friend bool operator!=(const ObjectRef &LHS, const ObjectRef &RHS) {
+ return !(LHS == RHS);
+ }
+
+ /// Allow a reference to be recreated after it's deconstructed.
+ static ObjectRef getFromInternalRef(const ObjectStore &CAS,
+ uint64_t InternalRef) {
+ return ObjectRef(CAS, InternalRef);
+ }
+
+ static ObjectRef getDenseMapEmptyKey() {
+ return ObjectRef(DenseMapEmptyTag{});
+ }
+ static ObjectRef getDenseMapTombstoneKey() {
+ return ObjectRef(DenseMapTombstoneTag{});
+ }
+
+ /// Print internal ref and/or CASID. Only suitable for debugging.
+ void print(raw_ostream &OS) const { return ReferenceBase::print(OS, *this); }
+
+ LLVM_DUMP_METHOD void dump() const;
+
+private:
+ friend class ObjectStore;
+ friend class ReferenceBase;
+ using ReferenceBase::ReferenceBase;
+ ObjectRef(const ObjectStore &CAS, uint64_t InternalRef)
+ : ReferenceBase(&CAS, InternalRef, /*IsHandle=*/false) {
+ assert(InternalRef != -1ULL && "Reserved for DenseMapInfo");
+ assert(InternalRef != -2ULL && "Reserved for DenseMapInfo");
+ }
+ explicit ObjectRef(DenseMapEmptyTag T) : ReferenceBase(T) {}
+ explicit ObjectRef(DenseMapTombstoneTag T) : ReferenceBase(T) {}
+ explicit ObjectRef(ReferenceBase) = delete;
+};
+
+/// Handle to a loaded object in a \a ObjectStore instance.
+///
+/// ObjectHandle encapulates a *loaded* object in the CAS. You need one
+/// of these to inspect the content of an object: to look at its stored
+/// data and references.
+class ObjectHandle : public ReferenceBase {
----------------
aganea wrote:
I just skimmed over the PR, but it still unclear why `ObjectHandle` is needed. Is this just for semantic purposes? Why can't we just have `ObjectRef`?
https://github.com/llvm/llvm-project/pull/68448
More information about the llvm-commits
mailing list