Merge pull request #411 from antmicro/mglb/UhdmSurelogAstFrontendRTTI

systemverilog: use RTTI for resource management in UhdmSurelogAstFrontend
diff --git a/systemverilog-plugin/tests/Makefile b/systemverilog-plugin/tests/Makefile
index e078fa7..1843a05 100644
--- a/systemverilog-plugin/tests/Makefile
+++ b/systemverilog-plugin/tests/Makefile
@@ -16,10 +16,14 @@
 
 TESTS = counter \
 		break_continue \
-		separate-compilation
+		separate-compilation \
+		debug-flag \
+		report-flag
 
 include $(shell pwd)/../../Makefile_test.common
 
 counter_verify = true
 break_continue_verify = $(call diff_test,break_continue,out)
 separate-compilation_verify = true
+debug-flag_verify = true
+report-flag_verify = true
diff --git a/systemverilog-plugin/tests/debug-flag/debug-flag-buf.sv b/systemverilog-plugin/tests/debug-flag/debug-flag-buf.sv
new file mode 100644
index 0000000..565946b
--- /dev/null
+++ b/systemverilog-plugin/tests/debug-flag/debug-flag-buf.sv
@@ -0,0 +1,21 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// 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.
+//
+// SPDX-License-Identifier: Apache-2.0
+module BUF (
+  input I,
+  output O
+);
+  assign O = I;
+endmodule;
diff --git a/systemverilog-plugin/tests/debug-flag/debug-flag-pkg.sv b/systemverilog-plugin/tests/debug-flag/debug-flag-pkg.sv
new file mode 100644
index 0000000..b0362fc
--- /dev/null
+++ b/systemverilog-plugin/tests/debug-flag/debug-flag-pkg.sv
@@ -0,0 +1,19 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// 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.
+//
+// SPDX-License-Identifier: Apache-2.0
+package pkg;
+  parameter BITS = 4;
+  parameter LOG2DELAY = 22;
+endpackage
diff --git a/systemverilog-plugin/tests/debug-flag/debug-flag.tcl b/systemverilog-plugin/tests/debug-flag/debug-flag.tcl
new file mode 100644
index 0000000..86cfee5
--- /dev/null
+++ b/systemverilog-plugin/tests/debug-flag/debug-flag.tcl
@@ -0,0 +1,16 @@
+yosys -import
+if { [info procs read_uhdm] == {} } { plugin -i systemverilog }
+yosys -import  ;# ingest plugin commands
+
+set TMP_DIR /tmp
+if { [info exists ::env(TMPDIR) ] } {
+  set TMP_DIR $::env(TMPDIR)
+}
+
+# Testing simple round-trip
+read_systemverilog -debug -odir $TMP_DIR/debug-flag-test -defer $::env(DESIGN_TOP)-pkg.sv
+read_systemverilog -debug -odir $TMP_DIR/debug-flag-test -defer $::env(DESIGN_TOP)-buf.sv
+read_systemverilog -debug -odir $TMP_DIR/debug-flag-test -defer $::env(DESIGN_TOP).v
+read_systemverilog -debug -odir $TMP_DIR/debug-flag-test -link
+hierarchy
+write_verilog
diff --git a/systemverilog-plugin/tests/debug-flag/debug-flag.v b/systemverilog-plugin/tests/debug-flag/debug-flag.v
new file mode 100644
index 0000000..5bd294a
--- /dev/null
+++ b/systemverilog-plugin/tests/debug-flag/debug-flag.v
@@ -0,0 +1,31 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// 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.
+//
+// SPDX-License-Identifier: Apache-2.0
+module top (
+  input clk,
+  output [3:0] led
+);
+
+  wire bufg;
+  BUF bufgctrl (
+      .I(clk),
+      .O(bufg)
+  );
+  reg [pkg::BITS + pkg::LOG2DELAY-1 : 0] counter = 0;
+  always @(posedge bufg) begin
+    counter <= counter + 1;
+  end
+  assign led[3:0] = counter >> pkg::LOG2DELAY;
+endmodule
diff --git a/systemverilog-plugin/tests/report-flag/report-flag-buf.sv b/systemverilog-plugin/tests/report-flag/report-flag-buf.sv
new file mode 100644
index 0000000..565946b
--- /dev/null
+++ b/systemverilog-plugin/tests/report-flag/report-flag-buf.sv
@@ -0,0 +1,21 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// 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.
+//
+// SPDX-License-Identifier: Apache-2.0
+module BUF (
+  input I,
+  output O
+);
+  assign O = I;
+endmodule;
diff --git a/systemverilog-plugin/tests/report-flag/report-flag-pkg.sv b/systemverilog-plugin/tests/report-flag/report-flag-pkg.sv
new file mode 100644
index 0000000..b0362fc
--- /dev/null
+++ b/systemverilog-plugin/tests/report-flag/report-flag-pkg.sv
@@ -0,0 +1,19 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// 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.
+//
+// SPDX-License-Identifier: Apache-2.0
+package pkg;
+  parameter BITS = 4;
+  parameter LOG2DELAY = 22;
+endpackage
diff --git a/systemverilog-plugin/tests/report-flag/report-flag.tcl b/systemverilog-plugin/tests/report-flag/report-flag.tcl
new file mode 100644
index 0000000..3a3cc6d
--- /dev/null
+++ b/systemverilog-plugin/tests/report-flag/report-flag.tcl
@@ -0,0 +1,16 @@
+yosys -import
+if { [info procs read_uhdm] == {} } { plugin -i systemverilog }
+yosys -import  ;# ingest plugin commands
+
+set TMP_DIR /tmp
+if { [info exists ::env(TMPDIR) ] } {
+  set TMP_DIR $::env(TMPDIR)
+}
+
+# Testing simple round-trip
+read_systemverilog -report $TMP_DIR/report-flag-test -odir $TMP_DIR/report-flag-test -defer $::env(DESIGN_TOP)-pkg.sv
+read_systemverilog -report $TMP_DIR/report-flag-test -odir $TMP_DIR/report-flag-test -defer $::env(DESIGN_TOP)-buf.sv
+read_systemverilog -report $TMP_DIR/report-flag-test -odir $TMP_DIR/report-flag-test -defer $::env(DESIGN_TOP).v
+read_systemverilog -report $TMP_DIR/report-flag-test -odir $TMP_DIR/report-flag-test -link
+hierarchy
+write_verilog
diff --git a/systemverilog-plugin/tests/report-flag/report-flag.v b/systemverilog-plugin/tests/report-flag/report-flag.v
new file mode 100644
index 0000000..5bd294a
--- /dev/null
+++ b/systemverilog-plugin/tests/report-flag/report-flag.v
@@ -0,0 +1,31 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// 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.
+//
+// SPDX-License-Identifier: Apache-2.0
+module top (
+  input clk,
+  output [3:0] led
+);
+
+  wire bufg;
+  BUF bufgctrl (
+      .I(clk),
+      .O(bufg)
+  );
+  reg [pkg::BITS + pkg::LOG2DELAY-1 : 0] counter = 0;
+  always @(posedge bufg) begin
+    counter <= counter + 1;
+  end
+  assign led[3:0] = counter >> pkg::LOG2DELAY;
+endmodule
diff --git a/systemverilog-plugin/uhdmastfrontend.cc b/systemverilog-plugin/uhdmastfrontend.cc
index 0ee97c0..5925d06 100644
--- a/systemverilog-plugin/uhdmastfrontend.cc
+++ b/systemverilog-plugin/uhdmastfrontend.cc
@@ -50,8 +50,8 @@
         delete synthSubset;
         if (this->shared.debug_flag || !this->report_directory.empty()) {
             for (auto design : restoredDesigns) {
-                std::stringstream strstr;
-                UHDM::visit_object(design, 1, "", &this->shared.report.unhandled, this->shared.debug_flag ? std::cout : strstr);
+                std::ofstream null_stream;
+                UHDM::visit_object(design, 1, "", &this->shared.report.unhandled, this->shared.debug_flag ? std::cout : null_stream);
             }
         }
         UhdmAst uhdm_ast(this->shared);
