2021-06-17 16:27:45 +00:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
|
|
|
//*************************************************************************
|
|
|
|
// DESCRIPTION: Verilator: Utility to hang advanced data structures of
|
|
|
|
// AstNode::user*p() pointers with automatic memory management.
|
|
|
|
//
|
|
|
|
// Code available from: https://verilator.org
|
|
|
|
//
|
|
|
|
//*************************************************************************
|
|
|
|
//
|
2024-01-01 08:19:59 +00:00
|
|
|
// Copyright 2003-2024 by Wilson Snyder. This program is free software; you
|
2021-06-17 16:27:45 +00:00
|
|
|
// can redistribute it and/or modify it under the terms of either the GNU
|
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
|
|
// Version 2.0.
|
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
|
|
//
|
|
|
|
//*************************************************************************
|
|
|
|
|
|
|
|
#ifndef VERILATOR_V3ASTUSERALLOCATOR_H_
|
|
|
|
#define VERILATOR_V3ASTUSERALLOCATOR_H_
|
|
|
|
|
|
|
|
#include "config_build.h"
|
|
|
|
#include "verilatedos.h"
|
|
|
|
|
|
|
|
#include "V3Ast.h"
|
|
|
|
|
|
|
|
#include <type_traits>
|
2021-12-17 17:56:33 +00:00
|
|
|
#include <utility>
|
2021-06-17 16:27:45 +00:00
|
|
|
#include <vector>
|
|
|
|
|
2022-08-05 09:56:57 +00:00
|
|
|
template <class T_Node, class T_Data, int T_UserN>
|
|
|
|
class AstUserAllocatorBase VL_NOT_FINAL {
|
2023-10-29 00:12:27 +00:00
|
|
|
static_assert(1 <= T_UserN && T_UserN <= 4, "Wrong user pointer number");
|
2021-06-17 16:27:45 +00:00
|
|
|
static_assert(std::is_base_of<AstNode, T_Node>::value, "T_Node must be an AstNode type");
|
|
|
|
|
|
|
|
private:
|
2023-10-28 19:31:52 +00:00
|
|
|
std::deque<T_Data> m_allocated;
|
2021-06-17 16:27:45 +00:00
|
|
|
|
2022-09-16 12:17:38 +00:00
|
|
|
T_Data* getUserp(const T_Node* nodep) const {
|
2022-07-05 13:20:37 +00:00
|
|
|
if VL_CONSTEXPR_CXX17 (T_UserN == 1) {
|
2021-06-20 22:32:57 +00:00
|
|
|
const VNUser user = nodep->user1u();
|
2021-06-17 16:27:45 +00:00
|
|
|
return user.to<T_Data*>();
|
2022-07-05 13:20:37 +00:00
|
|
|
} else if VL_CONSTEXPR_CXX17 (T_UserN == 2) {
|
2021-06-20 22:32:57 +00:00
|
|
|
const VNUser user = nodep->user2u();
|
2021-06-17 16:27:45 +00:00
|
|
|
return user.to<T_Data*>();
|
2022-07-05 13:20:37 +00:00
|
|
|
} else if VL_CONSTEXPR_CXX17 (T_UserN == 3) {
|
2021-06-20 22:32:57 +00:00
|
|
|
const VNUser user = nodep->user3u();
|
2021-06-17 16:27:45 +00:00
|
|
|
return user.to<T_Data*>();
|
|
|
|
} else {
|
2023-10-29 00:12:27 +00:00
|
|
|
const VNUser user = nodep->user4u();
|
2021-06-17 16:27:45 +00:00
|
|
|
return user.to<T_Data*>();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-16 12:17:38 +00:00
|
|
|
void setUserp(T_Node* nodep, T_Data* userp) const {
|
2022-07-05 13:20:37 +00:00
|
|
|
if VL_CONSTEXPR_CXX17 (T_UserN == 1) {
|
2022-09-15 23:58:01 +00:00
|
|
|
nodep->user1u(VNUser{userp});
|
2022-07-05 13:20:37 +00:00
|
|
|
} else if VL_CONSTEXPR_CXX17 (T_UserN == 2) {
|
2022-09-15 23:58:01 +00:00
|
|
|
nodep->user2u(VNUser{userp});
|
2022-07-05 13:20:37 +00:00
|
|
|
} else if VL_CONSTEXPR_CXX17 (T_UserN == 3) {
|
2022-09-15 23:58:01 +00:00
|
|
|
nodep->user3u(VNUser{userp});
|
2021-06-17 16:27:45 +00:00
|
|
|
} else {
|
2023-10-29 00:12:27 +00:00
|
|
|
nodep->user4u(VNUser{userp});
|
2021-06-17 16:27:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
AstUserAllocatorBase() {
|
2022-07-05 13:20:37 +00:00
|
|
|
if VL_CONSTEXPR_CXX17 (T_UserN == 1) {
|
2022-01-02 18:56:40 +00:00
|
|
|
VNUser1InUse::check();
|
2022-07-05 13:20:37 +00:00
|
|
|
} else if VL_CONSTEXPR_CXX17 (T_UserN == 2) {
|
2022-01-02 18:56:40 +00:00
|
|
|
VNUser2InUse::check();
|
2022-07-05 13:20:37 +00:00
|
|
|
} else if VL_CONSTEXPR_CXX17 (T_UserN == 3) {
|
2022-01-02 18:56:40 +00:00
|
|
|
VNUser3InUse::check();
|
2021-06-17 16:27:45 +00:00
|
|
|
} else {
|
2023-10-29 00:12:27 +00:00
|
|
|
VNUser4InUse::check();
|
2021-06-17 16:27:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-22 11:41:29 +00:00
|
|
|
VL_UNCOPYABLE(AstUserAllocatorBase);
|
|
|
|
|
2021-06-17 16:27:45 +00:00
|
|
|
public:
|
2021-12-17 17:56:33 +00:00
|
|
|
// Get a reference to the user data. If does not exist, construct it with given arguments.
|
2022-08-05 09:56:57 +00:00
|
|
|
template <typename... Args>
|
2021-12-17 17:56:33 +00:00
|
|
|
T_Data& operator()(T_Node* nodep, Args&&... args) {
|
2021-06-17 16:27:45 +00:00
|
|
|
T_Data* userp = getUserp(nodep);
|
|
|
|
if (!userp) {
|
2023-10-28 19:31:52 +00:00
|
|
|
m_allocated.emplace_back(std::forward<Args>(args)...);
|
|
|
|
userp = &m_allocated.back();
|
2021-06-17 16:27:45 +00:00
|
|
|
setUserp(nodep, userp);
|
|
|
|
}
|
|
|
|
return *userp;
|
|
|
|
}
|
Add V3VariableOrder pass
A separate V3VariableOrder pass is now used to order module variables
before Emit. All variables are now ordered together, without
consideration for whether they are ports, signals form the design, or
additional internal variables added by Verilator (which used to be
ordered and emitted as separate groups in Emit). For single threaded
models, this is performance neutral. For multi-threaded models, the
MTask affinity based sorting was slightly modified, so variables with no
MTask affinity are emitted last, otherwise the MTask affinity sets are
sorted using the TSP sorter as before, but again, ports, signals, and
internal variables are not differentiated. This yields a 2%+ speedup for
the multithreaded model on OpenTitan.
2021-06-29 16:57:07 +00:00
|
|
|
|
|
|
|
// Get a reference to the user data
|
2022-05-27 15:57:51 +00:00
|
|
|
T_Data& operator()(const T_Node* nodep) const {
|
2021-11-26 22:55:36 +00:00
|
|
|
T_Data* const userp = getUserp(nodep);
|
Add V3VariableOrder pass
A separate V3VariableOrder pass is now used to order module variables
before Emit. All variables are now ordered together, without
consideration for whether they are ports, signals form the design, or
additional internal variables added by Verilator (which used to be
ordered and emitted as separate groups in Emit). For single threaded
models, this is performance neutral. For multi-threaded models, the
MTask affinity based sorting was slightly modified, so variables with no
MTask affinity are emitted last, otherwise the MTask affinity sets are
sorted using the TSP sorter as before, but again, ports, signals, and
internal variables are not differentiated. This yields a 2%+ speedup for
the multithreaded model on OpenTitan.
2021-06-29 16:57:07 +00:00
|
|
|
UASSERT_OBJ(userp, nodep, "Missing User data on const AstNode");
|
|
|
|
return *userp;
|
|
|
|
}
|
2021-12-17 17:56:33 +00:00
|
|
|
|
|
|
|
// Get a pointer to the user data if exists, otherwise nullptr
|
|
|
|
T_Data* tryGet(const T_Node* nodep) { return getUserp(nodep); }
|
2023-10-29 00:12:27 +00:00
|
|
|
|
|
|
|
void clear() { m_allocated.clear(); }
|
2021-06-17 16:27:45 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// User pointer allocator classes. T_Node is the type of node the allocator should be applied to
|
2022-03-31 00:17:59 +00:00
|
|
|
// and is there for a bit of extra type safety. T_Data is the type of the data structure
|
2021-06-17 16:27:45 +00:00
|
|
|
// managed by the allocator.
|
|
|
|
template <class T_Node, class T_Data>
|
|
|
|
class AstUser1Allocator final : public AstUserAllocatorBase<T_Node, T_Data, 1> {};
|
|
|
|
template <class T_Node, class T_Data>
|
|
|
|
class AstUser2Allocator final : public AstUserAllocatorBase<T_Node, T_Data, 2> {};
|
|
|
|
template <class T_Node, class T_Data>
|
|
|
|
class AstUser3Allocator final : public AstUserAllocatorBase<T_Node, T_Data, 3> {};
|
|
|
|
template <class T_Node, class T_Data>
|
|
|
|
class AstUser4Allocator final : public AstUserAllocatorBase<T_Node, T_Data, 4> {};
|
|
|
|
|
|
|
|
#endif // Guard
|