Skip to content

Commit

Permalink
Make the json loader and parser independent from the generated ir files.
Browse files Browse the repository at this point in the history
Signed-off-by: fruffy <[email protected]>
  • Loading branch information
fruffy committed Dec 12, 2024
1 parent 650af7e commit faec211
Show file tree
Hide file tree
Showing 11 changed files with 200 additions and 138 deletions.
46 changes: 1 addition & 45 deletions frontends/common/constantParsing.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ limitations under the License.
#ifndef FRONTENDS_COMMON_CONSTANTPARSING_H_
#define FRONTENDS_COMMON_CONSTANTPARSING_H_

#include "lib/cstring.h"
#include "ir/unparsed_constant.h"

namespace P4::IR {
class Constant;
Expand All @@ -29,50 +29,6 @@ class SourceInfo;

namespace P4 {

/**
* An unparsed numeric constant. We produce these as token values during
* lexing. The parser is responsible for actually interpreting the raw text as a
* numeric value and transforming it into an IR::Constant using parseConstant().
*
* To illustrate how a numeric constant is represented using this struct,
* here is a breakdown of '16w0x12':
*
* ___
* / ___
* | /
* | bitwidth (if @hasWidth) | 16
* | \___
* |
* | ___
* | /
* | separator (if @hasWidth) | w
* | \___
* @text |
* | ___
* | /
* | ignored prefix of length @skip | 0x
* | \___
* |
* | ___
* | /
* | numeric value in base @base | w
* | \___
* \___
*
* Simple numeric constants like '5' are specified by setting @hasWidth to
* false and providing a @skip length of 0.
*/
struct UnparsedConstant {
cstring text; /// Raw P4 text which was recognized as a numeric constant.
unsigned skip; /// An ignored prefix of the numeric constant (e.g. '0x').
unsigned base; /// The base in which the constant is expressed.
bool hasWidth; /// If true, a bitwidth and separator are present.
};

std::ostream &operator<<(std::ostream &out, const UnparsedConstant &constant);

bool operator<(const UnparsedConstant &a, const UnparsedConstant &b);

/**
* Parses an UnparsedConstant @constant into an IR::Constant object, with
* location information taken from @srcInfo. If parsing fails, an IR::Constant
Expand Down
40 changes: 11 additions & 29 deletions ir/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,18 @@
# See the License for the specific language governing permissions and
# limitations under the License.

set (IR_LIB_SRCS
bitrange.cpp
json_parser.cpp
)

add_library (ir_lib STATIC ${IR_LIB_SRCS})
target_link_libraries(ir_lib PRIVATE p4ctoolkit absl::flat_hash_map ${LIBGC_LIBRARIES})


set (IR_SRCS
annotations.cpp
base.cpp
bitrange.cpp
dbprint.cpp
dbprint-expression.cpp
dbprint-stmt.cpp
Expand All @@ -25,41 +33,15 @@ set (IR_SRCS
expression.cpp
ir.cpp
irutils.cpp
json_parser.cpp
loop-visitor.cpp
node.cpp
loop-visitor.cpp
pass_manager.cpp
pass_utils.cpp
type.cpp
visitor.cpp
write_context.cpp
)

set (IR_HDRS
annotations.h
configuration.h
dbprint.h
dump.h
id.h
indexed_vector.h
ir-inline.h
ir-tree-macros.h
ir.h
ir-traversal.h
ir-traversal-internal.h
irutils.h
json_generator.h
json_loader.h
json_parser.h
namemap.h
node.h
nodemap.h
pass_manager.h
pass_utils.h
vector.h
visitor.h
)

set (BASE_IR_DEF_FILES
${CMAKE_CURRENT_SOURCE_DIR}/base.def
${CMAKE_CURRENT_SOURCE_DIR}/type.def
Expand All @@ -70,7 +52,7 @@ set (BASE_IR_DEF_FILES
set (IR_DEF_FILES ${IR_DEF_FILES} ${BASE_IR_DEF_FILES} PARENT_SCOPE)

add_library (ir STATIC ${IR_SRCS})
target_link_libraries(ir PRIVATE absl::flat_hash_map ${LIBGC_LIBRARIES})
target_link_libraries(ir PUBLIC ir_lib PRIVATE absl::flat_hash_map ${LIBGC_LIBRARIES})


add_dependencies(ir genIR)
Expand Down
77 changes: 77 additions & 0 deletions ir/inode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
Copyright 2013-present Barefoot Networks, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#ifndef IR_INODE_H_
#define IR_INODE_H_

#include "lib/castable.h"
#include "lib/cstring.h"
#include "lib/exceptions.h"
#include "lib/rtti.h"
#include "lib/source_file.h"

namespace P4 {
class JSONGenerator;
class JSONLoader;
} // namespace P4

namespace P4::IR {

class Node;

/// SFINAE helper to check if given class has a `static_type_name`
/// method. Definite node classes have them while interfaces do not
template <class, class = void>
struct has_static_type_name : std::false_type {};

template <class T>
struct has_static_type_name<T, std::void_t<decltype(T::static_type_name())>> : std::true_type {};

template <class T>
inline constexpr bool has_static_type_name_v = has_static_type_name<T>::value;

// node interface
class INode : public Util::IHasSourceInfo, public IHasDbPrint, public ICastable {
public:
virtual ~INode() {}
virtual const Node *getNode() const = 0;
virtual Node *getNode() = 0;
virtual void toJSON(JSONGenerator &) const = 0;
virtual cstring node_type_name() const = 0;
virtual void validate() const {}

// default checkedTo implementation for nodes: just fallback to generic ICastable method
template <typename T>
std::enable_if_t<!has_static_type_name_v<T>, const T *> checkedTo() const {
return ICastable::checkedTo<T>();
}

// alternative checkedTo implementation that produces slightly better error message
// due to node_type_name() / static_type_name() being available
template <typename T>
std::enable_if_t<has_static_type_name_v<T>, const T *> checkedTo() const {
const auto *result = to<T>();
BUG_CHECK(result, "Cast failed: %1% with type %2% is not a %3%.", this, node_type_name(),
T::static_type_name());
return result;
}

DECLARE_TYPEINFO(INode);
};

} // namespace P4::IR

#endif /* IR_INODE_H_ */
28 changes: 18 additions & 10 deletions ir/json_loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,14 @@ limitations under the License.
#include <utility>
#include <variant>

#include "ir.h"
#include "ir/id.h"
#include "ir/indexed_vector.h"
#include "ir/inode.h"
#include "ir/json_parser.h"
#include "ir/namemap.h"
#include "ir/unpacker_table.h"
#include "ir/unparsed_constant.h"
#include "ir/vector.h"
#include "json_parser.h"
#include "lib/bitvec.h"
#include "lib/cstring.h"
Expand All @@ -33,6 +40,7 @@ limitations under the License.
#include "lib/ordered_map.h"
#include "lib/ordered_set.h"
#include "lib/safe_vector.h"
#include "lib/string_map.h"

namespace P4 {

Expand All @@ -54,18 +62,18 @@ class JSONLoader {
};

public:
std::unordered_map<int, IR::Node *> &node_refs;
std::unordered_map<int, IR::INode *> &node_refs;
JsonData *json = nullptr;

explicit JSONLoader(std::istream &in)
: node_refs(*(new std::unordered_map<int, IR::Node *>())) {
: node_refs(*(new std::unordered_map<int, IR::INode *>())) {
in >> json;
}

explicit JSONLoader(JsonData *json)
: node_refs(*(new std::unordered_map<int, IR::Node *>())), json(json) {}
: node_refs(*(new std::unordered_map<int, IR::INode *>())), json(json) {}

JSONLoader(JsonData *json, std::unordered_map<int, IR::Node *> &refs)
JSONLoader(JsonData *json, std::unordered_map<int, IR::INode *> &refs)
: node_refs(refs), json(json) {}

JSONLoader(const JSONLoader &unpacker, const std::string &field)
Expand All @@ -74,7 +82,7 @@ class JSONLoader {
}

private:
const IR::Node *get_node() {
const IR::INode *get_node() {
if (!json || !json->is<JsonObject>()) return nullptr; // invalid json exception?
int id = json->as<JsonObject>().get_id();
if (id >= 0) {
Expand All @@ -86,7 +94,7 @@ class JSONLoader {
// when "--fromJSON" flag is used
JsonObject *obj = new JsonObject(json->as<JsonObject>().get_sourceJson());
if (obj->hasSrcInfo() == true) {
node_refs[id]->srcInfo =
node_refs[id]->getSourceInfo() =
Util::SourceInfo(obj->get_filename(), obj->get_line(),
obj->get_column(), obj->get_sourceFragment());
}
Expand Down Expand Up @@ -313,21 +321,21 @@ class JSONLoader {
}

template <typename T>
std::enable_if_t<has_fromJSON<T>::value && !std::is_base_of_v<IR::Node, T> &&
std::enable_if_t<has_fromJSON<T>::value && !std::is_base_of_v<IR::INode, T> &&
std::is_pointer_v<decltype(T::fromJSON(std::declval<JSONLoader &>()))>>
unpack_json(T *&v) {
v = T::fromJSON(*this);
}

template <typename T>
std::enable_if_t<has_fromJSON<T>::value && !std::is_base_of_v<IR::Node, T> &&
std::enable_if_t<has_fromJSON<T>::value && !std::is_base_of_v<IR::INode, T> &&
std::is_pointer_v<decltype(T::fromJSON(std::declval<JSONLoader &>()))>>
unpack_json(T &v) {
v = *(T::fromJSON(*this));
}

template <typename T>
std::enable_if_t<has_fromJSON<T>::value && !std::is_base_of<IR::Node, T>::value &&
std::enable_if_t<has_fromJSON<T>::value && !std::is_base_of<IR::INode, T>::value &&
!std::is_pointer_v<decltype(T::fromJSON(std::declval<JSONLoader &>()))>>
unpack_json(T &v) {
v = T::fromJSON(*this);
Expand Down
1 change: 0 additions & 1 deletion ir/json_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#include <string>
#include <vector>

#include "lib/big_int_util.h"
#include "lib/castable.h"
#include "lib/cstring.h"
#include "lib/ordered_map.h"
Expand Down
45 changes: 2 additions & 43 deletions ir/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@ limitations under the License.

#include <iosfwd>

#include "ir-tree-macros.h"
#include "ir/gen-tree-macro.h"
#include "lib/castable.h"
#include "ir/inode.h"
#include "ir/ir-tree-macros.h"
#include "lib/cstring.h"
#include "lib/exceptions.h"
#include "lib/source_file.h"

namespace P4 {
Expand Down Expand Up @@ -51,46 +50,6 @@ class Vector; // IWYU pragma: keep
template <class T>
class IndexedVector; // IWYU pragma: keep

/// SFINAE helper to check if given class has a `static_type_name`
/// method. Definite node classes have them while interfaces do not
template <class, class = void>
struct has_static_type_name : std::false_type {};

template <class T>
struct has_static_type_name<T, std::void_t<decltype(T::static_type_name())>> : std::true_type {};

template <class T>
inline constexpr bool has_static_type_name_v = has_static_type_name<T>::value;

// node interface
class INode : public Util::IHasSourceInfo, public IHasDbPrint, public ICastable {
public:
virtual ~INode() {}
virtual const Node *getNode() const = 0;
virtual Node *getNode() = 0;
virtual void toJSON(JSONGenerator &) const = 0;
virtual cstring node_type_name() const = 0;
virtual void validate() const {}

// default checkedTo implementation for nodes: just fallback to generic ICastable method
template <typename T>
std::enable_if_t<!has_static_type_name_v<T>, const T *> checkedTo() const {
return ICastable::checkedTo<T>();
}

// alternative checkedTo implementation that produces slightly better error message
// due to node_type_name() / static_type_name() being available
template <typename T>
std::enable_if_t<has_static_type_name_v<T>, const T *> checkedTo() const {
const auto *result = to<T>();
BUG_CHECK(result, "Cast failed: %1% with type %2% is not a %3%.", this, node_type_name(),
T::static_type_name());
return result;
}

DECLARE_TYPEINFO_WITH_TYPEID(INode, NodeKind::INode);
};

class Node : public virtual INode {
public:
virtual bool apply_visitor_preorder(Modifier &v);
Expand Down
18 changes: 18 additions & 0 deletions ir/unpacker_table.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#ifndef IR_UNPACKER_TABLE_H_
#define IR_UNPACKER_TABLE_H_

#include "ir/inode.h"
#include "lib/cstring.h"

namespace P4 {
class JSONLoader;

using NodeFactoryFn = IR::INode *(*)(JSONLoader &);
namespace IR {
extern std::map<cstring, NodeFactoryFn> unpacker_table;

} // namespace IR

} // namespace P4

#endif /* IR_UNPACKER_TABLE_H_ */
Loading

0 comments on commit faec211

Please sign in to comment.