diff --git a/frontends/common/constantParsing.h b/frontends/common/constantParsing.h index b2d4c5376ff..37a4a4bfdf7 100644 --- a/frontends/common/constantParsing.h +++ b/frontends/common/constantParsing.h @@ -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; @@ -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 diff --git a/ir/CMakeLists.txt b/ir/CMakeLists.txt index 242f6d104c9..31e31892372 100644 --- a/ir/CMakeLists.txt +++ b/ir/CMakeLists.txt @@ -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 @@ -25,9 +33,8 @@ 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 @@ -35,31 +42,6 @@ set (IR_SRCS 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 @@ -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) diff --git a/ir/declaration.h b/ir/declaration.h index 99a577768a2..7fe7aa2001c 100644 --- a/ir/declaration.h +++ b/ir/declaration.h @@ -18,7 +18,7 @@ limitations under the License. #define IR_DECLARATION_H_ #include "ir/id.h" -#include "ir/node.h" +#include "ir/inode.h" namespace P4::IR { diff --git a/ir/inode.h b/ir/inode.h new file mode 100644 index 00000000000..6f39d1a062a --- /dev/null +++ b/ir/inode.h @@ -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 +struct has_static_type_name : std::false_type {}; + +template +struct has_static_type_name> : std::true_type {}; + +template +inline constexpr bool has_static_type_name_v = has_static_type_name::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 + std::enable_if_t, const T *> checkedTo() const { + return ICastable::checkedTo(); + } + + // alternative checkedTo implementation that produces slightly better error message + // due to node_type_name() / static_type_name() being available + template + std::enable_if_t, const T *> checkedTo() const { + const auto *result = to(); + 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_ */ diff --git a/ir/json_generator.h b/ir/json_generator.h index 68d73d158d5..053520bce6b 100644 --- a/ir/json_generator.h +++ b/ir/json_generator.h @@ -18,11 +18,12 @@ limitations under the License. #define IR_JSON_GENERATOR_H_ #include +#include #include #include #include -#include "ir/node.h" +#include "ir/inode.h" #include "lib/bitvec.h" #include "lib/cstring.h" #include "lib/indent.h" @@ -247,19 +248,19 @@ class JSONGenerator { out << std::endl << --indent << "}"; } - void generate(const IR::Node &v) { - out << "{" << std::endl; - ++indent; - if (node_refs.find(v.id) != node_refs.end()) { - out << indent << "\"Node_ID\" : " << v.id; - } else { - node_refs.insert(v.id); - v.toJSON(*this); - if (dumpSourceInfo) { - v.sourceInfoToJSON(*this); - } - } - out << std::endl << --indent << "}"; + void generate(const IR::INode &v) { + // out << "{" << std::endl; + // ++indent; + // if (node_refs.find(v.id) != node_refs.end()) { + // out << indent << "\"Node_ID\" : " << v.id; + // } else { + // node_refs.insert(v.id); + // v.toJSON(*this); + // if (dumpSourceInfo) { + // v.sourceInfoToJSON(*this); + // } + // } + // out << std::endl << --indent << "}"; } template diff --git a/ir/json_loader.h b/ir/json_loader.h index b8d027b4b55..38514fdb96b 100644 --- a/ir/json_loader.h +++ b/ir/json_loader.h @@ -24,7 +24,14 @@ limitations under the License. #include #include -#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" @@ -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 { @@ -54,18 +62,18 @@ class JSONLoader { }; public: - std::unordered_map &node_refs; + std::unordered_map &node_refs; JsonData *json = nullptr; explicit JSONLoader(std::istream &in) - : node_refs(*(new std::unordered_map())) { + : node_refs(*(new std::unordered_map())) { in >> json; } explicit JSONLoader(JsonData *json) - : node_refs(*(new std::unordered_map())), json(json) {} + : node_refs(*(new std::unordered_map())), json(json) {} - JSONLoader(JsonData *json, std::unordered_map &refs) + JSONLoader(JsonData *json, std::unordered_map &refs) : node_refs(refs), json(json) {} JSONLoader(const JSONLoader &unpacker, const std::string &field) @@ -74,7 +82,7 @@ class JSONLoader { } private: - const IR::Node *get_node() { + const IR::INode *get_node() { if (!json || !json->is()) return nullptr; // invalid json exception? int id = json->as().get_id(); if (id >= 0) { @@ -86,7 +94,7 @@ class JSONLoader { // when "--fromJSON" flag is used JsonObject *obj = new JsonObject(json->as().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()); } @@ -313,21 +321,21 @@ class JSONLoader { } template - std::enable_if_t::value && !std::is_base_of_v && + std::enable_if_t::value && !std::is_base_of_v && std::is_pointer_v()))>> unpack_json(T *&v) { v = T::fromJSON(*this); } template - std::enable_if_t::value && !std::is_base_of_v && + std::enable_if_t::value && !std::is_base_of_v && std::is_pointer_v()))>> unpack_json(T &v) { v = *(T::fromJSON(*this)); } template - std::enable_if_t::value && !std::is_base_of::value && + std::enable_if_t::value && !std::is_base_of::value && !std::is_pointer_v()))>> unpack_json(T &v) { v = T::fromJSON(*this); diff --git a/ir/json_parser.h b/ir/json_parser.h index 073caca78e4..54102b3f879 100644 --- a/ir/json_parser.h +++ b/ir/json_parser.h @@ -5,7 +5,6 @@ #include #include -#include "lib/big_int_util.h" #include "lib/castable.h" #include "lib/cstring.h" #include "lib/ordered_map.h" diff --git a/ir/node.cpp b/ir/node.cpp index 0046acff2aa..44d5d6903b1 100644 --- a/ir/node.cpp +++ b/ir/node.cpp @@ -100,8 +100,7 @@ cstring IR::Node::prepareSourceInfoForJSON(Util::SourceInfo &si, unsigned *lineN if (!si.isValid()) { return nullptr; } - if (is()) { - auto assign = to(); + if (auto assign = to()) { si = (assign->left->srcInfo + si) + assign->right->srcInfo; } return si.toSourcePositionData(lineNumber, columnNumber); diff --git a/ir/node.h b/ir/node.h index 53e5eab1b10..027920a075e 100644 --- a/ir/node.h +++ b/ir/node.h @@ -19,11 +19,10 @@ limitations under the License. #include -#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 { @@ -51,46 +50,6 @@ class Vector; // IWYU pragma: keep template 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 -struct has_static_type_name : std::false_type {}; - -template -struct has_static_type_name> : std::true_type {}; - -template -inline constexpr bool has_static_type_name_v = has_static_type_name::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 - std::enable_if_t, const T *> checkedTo() const { - return ICastable::checkedTo(); - } - - // alternative checkedTo implementation that produces slightly better error message - // due to node_type_name() / static_type_name() being available - template - std::enable_if_t, const T *> checkedTo() const { - const auto *result = to(); - 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); diff --git a/ir/unpacker_table.h b/ir/unpacker_table.h new file mode 100644 index 00000000000..1c88aea176b --- /dev/null +++ b/ir/unpacker_table.h @@ -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 unpacker_table; + +} // namespace IR + +} // namespace P4 + +#endif /* IR_UNPACKER_TABLE_H_ */ diff --git a/ir/unparsed_constant.h b/ir/unparsed_constant.h new file mode 100644 index 00000000000..b5adaf871d1 --- /dev/null +++ b/ir/unparsed_constant.h @@ -0,0 +1,70 @@ +/* +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_UNPARSED_CONSTANT_H_ +#define IR_UNPARSED_CONSTANT_H_ + +#include "lib/cstring.h" + +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); + +} // namespace P4 + +#endif /* IR_UNPARSED_CONSTANT_H_ */ diff --git a/ir/visitor.cpp b/ir/visitor.cpp index 4224c25c176..754d8370323 100644 --- a/ir/visitor.cpp +++ b/ir/visitor.cpp @@ -23,7 +23,6 @@ limitations under the License. #include "absl/container/flat_hash_map.h" #include "absl/time/clock.h" #include "absl/time/time.h" -#include "ir/ir-generated.h" #include "lib/hash.h" #if HAVE_CXXABI_H @@ -34,15 +33,12 @@ limitations under the License. #include #endif -#include "dbprint.h" -#include "ir/id.h" -#include "ir/ir.h" +#include "ir/dbprint.h" #include "ir/vector.h" #include "lib/algorithm.h" #include "lib/error_catalog.h" #include "lib/indent.h" #include "lib/log.h" -#include "lib/map.h" namespace P4 { diff --git a/ir/visitor.h b/ir/visitor.h index 30d39addeec..6b08eeb46a2 100644 --- a/ir/visitor.h +++ b/ir/visitor.h @@ -19,18 +19,15 @@ limitations under the License. #include #include -#include #include #include #include #include #include #include -#include #include #include "absl/time/time.h" -#include "ir/gen-tree-macro.h" #include "ir/ir-tree-macros.h" #include "ir/node.h" #include "ir/vector.h" diff --git a/tools/ir-generator/irclass.cpp b/tools/ir-generator/irclass.cpp index 013ca5d48dd..59e1449facd 100644 --- a/tools/ir-generator/irclass.cpp +++ b/tools/ir-generator/irclass.cpp @@ -131,16 +131,16 @@ void IrDefinitions::generate(std::ostream &t, std::ostream &out, std::ostream &i << "#include \"ir/namemap.h\" // IWYU pragma: keep\n" << "#include \"ir/node.h\" // IWYU pragma: keep\n" << "#include \"ir/nodemap.h\" // IWYU pragma: keep\n" + << "#include \"ir/unpacker_table.h\" // IWYU pragma: keep\n" << "#include \"ir/vector.h\" // IWYU pragma: keep\n" << "#include \"lib/ordered_map.h\" // IWYU pragma: keep\n" << std::endl << "namespace P4 {\n" << std::endl << "class JSONLoader;\n" - << "using NodeFactoryFn = IR::Node*(*)(JSONLoader&);\n" + << "using NodeFactoryFn = IR::INode*(*)(JSONLoader&);\n" << std::endl << "namespace IR {\n" - << "extern std::map unpacker_table;\n" << "using namespace P4::literals;\n" << "}\n";