diff --git a/backends/cxxrtl/cxxrtl_backend.cc b/backends/cxxrtl/cxxrtl_backend.cc index ff11d7fe0..30995ea11 100644 --- a/backends/cxxrtl/cxxrtl_backend.cc +++ b/backends/cxxrtl/cxxrtl_backend.cc @@ -2391,7 +2391,7 @@ struct CxxrtlWorker { f << indent << "}\n"; f << "\n"; f << indent << "bool commit() override {\n"; - f << indent << indent << "null_observer observer;\n"; + f << indent << indent << "observer observer;\n"; f << indent << indent << "return commit<>(observer);\n"; f << indent << "}\n"; if (debug_info) { @@ -2486,7 +2486,7 @@ struct CxxrtlWorker { f << indent << "}\n"; f << "\n"; f << indent << "bool commit() override {\n"; - f << indent << indent << "null_observer observer;\n"; + f << indent << indent << "observer observer;\n"; f << indent << indent << "return commit<>(observer);\n"; f << indent << "}\n"; if (debug_info) { diff --git a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h index e2729bfe4..bd336f481 100644 --- a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h @@ -865,19 +865,12 @@ struct observer { // Called when the `commit()` method for a wire is about to update the `chunks` chunks at `base` with `chunks` chunks // at `value` that have a different bit pattern. It is guaranteed that `chunks` is equal to the wire chunk count and // `base` points to the first chunk. - virtual void on_update(size_t chunks, const chunk_t *base, const chunk_t *value) = 0; + void on_update(size_t chunks, const chunk_t *base, const chunk_t *value) {} // Called when the `commit()` method for a memory is about to update the `chunks` chunks at `&base[chunks * index]` // with `chunks` chunks at `value` that have a different bit pattern. It is guaranteed that `chunks` is equal to // the memory element chunk count and `base` points to the first chunk of the first element of the memory. - virtual void on_update(size_t chunks, const chunk_t *base, const chunk_t *value, size_t index) = 0; -}; - -// The `null_observer` class has the same interface as `observer`, but has no invocation overhead, since its methods -// are final and have no implementation. This allows the observer feature to be zero-cost when not in use. -struct null_observer final: observer { - void on_update(size_t chunks, const chunk_t *base, const chunk_t *value) override {} - void on_update(size_t chunks, const chunk_t *base, const chunk_t *value, size_t index) override {} + void on_update(size_t chunks, const chunk_t *base, const chunk_t *value, size_t index) {} }; template @@ -916,8 +909,7 @@ struct wire { // This method intentionally takes a mandatory argument (to make it more difficult to misuse in // black box implementations, leading to missed observer events). It is generic over its argument - // to make sure the `on_update` call is devirtualized. This is somewhat awkward but lets us keep - // a single implementation for both this method and the one in `memory`. + // to allow the `on_update` method to be non-virtual. template bool commit(ObserverT &observer) { if (curr != next) { diff --git a/backends/cxxrtl/runtime/cxxrtl/cxxrtl_replay.h b/backends/cxxrtl/runtime/cxxrtl/cxxrtl_replay.h index e44b1c4e1..d824fdb83 100644 --- a/backends/cxxrtl/runtime/cxxrtl/cxxrtl_replay.h +++ b/backends/cxxrtl/runtime/cxxrtl/cxxrtl_replay.h @@ -556,22 +556,20 @@ public: bool record_incremental(ModuleT &module) { assert(streaming); - struct : public observer { + struct { std::unordered_map *ident_lookup; spool::writer *writer; CXXRTL_ALWAYS_INLINE - void on_update(size_t chunks, const chunk_t *base, const chunk_t *value) override { + void on_update(size_t chunks, const chunk_t *base, const chunk_t *value) { writer->write_change(ident_lookup->at(base), chunks, value); } CXXRTL_ALWAYS_INLINE - void on_update(size_t chunks, const chunk_t *base, const chunk_t *value, size_t index) override { + void on_update(size_t chunks, const chunk_t *base, const chunk_t *value, size_t index) { writer->write_change(ident_lookup->at(base), chunks, value, index); } - } record_observer; - record_observer.ident_lookup = &ident_lookup; - record_observer.writer = &writer; + } record_observer = { &ident_lookup, &writer }; writer.write_sample(/*incremental=*/true, pointer++, timestamp); for (auto input_index : inputs) {