Modify parser and optimizer.

This commit is contained in:
chriseth
2019-05-20 17:32:56 +02:00
parent 46d9df7574
commit 1dc15d5864
20 changed files with 117 additions and 61 deletions
+2 -2
View File
@@ -1,4 +1,4 @@
Warning: Yul and its optimizer are still experimental. Please use the output with care.
strict_asm_jump/input.sol:1:3: Error: Jump instructions and labels are low-level EVM features that can lead to incorrect stack access. Because of that they are disallowed in strict assembly. Use functions, "switch", "if" or "for" statements instead.
strict_asm_jump/input.sol:1:3: Error: Function not found.
{ jump(1) }
^-----^
^--^
+5 -2
View File
@@ -549,8 +549,11 @@ BOOST_AUTO_TEST_CASE(builtins_parser)
SimpleDialect dialect;
CHECK_ERROR_DIALECT("{ let builtin := 6 }", ParserError, "Cannot use builtin function name \"builtin\" as identifier name.", dialect);
CHECK_ERROR_DIALECT("{ function builtin() {} }", ParserError, "Cannot use builtin function name \"builtin\" as identifier name.", dialect);
CHECK_ERROR_DIALECT("{ builtin := 6 }", ParserError, "Cannot assign to builtin function \"builtin\".", dialect);
CHECK_ERROR_DIALECT("{ function g() -> a,b {} builtin, builtin2 := g() }", ParserError, "Cannot assign to builtin function \"builtin\".", dialect);
CHECK_ERROR_DIALECT("{ builtin := 6 }", ParserError, "Expected '(' but got ':='", dialect);
CHECK_ERROR_DIALECT("{ function f(x) { f(builtin) } }", ParserError, "Expected '(' but got ')'", dialect);
CHECK_ERROR_DIALECT("{ function f(builtin) {}", ParserError, "Cannot use builtin function name \"builtin\" as identifier name.", dialect);
CHECK_ERROR_DIALECT("{ function f() -> builtin {}", ParserError, "Cannot use builtin function name \"builtin\" as identifier name.", dialect);
CHECK_ERROR_DIALECT("{ function g() -> a,b {} builtin, builtin2 := g() }", ParserError, "Expected '(' but got ','", dialect);
}
BOOST_AUTO_TEST_CASE(builtins_analysis)
+3 -3
View File
@@ -201,7 +201,7 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
CommonSubexpressionEliminator{*m_dialect}(*m_ast);
ExpressionSimplifier::run(*m_dialect, *m_ast);
UnusedPruner::runUntilStabilised(*m_dialect, *m_ast);
DeadCodeEliminator{}(*m_ast);
DeadCodeEliminator{*m_dialect}(*m_ast);
ExpressionJoiner::run(*m_ast);
ExpressionJoiner::run(*m_ast);
}
@@ -214,7 +214,7 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
{
disambiguate();
ForLoopInitRewriter{}(*m_ast);
DeadCodeEliminator{}(*m_ast);
DeadCodeEliminator{*m_dialect}(*m_ast);
}
else if (m_optimizerStep == "ssaTransform")
{
@@ -237,7 +237,7 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
else if (m_optimizerStep == "controlFlowSimplifier")
{
disambiguate();
ControlFlowSimplifier{}(*m_ast);
ControlFlowSimplifier{*m_dialect}(*m_ast);
}
else if (m_optimizerStep == "structuralSimplifier")
{
@@ -22,6 +22,7 @@
#include <test/tools/yulInterpreter/Interpreter.h>
#include <libyul/backends/evm/EVMDialect.h>
#include <libyul/AsmData.h>
#include <libevmasm/Instruction.h>
@@ -444,13 +445,15 @@ u256 EVMInstructionInterpreter::eval(
return 0;
}
u256 EVMInstructionInterpreter::evalBuiltin(YulString _name, const std::vector<u256>& _arguments)
u256 EVMInstructionInterpreter::evalBuiltin(BuiltinFunctionForEVM const& _fun, const std::vector<u256>& _arguments)
{
if (_name == "datasize"_yulstring)
if (_fun.instruction)
return eval(*_fun.instruction, _arguments);
else if (_fun.name == "datasize"_yulstring)
return u256(keccak256(h256(_arguments.at(0)))) & 0xfff;
else if (_name == "dataoffset"_yulstring)
else if (_fun.name == "dataoffset"_yulstring)
return u256(keccak256(h256(_arguments.at(0) + 2))) & 0xfff;
else if (_name == "datacopy"_yulstring)
else if (_fun.name == "datacopy"_yulstring)
{
// This is identical to codecopy.
if (logMemoryWrite(_arguments.at(0), _arguments.at(2)))
@@ -463,7 +466,7 @@ u256 EVMInstructionInterpreter::evalBuiltin(YulString _name, const std::vector<u
);
}
else
yulAssert(false, "Unknown builtin: " + _name.str());
yulAssert(false, "Unknown builtin: " + _fun.name.str());
return 0;
}
@@ -37,6 +37,8 @@ enum class Instruction: uint8_t;
namespace yul
{
class YulString;
struct BuiltinFunctionForEVM;
namespace test
{
@@ -70,7 +72,7 @@ public:
/// Evaluate instruction
dev::u256 eval(dev::eth::Instruction _instruction, std::vector<dev::u256> const& _arguments);
/// Evaluate builtin function
dev::u256 evalBuiltin(YulString _name, std::vector<dev::u256> const& _arguments);
dev::u256 evalBuiltin(BuiltinFunctionForEVM const& _fun, std::vector<dev::u256> const& _arguments);
private:
/// Record a memory read in the trace. Also updates m_state.msize
+7 -6
View File
@@ -208,12 +208,13 @@ void ExpressionEvaluator::operator()(FunctionCall const& _funCall)
{
evaluateArgs(_funCall.arguments);
if (dynamic_cast<EVMDialect const*>(&m_dialect) && m_dialect.builtin(_funCall.functionName.name))
{
EVMInstructionInterpreter interpreter(m_state);
setValue(interpreter.evalBuiltin(_funCall.functionName.name, values()));
return;
}
if (EVMDialect const* dialect = dynamic_cast<EVMDialect const*>(&m_dialect))
if (BuiltinFunctionForEVM const* fun = dialect->builtin(_funCall.functionName.name))
{
EVMInstructionInterpreter interpreter(m_state);
setValue(interpreter.evalBuiltin(*fun, values()));
return;
}
solAssert(m_functions.count(_funCall.functionName.name), "");
FunctionDefinition const& fun = *m_functions.at(_funCall.functionName.name);
+2 -2
View File
@@ -179,13 +179,13 @@ public:
(StructuralSimplifier{m_dialect})(*m_ast);
break;
case 'n':
(ControlFlowSimplifier{})(*m_ast);
(ControlFlowSimplifier{m_dialect})(*m_ast);
break;
case 'u':
UnusedPruner::runUntilStabilised(m_dialect, *m_ast);
break;
case 'D':
DeadCodeEliminator{}(*m_ast);
DeadCodeEliminator{m_dialect}(*m_ast);
break;
case 'a':
SSATransform::run(*m_ast, *m_nameDispenser);