diff --git a/systemverilog-plugin/uhdmsurelogastfrontend.cc b/systemverilog-plugin/uhdmsurelogastfrontend.cc
index 4f664c7..c11c861 100644
--- a/systemverilog-plugin/uhdmsurelogastfrontend.cc
+++ b/systemverilog-plugin/uhdmsurelogastfrontend.cc
@@ -29,6 +29,7 @@
 #include <sys/param.h>
 #include <unistd.h>
 #endif
+#include <memory>
 
 #include "Surelog/ErrorReporting/Report.h"
 #include "Surelog/surelog.h"
@@ -41,42 +42,66 @@
 
 YOSYS_NAMESPACE_BEGIN
 
-std::vector<vpiHandle> executeCompilation(SURELOG::SymbolTable *symbolTable, SURELOG::ErrorContainer *errors, SURELOG::CommandLineParser *clp,
-                                          SURELOG::scompiler *compiler)
+// SURELOG::scompiler wrapper.
+// Owns UHDM/VPI resources used by designs returned from `execute`
+class Compiler
 {
-    bool success = true;
-    bool noFatalErrors = true;
-    unsigned int codedReturn = 0;
-    clp->setWriteUhdm(false);
-    errors->printMessages(clp->muteStdout());
-    std::vector<vpiHandle> the_design;
-    if (success && (!clp->help())) {
-        compiler = SURELOG::start_compiler(clp);
-        if (!compiler)
+  public:
+    Compiler() = default;
+    ~Compiler()
+    {
+        if (this->scompiler) {
+            SURELOG::shutdown_compiler(this->scompiler);
+        }
+    }
+
+    const std::vector<vpiHandle> &execute(std::unique_ptr<SURELOG::ErrorContainer> errors, std::unique_ptr<SURELOG::CommandLineParser> clp)
+    {
+        log_assert(!this->errors && !this->clp && !this->scompiler);
+
+        bool success = true;
+        bool noFatalErrors = true;
+        unsigned int codedReturn = 0;
+        clp->setWriteUhdm(false);
+        errors->printMessages(clp->muteStdout());
+        if (success && (!clp->help())) {
+            this->scompiler = SURELOG::start_compiler(clp.get());
+            if (!this->scompiler)
+                codedReturn |= 1;
+            this->designs.push_back(SURELOG::get_uhdm_design(this->scompiler));
+        }
+        SURELOG::ErrorContainer::Stats stats;
+        if (!clp->help()) {
+            stats = errors->getErrorStats();
+            if (stats.nbFatal)
+                codedReturn |= 1;
+            if (stats.nbSyntax)
+                codedReturn |= 2;
+        }
+        bool noFErrors = true;
+        if (!clp->help())
+            noFErrors = errors->printStats(stats, clp->muteStdout());
+        if (noFErrors == false) {
+            noFatalErrors = false;
+        }
+        if ((!noFatalErrors) || (!success) || (errors->getErrorStats().nbError))
             codedReturn |= 1;
-        the_design.push_back(SURELOG::get_uhdm_design(compiler));
+        if (codedReturn) {
+            log_error("Error when parsing design. Aborting!\n");
+        }
+
+        this->clp = std::move(clp);
+        this->errors = std::move(errors);
+
+        return this->designs;
     }
-    SURELOG::ErrorContainer::Stats stats;
-    if (!clp->help()) {
-        stats = errors->getErrorStats();
-        if (stats.nbFatal)
-            codedReturn |= 1;
-        if (stats.nbSyntax)
-            codedReturn |= 2;
-    }
-    bool noFErrors = true;
-    if (!clp->help())
-        noFErrors = errors->printStats(stats, clp->muteStdout());
-    if (noFErrors == false) {
-        noFatalErrors = false;
-    }
-    if ((!noFatalErrors) || (!success) || (errors->getErrorStats().nbError))
-        codedReturn |= 1;
-    if (codedReturn) {
-        log_error("Error when parsing design. Aborting!\n");
-    }
-    return the_design;
-}
+
+  private:
+    std::unique_ptr<SURELOG::ErrorContainer> errors = nullptr;
+    std::unique_ptr<SURELOG::CommandLineParser> clp = nullptr;
+    SURELOG::scompiler *scompiler = nullptr;
+    std::vector<vpiHandle> designs = {};
+};
 
 struct UhdmSurelogAstFrontend : public UhdmCommonFrontend {
     UhdmSurelogAstFrontend(std::string name, std::string short_help) : UhdmCommonFrontend(name, short_help) {}
@@ -98,9 +123,9 @@
         for (size_t i = 0; i < this->args.size(); ++i)
             cstrings.push_back(const_cast<char *>(this->args[i].c_str()));
 
-        SURELOG::SymbolTable *symbolTable = new SURELOG::SymbolTable();
-        SURELOG::ErrorContainer *errors = new SURELOG::ErrorContainer(symbolTable);
-        SURELOG::CommandLineParser *clp = new SURELOG::CommandLineParser(errors, symbolTable, false, false);
+        auto symbolTable = std::make_unique<SURELOG::SymbolTable>();
+        auto errors = std::make_unique<SURELOG::ErrorContainer>(symbolTable.get());
+        auto clp = std::make_unique<SURELOG::CommandLineParser>(errors.get(), symbolTable.get(), false, false);
         bool success = clp->parseCommandLine(cstrings.size(), &cstrings[0]);
         if (!success) {
             log_error("Error parsing Surelog arguments!\n");
@@ -122,25 +147,21 @@
             clp->setLink(true);
         }
 
-        SURELOG::scompiler *compiler = nullptr;
-        const std::vector<vpiHandle> uhdm_design = executeCompilation(symbolTable, errors, clp, compiler);
+        Compiler compiler;
+        const auto &uhdm_designs = compiler.execute(std::move(errors), std::move(clp));
+
         if (this->shared.debug_flag || !this->report_directory.empty()) {
-            for (auto design : uhdm_design) {
-                std::stringstream strstr;
-                UHDM::visit_object(design, 1, "", &this->shared.report.unhandled, this->shared.debug_flag ? std::cout : strstr);
+            for (auto design : uhdm_designs) {
+                std::ofstream null_stream;
+                UHDM::visit_object(design, 1, "", &this->shared.report.unhandled, this->shared.debug_flag ? std::cout : null_stream);
             }
         }
 
-        SURELOG::shutdown_compiler(compiler);
-        delete clp;
-        delete symbolTable;
-        delete errors;
         // on parse_only mode, don't try to load design
         // into yosys
         if (this->shared.parse_only)
             return nullptr;
 
-        UhdmAst uhdm_ast(this->shared);
         if (this->shared.defer && !this->shared.link)
             return nullptr;
 
@@ -151,11 +172,12 @@
             UHDM::Serializer serializer;
             UHDM::SynthSubset *synthSubset =
               make_new_object_with_optional_extra_true_arg<UHDM::SynthSubset>(&serializer, this->shared.nonSynthesizableObjects, false);
-            synthSubset->listenDesigns(uhdm_design);
+            synthSubset->listenDesigns(uhdm_designs);
             delete synthSubset;
         }
 
-        AST::AstNode *current_ast = uhdm_ast.visit_designs(uhdm_design);
+        UhdmAst uhdm_ast(this->shared);
+        AST::AstNode *current_ast = uhdm_ast.visit_designs(uhdm_designs);
         if (!this->report_directory.empty()) {
             this->shared.report.write(this->report_directory);
         }