aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchriseth <chris@ethereum.org>2018-12-13 22:26:01 +0800
committerchriseth <chris@ethereum.org>2018-12-13 23:49:04 +0800
commit11209ec48a3581419ebfa4764669c2a128f1b997 (patch)
tree29e6a72de33ebd31dc9f0fc1fab7efa7fdc87dfb
parent633dd44576e267f4728b86ec69a9cc56517a1f89 (diff)
downloaddexon-solidity-11209ec48a3581419ebfa4764669c2a128f1b997.tar.gz
dexon-solidity-11209ec48a3581419ebfa4764669c2a128f1b997.tar.zst
dexon-solidity-11209ec48a3581419ebfa4764669c2a128f1b997.zip
Add variable declaration initializer.
-rw-r--r--libyul/CMakeLists.txt1
-rw-r--r--libyul/optimiser/Suite.cpp2
-rw-r--r--libyul/optimiser/VarDeclInitializer.cpp56
-rw-r--r--libyul/optimiser/VarDeclInitializer.h38
-rw-r--r--test/libyul/YulOptimizerTest.cpp3
-rw-r--r--test/libyul/yulOptimizerTests/varDeclInitializer/ambiguous.yul29
-rw-r--r--test/libyul/yulOptimizerTests/varDeclInitializer/inside_func.yul24
-rw-r--r--test/libyul/yulOptimizerTests/varDeclInitializer/multi.yul14
-rw-r--r--test/libyul/yulOptimizerTests/varDeclInitializer/multi_assign.yul21
-rw-r--r--test/libyul/yulOptimizerTests/varDeclInitializer/simple.yul8
10 files changed, 196 insertions, 0 deletions
diff --git a/libyul/CMakeLists.txt b/libyul/CMakeLists.txt
index 74a5703c..9dee5348 100644
--- a/libyul/CMakeLists.txt
+++ b/libyul/CMakeLists.txt
@@ -44,5 +44,6 @@ add_library(yul
optimiser/UnusedPruner.cpp
optimiser/Utilities.cpp
optimiser/VarDeclPropagator.cpp
+ optimiser/VarDeclInitializer.cpp
)
target_link_libraries(yul PUBLIC evmasm devcore langutil)
diff --git a/libyul/optimiser/Suite.cpp b/libyul/optimiser/Suite.cpp
index ad22bfa3..16df6d3c 100644
--- a/libyul/optimiser/Suite.cpp
+++ b/libyul/optimiser/Suite.cpp
@@ -21,6 +21,7 @@
#include <libyul/optimiser/Suite.h>
#include <libyul/optimiser/Disambiguator.h>
+#include <libyul/optimiser/VarDeclInitializer.h>
#include <libyul/optimiser/FunctionGrouper.h>
#include <libyul/optimiser/FunctionHoister.h>
#include <libyul/optimiser/ExpressionSplitter.h>
@@ -56,6 +57,7 @@ void OptimiserSuite::run(
Block ast = boost::get<Block>(Disambiguator(_analysisInfo, reservedIdentifiers)(_ast));
+ (VarDeclInitializer{})(ast);
(FunctionHoister{})(ast);
(FunctionGrouper{})(ast);
(ForLoopInitRewriter{})(ast);
diff --git a/libyul/optimiser/VarDeclInitializer.cpp b/libyul/optimiser/VarDeclInitializer.cpp
new file mode 100644
index 00000000..4a26757f
--- /dev/null
+++ b/libyul/optimiser/VarDeclInitializer.cpp
@@ -0,0 +1,56 @@
+/*
+ This file is part of solidity.
+
+ solidity is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ solidity is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with solidity. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <libyul/optimiser/VarDeclInitializer.h>
+#include <libyul/AsmData.h>
+
+#include <libdevcore/CommonData.h>
+#include <libdevcore/Visitor.h>
+
+using namespace std;
+using namespace dev;
+using namespace yul;
+
+void VarDeclInitializer::operator()(Block& _block)
+{
+ ASTModifier::operator()(_block);
+
+ static Expression const zero{Literal{{}, LiteralKind::Number, YulString{"0"}, {}}};
+
+ using OptionalStatements = boost::optional<vector<Statement>>;
+ GenericFallbackReturnsVisitor<OptionalStatements, VariableDeclaration> visitor{
+ [](VariableDeclaration& _varDecl) -> OptionalStatements
+ {
+ if (_varDecl.value)
+ return {};
+ else if (_varDecl.variables.size() == 1)
+ {
+ _varDecl.value = make_shared<Expression>(zero);
+ return {};
+ }
+ else
+ {
+ OptionalStatements ret{vector<Statement>{}};
+ langutil::SourceLocation loc{std::move(_varDecl.location)};
+ for (auto& var: _varDecl.variables)
+ ret->push_back(VariableDeclaration{loc, {std::move(var)}, make_shared<Expression>(zero)});
+ return ret;
+ }
+ }
+ };
+ iterateReplacing(_block.statements, boost::apply_visitor(visitor));
+}
diff --git a/libyul/optimiser/VarDeclInitializer.h b/libyul/optimiser/VarDeclInitializer.h
new file mode 100644
index 00000000..41d0917c
--- /dev/null
+++ b/libyul/optimiser/VarDeclInitializer.h
@@ -0,0 +1,38 @@
+/*
+ This file is part of solidity.
+
+ solidity is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ solidity is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with solidity. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <libyul/AsmDataForward.h>
+#include <libyul/optimiser/ASTWalker.h>
+
+namespace yul
+{
+
+/**
+ * Rewrites variable declarations so that all of them are initialized.
+ * Declarations like ``let x, y`` are split into multiple declaration
+ * statements.
+ * Only supports initializing with the zero literal for now.
+ */
+class VarDeclInitializer: public ASTModifier
+{
+public:
+ void operator()(Block& _block) override;
+};
+
+}
diff --git a/test/libyul/YulOptimizerTest.cpp b/test/libyul/YulOptimizerTest.cpp
index 68226e33..68de563d 100644
--- a/test/libyul/YulOptimizerTest.cpp
+++ b/test/libyul/YulOptimizerTest.cpp
@@ -23,6 +23,7 @@
#include <libyul/optimiser/BlockFlattener.h>
#include <libyul/optimiser/VarDeclPropagator.h>
+#include <libyul/optimiser/VarDeclInitializer.h>
#include <libyul/optimiser/Disambiguator.h>
#include <libyul/optimiser/CommonSubexpressionEliminator.h>
#include <libyul/optimiser/NameCollector.h>
@@ -112,6 +113,8 @@ bool YulOptimizerTest::run(ostream& _stream, string const& _linePrefix, bool con
disambiguate();
VarDeclPropagator{}(*m_ast);
}
+ else if (m_optimizerStep == "varDeclInitializer")
+ VarDeclInitializer{}(*m_ast);
else if (m_optimizerStep == "forLoopInitRewriter")
{
disambiguate();
diff --git a/test/libyul/yulOptimizerTests/varDeclInitializer/ambiguous.yul b/test/libyul/yulOptimizerTests/varDeclInitializer/ambiguous.yul
new file mode 100644
index 00000000..5e2d60c2
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/varDeclInitializer/ambiguous.yul
@@ -0,0 +1,29 @@
+{
+ // This component does not need the disambiguator
+ function f() -> x, y {
+ let a, b
+ mstore(a, b)
+ let d
+ d := 2
+ }
+ let a
+ a := 4
+ let b := 2
+ let x, y := f()
+}
+// ----
+// varDeclInitializer
+// {
+// function f() -> x, y
+// {
+// let a := 0
+// let b := 0
+// mstore(a, b)
+// let d := 0
+// d := 2
+// }
+// let a := 0
+// a := 4
+// let b := 2
+// let x, y := f()
+// }
diff --git a/test/libyul/yulOptimizerTests/varDeclInitializer/inside_func.yul b/test/libyul/yulOptimizerTests/varDeclInitializer/inside_func.yul
new file mode 100644
index 00000000..16428d7e
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/varDeclInitializer/inside_func.yul
@@ -0,0 +1,24 @@
+{
+ function f() -> x, y {
+ let a, b
+ mstore(a, b)
+ let d
+ d := 2
+ }
+ let r
+ r := 4
+}
+// ----
+// varDeclInitializer
+// {
+// function f() -> x, y
+// {
+// let a := 0
+// let b := 0
+// mstore(a, b)
+// let d := 0
+// d := 2
+// }
+// let r := 0
+// r := 4
+// }
diff --git a/test/libyul/yulOptimizerTests/varDeclInitializer/multi.yul b/test/libyul/yulOptimizerTests/varDeclInitializer/multi.yul
new file mode 100644
index 00000000..02d731af
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/varDeclInitializer/multi.yul
@@ -0,0 +1,14 @@
+{
+ let x, y, z
+ let a
+ let b
+}
+// ----
+// varDeclInitializer
+// {
+// let x := 0
+// let y := 0
+// let z := 0
+// let a := 0
+// let b := 0
+// }
diff --git a/test/libyul/yulOptimizerTests/varDeclInitializer/multi_assign.yul b/test/libyul/yulOptimizerTests/varDeclInitializer/multi_assign.yul
new file mode 100644
index 00000000..2e14fe70
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/varDeclInitializer/multi_assign.yul
@@ -0,0 +1,21 @@
+{
+ function f() -> x, y {
+ let a, b := f()
+ let u
+ }
+ let r
+ let s := 3
+ let t
+}
+// ----
+// varDeclInitializer
+// {
+// function f() -> x, y
+// {
+// let a, b := f()
+// let u := 0
+// }
+// let r := 0
+// let s := 3
+// let t := 0
+// }
diff --git a/test/libyul/yulOptimizerTests/varDeclInitializer/simple.yul b/test/libyul/yulOptimizerTests/varDeclInitializer/simple.yul
new file mode 100644
index 00000000..2a9bbe42
--- /dev/null
+++ b/test/libyul/yulOptimizerTests/varDeclInitializer/simple.yul
@@ -0,0 +1,8 @@
+{
+ let a
+}
+// ----
+// varDeclInitializer
+// {
+// let a := 0
+// }