mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Extract StackReuseCodegen tests.
This commit is contained in:
parent
1d95f95635
commit
e99da7e015
@ -353,18 +353,19 @@ void solidity::evmasm::eachInstruction(
|
||||
}
|
||||
}
|
||||
|
||||
string solidity::evmasm::disassemble(bytes const& _mem)
|
||||
string solidity::evmasm::disassemble(bytes const& _mem, string const& _delimiter)
|
||||
{
|
||||
stringstream ret;
|
||||
eachInstruction(_mem, [&](Instruction _instr, u256 const& _data) {
|
||||
if (!isValidInstruction(_instr))
|
||||
ret << "0x" << std::uppercase << std::hex << static_cast<int>(_instr) << " ";
|
||||
ret << "0x" << std::uppercase << std::hex << static_cast<int>(_instr) << _delimiter;
|
||||
else
|
||||
{
|
||||
InstructionInfo info = instructionInfo(_instr);
|
||||
ret << info.name << " ";
|
||||
ret << info.name;
|
||||
if (info.additional)
|
||||
ret << "0x" << std::uppercase << std::hex << _data << " ";
|
||||
ret << " 0x" << std::uppercase << std::hex << _data;
|
||||
ret << _delimiter;
|
||||
}
|
||||
});
|
||||
return ret.str();
|
||||
|
@ -314,6 +314,6 @@ extern const std::map<std::string, Instruction> c_instructions;
|
||||
void eachInstruction(bytes const& _mem, std::function<void(Instruction,u256 const&)> const& _onInstruction);
|
||||
|
||||
/// Convert from EVM code to simple EVM assembly language.
|
||||
std::string disassemble(bytes const& _mem);
|
||||
std::string disassemble(bytes const& _mem, std::string const& _delimiter = " ");
|
||||
|
||||
}
|
||||
|
@ -121,6 +121,8 @@ set(libyul_sources
|
||||
libyul/Common.cpp
|
||||
libyul/Common.h
|
||||
libyul/CompilabilityChecker.cpp
|
||||
libyul/EVMCodeTransformTest.cpp
|
||||
libyul/EVMCodeTransformTest.h
|
||||
libyul/EwasmTranslationTest.cpp
|
||||
libyul/EwasmTranslationTest.h
|
||||
libyul/FunctionSideEffects.cpp
|
||||
@ -131,7 +133,6 @@ set(libyul_sources
|
||||
libyul/ObjectCompilerTest.h
|
||||
libyul/ObjectParser.cpp
|
||||
libyul/Parser.cpp
|
||||
libyul/StackReuseCodegen.cpp
|
||||
libyul/SyntaxTest.h
|
||||
libyul/SyntaxTest.cpp
|
||||
libyul/YulInterpreterTest.cpp
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <test/libsolidity/SyntaxTest.h>
|
||||
#include <test/libsolidity/SemanticTest.h>
|
||||
#include <test/libsolidity/SMTCheckerTest.h>
|
||||
#include <test/libyul/EVMCodeTransformTest.h>
|
||||
#include <test/libyul/EwasmTranslationTest.h>
|
||||
#include <test/libyul/YulOptimizerTest.h>
|
||||
#include <test/libyul/YulInterpreterTest.h>
|
||||
@ -60,6 +61,7 @@ Testsuite const g_interactiveTestsuites[] = {
|
||||
{"Yul Object Compiler", "libyul", "objectCompiler", false, false, &yul::test::ObjectCompilerTest::create},
|
||||
{"Function Side Effects","libyul", "functionSideEffects", false, false, &yul::test::FunctionSideEffects::create},
|
||||
{"Yul Syntax", "libyul", "yulSyntaxTests", false, false, &yul::test::SyntaxTest::create},
|
||||
{"EVM Code Transform", "libyul", "evmCodeTransform", false, false, &yul::test::EVMCodeTransformTest::create, {"nooptions"}},
|
||||
{"Syntax", "libsolidity", "syntaxTests", false, false, &SyntaxTest::create},
|
||||
{"Error Recovery", "libsolidity", "errorRecoveryTests", false, false, &SyntaxTest::createErrorRecovery},
|
||||
{"Semantic", "libsolidity", "semanticTests", false, true, &SemanticTest::create},
|
||||
|
63
test/libyul/EVMCodeTransformTest.cpp
Normal file
63
test/libyul/EVMCodeTransformTest.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
|
||||
#include <test/libyul/EVMCodeTransformTest.h>
|
||||
#include <test/libyul/Common.h>
|
||||
|
||||
#include <libyul/AssemblyStack.h>
|
||||
|
||||
#include <liblangutil/SourceReferenceFormatter.h>
|
||||
|
||||
#include <libsolutil/AnsiColorized.h>
|
||||
|
||||
using namespace solidity;
|
||||
using namespace solidity::util;
|
||||
using namespace solidity::langutil;
|
||||
using namespace solidity::yul;
|
||||
using namespace solidity::yul::test;
|
||||
using namespace solidity::frontend;
|
||||
using namespace solidity::frontend::test;
|
||||
using namespace std;
|
||||
|
||||
EVMCodeTransformTest::EVMCodeTransformTest(string const& _filename):
|
||||
TestCase(_filename)
|
||||
{
|
||||
m_source = m_reader.source();
|
||||
m_stackOpt = m_reader.boolSetting("stackOptimization", false);
|
||||
m_expectation = m_reader.simpleExpectations();
|
||||
}
|
||||
|
||||
TestCase::TestResult EVMCodeTransformTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted)
|
||||
{
|
||||
solidity::frontend::OptimiserSettings settings = solidity::frontend::OptimiserSettings::full();
|
||||
settings.runYulOptimiser = false;
|
||||
settings.optimizeStackAllocation = m_stackOpt;
|
||||
AssemblyStack stack(EVMVersion{}, AssemblyStack::Language::StrictAssembly, settings);
|
||||
if (!stack.parseAndAnalyze("", m_source))
|
||||
{
|
||||
AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << endl;
|
||||
SourceReferenceFormatter formatter(_stream, true, false);
|
||||
for (auto const& error: stack.errors())
|
||||
formatter.printErrorInformation(*error);
|
||||
return TestResult::FatalError;
|
||||
}
|
||||
|
||||
m_obtainedResult = evmasm::disassemble(stack.assemble(AssemblyStack::Machine::EVM).bytecode->bytecode, "\n");
|
||||
|
||||
return checkResult(_stream, _linePrefix, _formatted);
|
||||
}
|
39
test/libyul/EVMCodeTransformTest.h
Normal file
39
test/libyul/EVMCodeTransformTest.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <test/TestCase.h>
|
||||
|
||||
namespace solidity::yul::test
|
||||
{
|
||||
|
||||
class EVMCodeTransformTest: public solidity::frontend::test::TestCase
|
||||
{
|
||||
public:
|
||||
static std::unique_ptr<TestCase> create(Config const& _config)
|
||||
{
|
||||
return std::make_unique<EVMCodeTransformTest>(_config.filename);
|
||||
}
|
||||
explicit EVMCodeTransformTest(std::string const& _filename);
|
||||
TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override;
|
||||
private:
|
||||
bool m_stackOpt = false;
|
||||
};
|
||||
|
||||
}
|
@ -1,414 +0,0 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
/**
|
||||
* Unit tests for stack-reusing code generator.
|
||||
*/
|
||||
|
||||
#include <test/Common.h>
|
||||
|
||||
#include <libyul/AssemblyStack.h>
|
||||
#include <libevmasm/Instruction.h>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace solidity::yul::test
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
string assemble(string const& _input)
|
||||
{
|
||||
solidity::frontend::OptimiserSettings settings = solidity::frontend::OptimiserSettings::full();
|
||||
settings.runYulOptimiser = false;
|
||||
settings.optimizeStackAllocation = true;
|
||||
AssemblyStack asmStack(langutil::EVMVersion{}, AssemblyStack::Language::StrictAssembly, settings);
|
||||
BOOST_REQUIRE_MESSAGE(asmStack.parseAndAnalyze("", _input), "Source did not parse: " + _input);
|
||||
return evmasm::disassemble(asmStack.assemble(AssemblyStack::Machine::EVM).bytecode->bytecode);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(StackReuseCodegen, *boost::unit_test::label("nooptions"))
|
||||
|
||||
BOOST_AUTO_TEST_CASE(smoke_test)
|
||||
{
|
||||
string out = assemble("{}");
|
||||
BOOST_CHECK_EQUAL(out, "");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(single_var)
|
||||
{
|
||||
string out = assemble("{ let x }");
|
||||
BOOST_CHECK_EQUAL(out, "PUSH1 0x0 POP ");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(single_var_assigned)
|
||||
{
|
||||
string out = assemble("{ let x := 1 }");
|
||||
BOOST_CHECK_EQUAL(out, "PUSH1 0x1 POP ");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(single_var_assigned_plus_code)
|
||||
{
|
||||
string out = assemble("{ let x := 1 mstore(3, 4) }");
|
||||
BOOST_CHECK_EQUAL(out, "PUSH1 0x1 POP PUSH1 0x4 PUSH1 0x3 MSTORE ");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(single_var_assigned_plus_code_and_reused)
|
||||
{
|
||||
string out = assemble("{ let x := 1 mstore(3, 4) pop(mload(x)) }");
|
||||
BOOST_CHECK_EQUAL(out, "PUSH1 0x1 PUSH1 0x4 PUSH1 0x3 MSTORE DUP1 MLOAD POP POP ");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(multi_reuse_single_slot)
|
||||
{
|
||||
string out = assemble("{ let x := 1 x := 6 let y := 2 y := 4 }");
|
||||
BOOST_CHECK_EQUAL(out, "PUSH1 0x1 PUSH1 0x6 SWAP1 POP POP PUSH1 0x2 PUSH1 0x4 SWAP1 POP POP ");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(multi_reuse_single_slot_nested)
|
||||
{
|
||||
string out = assemble("{ let x := 1 x := 6 { let y := 2 y := 4 } }");
|
||||
BOOST_CHECK_EQUAL(out, "PUSH1 0x1 PUSH1 0x6 SWAP1 POP POP PUSH1 0x2 PUSH1 0x4 SWAP1 POP POP ");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(multi_reuse_same_variable_name)
|
||||
{
|
||||
string out = assemble("{ let z := mload(0) { let x := 1 x := 6 z := x } { let x := 2 z := x x := 4 } }");
|
||||
BOOST_CHECK_EQUAL(out,
|
||||
"PUSH1 0x0 MLOAD "
|
||||
"PUSH1 0x1 PUSH1 0x6 SWAP1 POP DUP1 SWAP2 POP POP "
|
||||
"PUSH1 0x2 DUP1 SWAP2 POP PUSH1 0x4 SWAP1 POP POP "
|
||||
"POP "
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(last_use_in_nested_block)
|
||||
{
|
||||
string out = assemble("{ let z := 0 { pop(z) } let x := 1 }");
|
||||
BOOST_CHECK_EQUAL(out, "PUSH1 0x0 DUP1 POP POP PUSH1 0x1 POP ");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(if_)
|
||||
{
|
||||
// z is only removed after the if (after the jumpdest)
|
||||
string out = assemble("{ let z := mload(0) if z { let x := z } let t := 3 }");
|
||||
BOOST_CHECK_EQUAL(out, "PUSH1 0x0 MLOAD DUP1 ISZERO PUSH1 0xA JUMPI DUP1 POP JUMPDEST POP PUSH1 0x3 POP ");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(switch_)
|
||||
{
|
||||
string out = assemble("{ let z := 0 switch z case 0 { let x := 2 let y := 3 } default { z := 3 } let t := 9 }");
|
||||
BOOST_CHECK_EQUAL(out,
|
||||
"PUSH1 0x0 DUP1 "
|
||||
"PUSH1 0x0 DUP2 EQ PUSH1 0x11 JUMPI "
|
||||
"PUSH1 0x3 SWAP2 POP PUSH1 0x18 JUMP "
|
||||
"JUMPDEST PUSH1 0x2 POP PUSH1 0x3 POP "
|
||||
"JUMPDEST POP POP " // This is where z and its copy (switch condition) can be removed.
|
||||
"PUSH1 0x9 POP "
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(reuse_slots)
|
||||
{
|
||||
// x and y should reuse the slots of b and d
|
||||
string out = assemble("{ let a, b, c, d let x := 2 let y := 3 mstore(x, a) mstore(y, c) }");
|
||||
BOOST_CHECK_EQUAL(out,
|
||||
"PUSH1 0x0 PUSH1 0x0 PUSH1 0x0 PUSH1 0x0 "
|
||||
"POP " // d is removed right away
|
||||
"PUSH1 0x2 SWAP2 POP " // x is stored at b's slot
|
||||
"PUSH1 0x3 DUP4 DUP4 MSTORE "
|
||||
"DUP2 DUP2 MSTORE "
|
||||
"POP POP POP POP "
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(for_1)
|
||||
{
|
||||
// Special scoping rules, but can remove z early
|
||||
string out = assemble("{ for { let z := 0 } 1 { } { let x := 3 } let t := 2 }");
|
||||
BOOST_CHECK_EQUAL(out,
|
||||
"PUSH1 0x0 POP "
|
||||
"JUMPDEST PUSH1 0x1 ISZERO PUSH1 0x11 JUMPI "
|
||||
"PUSH1 0x3 POP JUMPDEST PUSH1 0x3 JUMP "
|
||||
"JUMPDEST PUSH1 0x2 POP "
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(for_2)
|
||||
{
|
||||
// Special scoping rules, cannot remove z until after the loop!
|
||||
string out = assemble("{ for { let z := 0 } 1 { } { z := 8 let x := 3 } let t := 2 }");
|
||||
BOOST_CHECK_EQUAL(out,
|
||||
"PUSH1 0x0 "
|
||||
"JUMPDEST PUSH1 0x1 ISZERO PUSH1 0x14 JUMPI "
|
||||
"PUSH1 0x8 SWAP1 POP "
|
||||
"PUSH1 0x3 POP "
|
||||
"JUMPDEST PUSH1 0x2 JUMP "
|
||||
"JUMPDEST POP " // z is removed
|
||||
"PUSH1 0x2 POP "
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_trivial)
|
||||
{
|
||||
string in = R"({
|
||||
function f() { }
|
||||
})";
|
||||
BOOST_CHECK_EQUAL(assemble(in),
|
||||
"PUSH1 0x6 JUMP JUMPDEST JUMPDEST JUMP JUMPDEST "
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_retparam)
|
||||
{
|
||||
string in = R"({
|
||||
function f() -> x, y { }
|
||||
})";
|
||||
BOOST_CHECK_EQUAL(assemble(in),
|
||||
"PUSH1 0xC JUMP "
|
||||
"JUMPDEST PUSH1 0x0 PUSH1 0x0 JUMPDEST SWAP1 SWAP2 JUMP "
|
||||
"JUMPDEST "
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_params)
|
||||
{
|
||||
string in = R"({
|
||||
function f(a, b) { }
|
||||
})";
|
||||
BOOST_CHECK_EQUAL(assemble(in), "PUSH1 0x8 JUMP JUMPDEST JUMPDEST POP POP JUMP JUMPDEST ");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_params_and_retparams)
|
||||
{
|
||||
string in = R"({
|
||||
function f(a, b, c, d) -> x, y { }
|
||||
})";
|
||||
// This does not re-use the parameters for the return parameters
|
||||
// We do not expect parameters to be fully unused, so the stack
|
||||
// layout for a function is still fixed, even though parameters
|
||||
// can be re-used.
|
||||
BOOST_CHECK_EQUAL(assemble(in),
|
||||
"PUSH1 0x11 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x0 JUMPDEST SWAP5 POP SWAP5 SWAP3 POP POP POP JUMP JUMPDEST "
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_params_and_retparams_partly_unused)
|
||||
{
|
||||
string in = R"({
|
||||
function f(a, b, c, d) -> x, y { b := 3 let s := 9 y := 2 mstore(s, y) }
|
||||
})";
|
||||
BOOST_CHECK_EQUAL(assemble(in),
|
||||
"PUSH1 0x1F JUMP "
|
||||
"JUMPDEST PUSH1 0x0 PUSH1 0x0 "
|
||||
"PUSH1 0x3 SWAP4 POP "
|
||||
"PUSH1 0x9 PUSH1 0x2 SWAP2 POP "
|
||||
"DUP2 DUP2 MSTORE "
|
||||
"POP JUMPDEST SWAP5 POP SWAP5 SWAP3 POP POP POP JUMP "
|
||||
"JUMPDEST "
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_with_body_embedded)
|
||||
{
|
||||
string in = R"({
|
||||
let b := 3
|
||||
function f(a, r) -> t {
|
||||
// r could be removed right away, but a cannot - this is not implemented, though
|
||||
let x := a a := 3 t := a
|
||||
}
|
||||
b := 7
|
||||
})";
|
||||
BOOST_CHECK_EQUAL(assemble(in),
|
||||
"PUSH1 0x3 PUSH1 "
|
||||
"0x17 JUMP "
|
||||
"JUMPDEST PUSH1 0x0 " // start of f, initialize t
|
||||
"DUP2 POP " // let x := a
|
||||
"PUSH1 0x3 SWAP2 POP "
|
||||
"DUP2 SWAP1 POP "
|
||||
"JUMPDEST SWAP3 SWAP2 POP POP JUMP "
|
||||
"JUMPDEST PUSH1 0x7 SWAP1 "
|
||||
"POP POP "
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_call)
|
||||
{
|
||||
string in = R"({
|
||||
let b := f(1, 2)
|
||||
function f(a, r) -> t { }
|
||||
b := f(3, 4)
|
||||
})";
|
||||
BOOST_CHECK_EQUAL(assemble(in),
|
||||
"PUSH1 0x9 PUSH1 0x2 PUSH1 0x1 PUSH1 0xD JUMP "
|
||||
"JUMPDEST PUSH1 0x16 JUMP " // jump over f
|
||||
"JUMPDEST PUSH1 0x0 JUMPDEST SWAP3 SWAP2 POP POP JUMP " // f
|
||||
"JUMPDEST PUSH1 0x20 PUSH1 0x4 PUSH1 0x3 PUSH1 0xD JUMP "
|
||||
"JUMPDEST SWAP1 POP POP "
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(functions_multi_return)
|
||||
{
|
||||
string in = R"({
|
||||
function f(a, b) -> t { }
|
||||
function g() -> r, s { }
|
||||
let x := f(1, 2)
|
||||
x := f(3, 4)
|
||||
let y, z := g()
|
||||
y, z := g()
|
||||
let unused := 7
|
||||
})";
|
||||
BOOST_CHECK_EQUAL(assemble(in),
|
||||
"PUSH1 0x15 JUMP "
|
||||
"JUMPDEST PUSH1 0x0 JUMPDEST SWAP3 SWAP2 POP POP JUMP " // f
|
||||
"JUMPDEST PUSH1 0x0 PUSH1 0x0 JUMPDEST SWAP1 SWAP2 JUMP " // g
|
||||
"JUMPDEST PUSH1 0x1F PUSH1 0x2 PUSH1 0x1 PUSH1 0x3 JUMP " // f(1, 2)
|
||||
"JUMPDEST PUSH1 0x29 PUSH1 0x4 PUSH1 0x3 PUSH1 0x3 JUMP " // f(3, 4)
|
||||
"JUMPDEST SWAP1 POP " // assignment to x
|
||||
"POP " // remove x
|
||||
"PUSH1 0x32 PUSH1 0xC JUMP " // g()
|
||||
"JUMPDEST PUSH1 0x38 PUSH1 0xC JUMP " // g()
|
||||
"JUMPDEST SWAP2 POP SWAP2 POP " // assignments
|
||||
"POP POP " // removal of y and z
|
||||
"PUSH1 0x7 POP "
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(reuse_slots_function)
|
||||
{
|
||||
string in = R"({
|
||||
function f() -> x, y, z, t {}
|
||||
let a, b, c, d := f() let x1 := 2 let y1 := 3 mstore(x1, a) mstore(y1, c)
|
||||
})";
|
||||
BOOST_CHECK_EQUAL(assemble(in),
|
||||
"PUSH1 0x12 JUMP "
|
||||
"JUMPDEST PUSH1 0x0 PUSH1 0x0 PUSH1 0x0 PUSH1 0x0 JUMPDEST SWAP1 SWAP2 SWAP3 SWAP4 JUMP "
|
||||
"JUMPDEST PUSH1 0x18 PUSH1 0x3 JUMP "
|
||||
// Stack: a b c d
|
||||
"JUMPDEST POP " // d is unused
|
||||
// Stack: a b c
|
||||
"PUSH1 0x2 SWAP2 POP " // x1 reuses b's slot
|
||||
"PUSH1 0x3 "
|
||||
// Stack: a x1 c y1
|
||||
"DUP4 DUP4 MSTORE "
|
||||
"DUP2 DUP2 MSTORE "
|
||||
"POP POP POP POP "
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(reuse_slots_function_with_gaps)
|
||||
{
|
||||
string in = R"({
|
||||
// Only x3 is actually used, the slots of
|
||||
// x1 and x2 will be reused right away.
|
||||
let x1 := 5 let x2 := 6 let x3 := 7
|
||||
mstore(x1, x2)
|
||||
function f() -> x, y, z, t {}
|
||||
let a, b, c, d := f() mstore(x3, a) mstore(c, d)
|
||||
})";
|
||||
BOOST_CHECK_EQUAL(assemble(in),
|
||||
"PUSH1 0x5 PUSH1 0x6 PUSH1 0x7 "
|
||||
"DUP2 DUP4 MSTORE "
|
||||
"PUSH1 0x1B JUMP " // jump across function
|
||||
"JUMPDEST PUSH1 0x0 PUSH1 0x0 PUSH1 0x0 PUSH1 0x0 JUMPDEST SWAP1 SWAP2 SWAP3 SWAP4 JUMP "
|
||||
"JUMPDEST PUSH1 0x21 PUSH1 0xC JUMP "
|
||||
// stack: x1 x2 x3 a b c d
|
||||
"JUMPDEST SWAP6 POP " // move d into x1
|
||||
// stack: d x2 x3 a b c
|
||||
"SWAP4 POP "
|
||||
// stack: d c x3 a b
|
||||
"POP "
|
||||
// stack: d c x3 a
|
||||
"DUP1 DUP3 MSTORE "
|
||||
"POP POP "
|
||||
// stack: d c
|
||||
"DUP2 DUP2 MSTORE "
|
||||
"POP POP "
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(reuse_on_decl_assign_to_last_used)
|
||||
{
|
||||
string in = R"({
|
||||
let x := 5
|
||||
let y := x // y should reuse the stack slot of x
|
||||
sstore(y, y)
|
||||
})";
|
||||
BOOST_CHECK_EQUAL(assemble(in),
|
||||
"PUSH1 0x5 "
|
||||
"DUP1 SWAP1 POP "
|
||||
"DUP1 DUP2 SSTORE "
|
||||
"POP "
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(reuse_on_decl_assign_to_last_used_expr)
|
||||
{
|
||||
string in = R"({
|
||||
let x := 5
|
||||
let y := add(x, 2) // y should reuse the stack slot of x
|
||||
sstore(y, y)
|
||||
})";
|
||||
BOOST_CHECK_EQUAL(assemble(in),
|
||||
"PUSH1 0x5 "
|
||||
"PUSH1 0x2 DUP2 ADD "
|
||||
"SWAP1 POP "
|
||||
"DUP1 DUP2 SSTORE "
|
||||
"POP "
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(reuse_on_decl_assign_to_not_last_used)
|
||||
{
|
||||
string in = R"({
|
||||
let x := 5
|
||||
let y := x // y should not reuse the stack slot of x, since x is still used below
|
||||
sstore(y, x)
|
||||
})";
|
||||
BOOST_CHECK_EQUAL(assemble(in),
|
||||
"PUSH1 0x5 "
|
||||
"DUP1 "
|
||||
"DUP2 DUP2 SSTORE "
|
||||
"POP POP "
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(reuse_on_decl_assign_not_same_scope)
|
||||
{
|
||||
string in = R"({
|
||||
let x := 5
|
||||
{
|
||||
let y := x // y should not reuse the stack slot of x, since x is not in the same scope
|
||||
sstore(y, y)
|
||||
}
|
||||
})";
|
||||
BOOST_CHECK_EQUAL(assemble(in),
|
||||
"PUSH1 0x5 "
|
||||
"DUP1 "
|
||||
"DUP1 DUP2 SSTORE "
|
||||
"POP POP "
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
}
|
19
test/libyul/evmCodeTransform/stackReuse/for_1.yul
Normal file
19
test/libyul/evmCodeTransform/stackReuse/for_1.yul
Normal file
@ -0,0 +1,19 @@
|
||||
{ for { let z := 0 } 1 { } { let x := 3 } let t := 2 }
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0x0
|
||||
// POP
|
||||
// JUMPDEST
|
||||
// PUSH1 0x1
|
||||
// ISZERO
|
||||
// PUSH1 0x11
|
||||
// JUMPI
|
||||
// PUSH1 0x3
|
||||
// POP
|
||||
// JUMPDEST
|
||||
// PUSH1 0x3
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// PUSH1 0x2
|
||||
// POP
|
22
test/libyul/evmCodeTransform/stackReuse/for_2.yul
Normal file
22
test/libyul/evmCodeTransform/stackReuse/for_2.yul
Normal file
@ -0,0 +1,22 @@
|
||||
{ for { let z := 0 } 1 { } { z := 8 let x := 3 } let t := 2 }
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0x0
|
||||
// JUMPDEST
|
||||
// PUSH1 0x1
|
||||
// ISZERO
|
||||
// PUSH1 0x14
|
||||
// JUMPI
|
||||
// PUSH1 0x8
|
||||
// SWAP1
|
||||
// POP
|
||||
// PUSH1 0x3
|
||||
// POP
|
||||
// JUMPDEST
|
||||
// PUSH1 0x2
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// POP
|
||||
// PUSH1 0x2
|
||||
// POP
|
34
test/libyul/evmCodeTransform/stackReuse/function_call.yul
Normal file
34
test/libyul/evmCodeTransform/stackReuse/function_call.yul
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
let b := f(1, 2)
|
||||
function f(a, r) -> t { }
|
||||
b := f(3, 4)
|
||||
}
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0x9
|
||||
// PUSH1 0x2
|
||||
// PUSH1 0x1
|
||||
// PUSH1 0xD
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// PUSH1 0x16
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// PUSH1 0x0
|
||||
// JUMPDEST
|
||||
// SWAP3
|
||||
// SWAP2
|
||||
// POP
|
||||
// POP
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// PUSH1 0x20
|
||||
// PUSH1 0x4
|
||||
// PUSH1 0x3
|
||||
// PUSH1 0xD
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// SWAP1
|
||||
// POP
|
||||
// POP
|
14
test/libyul/evmCodeTransform/stackReuse/function_params.yul
Normal file
14
test/libyul/evmCodeTransform/stackReuse/function_params.yul
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
function f(a, b) { }
|
||||
}
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0x8
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// JUMPDEST
|
||||
// POP
|
||||
// POP
|
||||
// JUMP
|
||||
// JUMPDEST
|
@ -0,0 +1,25 @@
|
||||
// This does not re-use the parameters for the return parameters
|
||||
// We do not expect parameters to be fully unused, so the stack
|
||||
// layout for a function is still fixed, even though parameters
|
||||
// can be re-used.
|
||||
{
|
||||
function f(a, b, c, d) -> x, y { }
|
||||
}
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0x11
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// PUSH1 0x0
|
||||
// PUSH1 0x0
|
||||
// JUMPDEST
|
||||
// SWAP5
|
||||
// POP
|
||||
// SWAP5
|
||||
// SWAP3
|
||||
// POP
|
||||
// POP
|
||||
// POP
|
||||
// JUMP
|
||||
// JUMPDEST
|
@ -0,0 +1,32 @@
|
||||
{
|
||||
function f(a, b, c, d) -> x, y { b := 3 let s := 9 y := 2 mstore(s, y) }
|
||||
}
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0x1F
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// PUSH1 0x0
|
||||
// PUSH1 0x0
|
||||
// PUSH1 0x3
|
||||
// SWAP4
|
||||
// POP
|
||||
// PUSH1 0x9
|
||||
// PUSH1 0x2
|
||||
// SWAP2
|
||||
// POP
|
||||
// DUP2
|
||||
// DUP2
|
||||
// MSTORE
|
||||
// POP
|
||||
// JUMPDEST
|
||||
// SWAP5
|
||||
// POP
|
||||
// SWAP5
|
||||
// SWAP3
|
||||
// POP
|
||||
// POP
|
||||
// POP
|
||||
// JUMP
|
||||
// JUMPDEST
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
function f() -> x, y { }
|
||||
}
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0xC
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// PUSH1 0x0
|
||||
// PUSH1 0x0
|
||||
// JUMPDEST
|
||||
// SWAP1
|
||||
// SWAP2
|
||||
// JUMP
|
||||
// JUMPDEST
|
12
test/libyul/evmCodeTransform/stackReuse/function_trivial.yul
Normal file
12
test/libyul/evmCodeTransform/stackReuse/function_trivial.yul
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
function f() { }
|
||||
}
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0x6
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// JUMPDEST
|
||||
// JUMP
|
||||
// JUMPDEST
|
@ -0,0 +1,35 @@
|
||||
{
|
||||
let b := 3
|
||||
function f(a, r) -> t {
|
||||
// r could be removed right away, but a cannot - this is not implemented, though
|
||||
let x := a a := 3 t := a
|
||||
}
|
||||
b := 7
|
||||
}
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0x3
|
||||
// PUSH1 0x17
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// PUSH1 0x0
|
||||
// DUP2
|
||||
// POP
|
||||
// PUSH1 0x3
|
||||
// SWAP2
|
||||
// POP
|
||||
// DUP2
|
||||
// SWAP1
|
||||
// POP
|
||||
// JUMPDEST
|
||||
// SWAP3
|
||||
// SWAP2
|
||||
// POP
|
||||
// POP
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// PUSH1 0x7
|
||||
// SWAP1
|
||||
// POP
|
||||
// POP
|
@ -0,0 +1,61 @@
|
||||
{
|
||||
function f(a, b) -> t { }
|
||||
function g() -> r, s { }
|
||||
let x := f(1, 2)
|
||||
x := f(3, 4)
|
||||
let y, z := g()
|
||||
y, z := g()
|
||||
let unused := 7
|
||||
}
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0x15
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// PUSH1 0x0
|
||||
// JUMPDEST
|
||||
// SWAP3
|
||||
// SWAP2
|
||||
// POP
|
||||
// POP
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// PUSH1 0x0
|
||||
// PUSH1 0x0
|
||||
// JUMPDEST
|
||||
// SWAP1
|
||||
// SWAP2
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// PUSH1 0x1F
|
||||
// PUSH1 0x2
|
||||
// PUSH1 0x1
|
||||
// PUSH1 0x3
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// PUSH1 0x29
|
||||
// PUSH1 0x4
|
||||
// PUSH1 0x3
|
||||
// PUSH1 0x3
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// SWAP1
|
||||
// POP
|
||||
// POP
|
||||
// PUSH1 0x32
|
||||
// PUSH1 0xC
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// PUSH1 0x38
|
||||
// PUSH1 0xC
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// SWAP2
|
||||
// POP
|
||||
// SWAP2
|
||||
// POP
|
||||
// POP
|
||||
// POP
|
||||
// PUSH1 0x7
|
||||
// POP
|
17
test/libyul/evmCodeTransform/stackReuse/if.yul
Normal file
17
test/libyul/evmCodeTransform/stackReuse/if.yul
Normal file
@ -0,0 +1,17 @@
|
||||
// z is only removed after the if (after the jumpdest)
|
||||
{ let z := mload(0) if z { let x := z } let t := 3 }
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0x0
|
||||
// MLOAD
|
||||
// DUP1
|
||||
// ISZERO
|
||||
// PUSH1 0xA
|
||||
// JUMPI
|
||||
// DUP1
|
||||
// POP
|
||||
// JUMPDEST
|
||||
// POP
|
||||
// PUSH1 0x3
|
||||
// POP
|
@ -0,0 +1,10 @@
|
||||
{ let z := 0 { pop(z) } let x := 1 }
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0x0
|
||||
// DUP1
|
||||
// POP
|
||||
// POP
|
||||
// PUSH1 0x1
|
||||
// POP
|
@ -0,0 +1,23 @@
|
||||
{ let z := mload(0) { let x := 1 x := 6 z := x } { let x := 2 z := x x := 4 } }
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0x0
|
||||
// MLOAD
|
||||
// PUSH1 0x1
|
||||
// PUSH1 0x6
|
||||
// SWAP1
|
||||
// POP
|
||||
// DUP1
|
||||
// SWAP2
|
||||
// POP
|
||||
// POP
|
||||
// PUSH1 0x2
|
||||
// DUP1
|
||||
// SWAP2
|
||||
// POP
|
||||
// PUSH1 0x4
|
||||
// SWAP1
|
||||
// POP
|
||||
// POP
|
||||
// POP
|
@ -0,0 +1,14 @@
|
||||
{ let x := 1 x := 6 let y := 2 y := 4 }
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0x1
|
||||
// PUSH1 0x6
|
||||
// SWAP1
|
||||
// POP
|
||||
// POP
|
||||
// PUSH1 0x2
|
||||
// PUSH1 0x4
|
||||
// SWAP1
|
||||
// POP
|
||||
// POP
|
@ -0,0 +1,14 @@
|
||||
{ let x := 1 x := 6 { let y := 2 y := 4 } }
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0x1
|
||||
// PUSH1 0x6
|
||||
// SWAP1
|
||||
// POP
|
||||
// POP
|
||||
// PUSH1 0x2
|
||||
// PUSH1 0x4
|
||||
// SWAP1
|
||||
// POP
|
||||
// POP
|
@ -0,0 +1,17 @@
|
||||
{
|
||||
let x := 5
|
||||
{
|
||||
let y := x // y should not reuse the stack slot of x, since x is not in the same scope
|
||||
sstore(y, y)
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0x5
|
||||
// DUP1
|
||||
// DUP1
|
||||
// DUP2
|
||||
// SSTORE
|
||||
// POP
|
||||
// POP
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
let x := 5
|
||||
let y := x // y should reuse the stack slot of x
|
||||
sstore(y, y)
|
||||
}
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0x5
|
||||
// DUP1
|
||||
// SWAP1
|
||||
// POP
|
||||
// DUP1
|
||||
// DUP2
|
||||
// SSTORE
|
||||
// POP
|
@ -0,0 +1,18 @@
|
||||
{
|
||||
let x := 5
|
||||
let y := add(x, 2) // y should reuse the stack slot of x
|
||||
sstore(y, y)
|
||||
}
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0x5
|
||||
// PUSH1 0x2
|
||||
// DUP2
|
||||
// ADD
|
||||
// SWAP1
|
||||
// POP
|
||||
// DUP1
|
||||
// DUP2
|
||||
// SSTORE
|
||||
// POP
|
@ -0,0 +1,15 @@
|
||||
{
|
||||
let x := 5
|
||||
let y := x // y should not reuse the stack slot of x, since x is still used below
|
||||
sstore(y, x)
|
||||
}
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0x5
|
||||
// DUP1
|
||||
// DUP2
|
||||
// DUP2
|
||||
// SSTORE
|
||||
// POP
|
||||
// POP
|
23
test/libyul/evmCodeTransform/stackReuse/reuse_slots.yul
Normal file
23
test/libyul/evmCodeTransform/stackReuse/reuse_slots.yul
Normal file
@ -0,0 +1,23 @@
|
||||
{ let a, b, c, d let x := 2 let y := 3 mstore(x, a) mstore(y, c) }
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0x0
|
||||
// PUSH1 0x0
|
||||
// PUSH1 0x0
|
||||
// PUSH1 0x0
|
||||
// POP
|
||||
// PUSH1 0x2
|
||||
// SWAP2
|
||||
// POP
|
||||
// PUSH1 0x3
|
||||
// DUP4
|
||||
// DUP4
|
||||
// MSTORE
|
||||
// DUP2
|
||||
// DUP2
|
||||
// MSTORE
|
||||
// POP
|
||||
// POP
|
||||
// POP
|
||||
// POP
|
@ -0,0 +1,40 @@
|
||||
{
|
||||
function f() -> x, y, z, t {}
|
||||
let a, b, c, d := f() let x1 := 2 let y1 := 3 mstore(x1, a) mstore(y1, c)
|
||||
}
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0x12
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// PUSH1 0x0
|
||||
// PUSH1 0x0
|
||||
// PUSH1 0x0
|
||||
// PUSH1 0x0
|
||||
// JUMPDEST
|
||||
// SWAP1
|
||||
// SWAP2
|
||||
// SWAP3
|
||||
// SWAP4
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// PUSH1 0x18
|
||||
// PUSH1 0x3
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// POP
|
||||
// PUSH1 0x2
|
||||
// SWAP2
|
||||
// POP
|
||||
// PUSH1 0x3
|
||||
// DUP4
|
||||
// DUP4
|
||||
// MSTORE
|
||||
// DUP2
|
||||
// DUP2
|
||||
// MSTORE
|
||||
// POP
|
||||
// POP
|
||||
// POP
|
||||
// POP
|
@ -0,0 +1,50 @@
|
||||
{
|
||||
// Only x3 is actually used, the slots of
|
||||
// x1 and x2 will be reused right away.
|
||||
let x1 := 5 let x2 := 6 let x3 := 7
|
||||
mstore(x1, x2)
|
||||
function f() -> x, y, z, t {}
|
||||
let a, b, c, d := f() mstore(x3, a) mstore(c, d)
|
||||
}
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0x5
|
||||
// PUSH1 0x6
|
||||
// PUSH1 0x7
|
||||
// DUP2
|
||||
// DUP4
|
||||
// MSTORE
|
||||
// PUSH1 0x1B
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// PUSH1 0x0
|
||||
// PUSH1 0x0
|
||||
// PUSH1 0x0
|
||||
// PUSH1 0x0
|
||||
// JUMPDEST
|
||||
// SWAP1
|
||||
// SWAP2
|
||||
// SWAP3
|
||||
// SWAP4
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// PUSH1 0x21
|
||||
// PUSH1 0xC
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// SWAP6
|
||||
// POP
|
||||
// SWAP4
|
||||
// POP
|
||||
// POP
|
||||
// DUP1
|
||||
// DUP3
|
||||
// MSTORE
|
||||
// POP
|
||||
// POP
|
||||
// DUP2
|
||||
// DUP2
|
||||
// MSTORE
|
||||
// POP
|
||||
// POP
|
6
test/libyul/evmCodeTransform/stackReuse/single_var.yul
Normal file
6
test/libyul/evmCodeTransform/stackReuse/single_var.yul
Normal file
@ -0,0 +1,6 @@
|
||||
{ let x }
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0x0
|
||||
// POP
|
@ -0,0 +1,6 @@
|
||||
{ let x := 1 }
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0x1
|
||||
// POP
|
@ -0,0 +1,9 @@
|
||||
{ let x := 1 mstore(3, 4) }
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0x1
|
||||
// POP
|
||||
// PUSH1 0x4
|
||||
// PUSH1 0x3
|
||||
// MSTORE
|
@ -0,0 +1,12 @@
|
||||
{ let x := 1 mstore(3, 4) pop(mload(x)) }
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0x1
|
||||
// PUSH1 0x4
|
||||
// PUSH1 0x3
|
||||
// MSTORE
|
||||
// DUP1
|
||||
// MLOAD
|
||||
// POP
|
||||
// POP
|
4
test/libyul/evmCodeTransform/stackReuse/smoke.yul
Normal file
4
test/libyul/evmCodeTransform/stackReuse/smoke.yul
Normal file
@ -0,0 +1,4 @@
|
||||
{}
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
26
test/libyul/evmCodeTransform/stackReuse/switch.yul
Normal file
26
test/libyul/evmCodeTransform/stackReuse/switch.yul
Normal file
@ -0,0 +1,26 @@
|
||||
{ let z := 0 switch z case 0 { let x := 2 let y := 3 } default { z := 3 } let t := 9 }
|
||||
// ====
|
||||
// stackOptimization: true
|
||||
// ----
|
||||
// PUSH1 0x0
|
||||
// DUP1
|
||||
// PUSH1 0x0
|
||||
// DUP2
|
||||
// EQ
|
||||
// PUSH1 0x11
|
||||
// JUMPI
|
||||
// PUSH1 0x3
|
||||
// SWAP2
|
||||
// POP
|
||||
// PUSH1 0x18
|
||||
// JUMP
|
||||
// JUMPDEST
|
||||
// PUSH1 0x2
|
||||
// POP
|
||||
// PUSH1 0x3
|
||||
// POP
|
||||
// JUMPDEST
|
||||
// POP
|
||||
// POP
|
||||
// PUSH1 0x9
|
||||
// POP
|
@ -32,6 +32,7 @@ add_executable(isoltest
|
||||
../libsolidity/ASTJSONTest.cpp
|
||||
../libsolidity/SMTCheckerTest.cpp
|
||||
../libyul/Common.cpp
|
||||
../libyul/EVMCodeTransformTest.cpp
|
||||
../libyul/EwasmTranslationTest.cpp
|
||||
../libyul/FunctionSideEffects.cpp
|
||||
../libyul/ObjectCompilerTest.cpp
|
||||
|
Loading…
Reference in New Issue
Block a user