Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Compiler Features:
Bugfixes:
* SMTChecker: Implement Boolean short-circuiting.
* SMTChecker: SSA control-flow did not take into account state variables that were modified inside inlined functions that were called inside branches.
* Yul: Properly register functions and disallow shadowing between function variables and variables in the outside scope.



Expand Down
4 changes: 2 additions & 2 deletions libyul/AsmScope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ bool Scope::registerVariable(YulString _name, YulType const& _type)
return true;
}

bool Scope::registerFunction(YulString _name, std::vector<YulType> const& _arguments, std::vector<YulType> const& _returns)
bool Scope::registerFunction(YulString _name, std::vector<YulType> _arguments, std::vector<YulType> _returns)
{
if (exists(_name))
return false;
identifiers[_name] = Function{_arguments, _returns};
identifiers[_name] = Function{std::move(_arguments), std::move(_returns)};
return true;
}

Expand Down
4 changes: 2 additions & 2 deletions libyul/AsmScope.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ struct Scope
bool registerLabel(YulString _name);
bool registerFunction(
YulString _name,
std::vector<YulType> const& _arguments,
std::vector<YulType> const& _returns
std::vector<YulType> _arguments,
std::vector<YulType> _returns
);

/// Looks up the identifier in this or super scopes and returns a valid pointer if found
Expand Down
46 changes: 25 additions & 21 deletions libyul/AsmScopeFiller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,28 +74,13 @@ bool ScopeFiller::operator()(VariableDeclaration const& _varDecl)

bool ScopeFiller::operator()(FunctionDefinition const& _funDef)
{
bool success = true;
vector<Scope::YulType> arguments;
for (auto const& _argument: _funDef.parameters)
arguments.emplace_back(_argument.type.str());
vector<Scope::YulType> returns;
for (auto const& _return: _funDef.returnVariables)
returns.emplace_back(_return.type.str());
if (!m_currentScope->registerFunction(_funDef.name, arguments, returns))
{
//@TODO secondary location
m_errorReporter.declarationError(
_funDef.location,
"Function name " + _funDef.name.str() + " already taken in this scope."
);
success = false;
}

auto virtualBlock = m_info.virtualBlocks[&_funDef] = make_shared<Block>();
Scope& varScope = scope(virtualBlock.get());
varScope.superScope = m_currentScope;
m_currentScope = &varScope;
varScope.functionScope = true;

bool success = true;
for (auto const& var: _funDef.parameters + _funDef.returnVariables)
if (!registerVariable(var, _funDef.location, varScope))
success = false;
Expand Down Expand Up @@ -153,12 +138,11 @@ bool ScopeFiller::operator()(Block const& _block)
// an entry in the scope according to their visibility.
for (auto const& s: _block.statements)
if (s.type() == typeid(FunctionDefinition))
if (!boost::apply_visitor(*this, s))
if (!registerFunction(boost::get<FunctionDefinition>(s)))
success = false;
for (auto const& s: _block.statements)
if (s.type() != typeid(FunctionDefinition))
if (!boost::apply_visitor(*this, s))
success = false;
if (!boost::apply_visitor(*this, s))
success = false;

m_currentScope = m_currentScope->superScope;
return success;
Expand All @@ -178,6 +162,26 @@ bool ScopeFiller::registerVariable(TypedName const& _name, SourceLocation const&
return true;
}

bool ScopeFiller::registerFunction(FunctionDefinition const& _funDef)
{
vector<Scope::YulType> arguments;
for (auto const& _argument: _funDef.parameters)
arguments.emplace_back(_argument.type.str());
vector<Scope::YulType> returns;
for (auto const& _return: _funDef.returnVariables)
returns.emplace_back(_return.type.str());
if (!m_currentScope->registerFunction(_funDef.name, std::move(arguments), std::move(returns)))
{
//@TODO secondary location
m_errorReporter.declarationError(
_funDef.location,
"Function name " + _funDef.name.str() + " already taken in this scope."
);
return false;
}
return true;
}

Scope& ScopeFiller::scope(Block const* _block)
{
auto& scope = m_info.scopes[_block];
Expand Down
1 change: 1 addition & 0 deletions libyul/AsmScopeFiller.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class ScopeFiller: public boost::static_visitor<bool>
langutil::SourceLocation const& _location,
Scope& _scope
);
bool registerFunction(FunctionDefinition const& _funDef);

Scope& scope(Block const* _block);

Expand Down
1 change: 1 addition & 0 deletions libyul/optimiser/Suite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ void OptimiserSuite::run(
BlockFlattener{}(ast);
DeadCodeEliminator{}(ast);

FunctionGrouper{}(ast);
VarNameCleaner{ast, *_dialect, reservedIdentifiers}(ast);
yul::AsmAnalyzer::analyzeStrictAssertCorrect(_dialect, ast);

Expand Down
2 changes: 1 addition & 1 deletion libyul/optimiser/VarNameCleaner.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ struct Dialect;
* renumbered by their base name.
* Function names are not modified.
*
* Prerequisites: Disambiguator, FunctionHoister
* Prerequisites: Disambiguator, FunctionHoister, FunctionGrouper
*/
class VarNameCleaner: public ASTModifier
{
Expand Down
2 changes: 1 addition & 1 deletion test/cmdlineTests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ printTask "Testing assemble, yul, strict-assembly and optimize..."
# while it results in empty binary representation with optimizations turned on.
test_solc_assembly_output "{ let x:u256 := 0:u256 }" "{ let x:u256 := 0:u256 }" "--yul"
test_solc_assembly_output "{ let x := 0 }" "{ let x := 0 }" "--strict-assembly"
test_solc_assembly_output "{ let x := 0 }" "{ }" "--strict-assembly --optimize"
test_solc_assembly_output "{ let x := 0 }" "{ { } }" "--strict-assembly --optimize"
)


Expand Down
16 changes: 10 additions & 6 deletions test/cmdlineTests/object_compiler/output
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,19 @@
Pretty printed source:
object "MyContract" {
code {
sstore(0, caller())
let _1 := datasize("Runtime")
datacopy(0, dataoffset("Runtime"), _1)
return(0, _1)
{
sstore(0, caller())
let _1 := datasize("Runtime")
datacopy(0, dataoffset("Runtime"), _1)
return(0, _1)
}
}
object "Runtime" {
code {
mstore(0, sload(0))
return(0, 0x20)
{
mstore(0, sload(0))
return(0, 0x20)
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion test/cmdlineTests/standard_yul_optimized/output.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"contracts":{"A":{"object":{"evm":{"assembly":" /* \"A\":17:18 */\n 0x00\n 0x00\n /* \"A\":11:19 */\n mload\n /* \"A\":20:40 */\n sstore\n","bytecode":{"linkReferences":{},"object":"600060005155","opcodes":"PUSH1 0x0 PUSH1 0x0 MLOAD SSTORE ","sourceMap":""}},"ir":"object \"object\" {\n code {\n let x := mload(0)\n sstore(add(x, 0), 0)\n }\n}\n","irOptimized":"object \"object\" {\n code {\n sstore(mload(0), 0)\n }\n}\n"}}},"errors":[{"component":"general","formattedMessage":"Yul is still experimental. Please use the output with care.","message":"Yul is still experimental. Please use the output with care.","severity":"warning","type":"Warning"}]}
{"contracts":{"A":{"object":{"evm":{"assembly":" /* \"A\":17:18 */\n 0x00\n 0x00\n /* \"A\":11:19 */\n mload\n /* \"A\":20:40 */\n sstore\n","bytecode":{"linkReferences":{},"object":"600060005155","opcodes":"PUSH1 0x0 PUSH1 0x0 MLOAD SSTORE ","sourceMap":""}},"ir":"object \"object\" {\n code {\n let x := mload(0)\n sstore(add(x, 0), 0)\n }\n}\n","irOptimized":"object \"object\" {\n code {\n {\n sstore(mload(0), 0)\n }\n }\n}\n"}}},"errors":[{"component":"general","formattedMessage":"Yul is still experimental. Please use the output with care.","message":"Yul is still experimental. Please use the output with care.","severity":"warning","type":"Warning"}]}
8 changes: 5 additions & 3 deletions test/cmdlineTests/yul_stack_opt/output
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
Pretty printed source:
object "object" {
code {
let a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1 := fun()
let a2, b2, c2, d2, e2, f2, g2, h2, i2, j2, k2, l2, m2, n2, o2, p2 := fun()
sstore(a1, a2)
{
let a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1 := fun()
let a2, b2, c2, d2, e2, f2, g2, h2, i2, j2, k2, l2, m2, n2, o2, p2 := fun()
sstore(a1, a2)
}
function fun() -> a3, b3, c3, d3, e3, f3, g3, h3, i3, j3, k3, l3, m3, n3, o3, p3
{
let a := 1
Expand Down
6 changes: 6 additions & 0 deletions test/libyul/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,12 @@ BOOST_AUTO_TEST_CASE(switch_duplicate_case_different_literal)
BOOST_CHECK(successParse("{ switch 1:u256 case \"1\":u256 {} case \"2\":u256 {} }"));
}

BOOST_AUTO_TEST_CASE(function_shadowing_outside_vars)
{
CHECK_ERROR("{ let x:u256 function f() -> x:u256 {} }", DeclarationError, "already taken in this scope");
BOOST_CHECK(successParse("{ { let x:u256 } function f() -> x:u256 {} }"));
}

BOOST_AUTO_TEST_CASE(builtins_parser)
{
struct SimpleDialect: public Dialect
Expand Down
22 changes: 12 additions & 10 deletions test/libyul/yulOptimizerTests/fullSuite/abi2.yul
Original file line number Diff line number Diff line change
Expand Up @@ -1073,18 +1073,20 @@
// step: fullSuite
// ----
// {
// let _1 := mload(1)
// let _2 := mload(0)
// if slt(sub(_1, _2), 64)
// {
// revert(0, 0)
// let _1 := mload(1)
// let _2 := mload(0)
// if slt(sub(_1, _2), 64)
// {
// revert(0, 0)
// }
// sstore(0, and(calldataload(_2), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
// let x0, x1, x2, x3, x4 := abi_decode_tuple_t_addresst_uint256t_bytes_calldata_ptrt_enum$_Operation_$1949(mload(7), mload(8))
// sstore(x1, x0)
// sstore(x3, x2)
// sstore(1, x4)
// pop(abi_encode_tuple_t_bytes32_t_address_t_uint256_t_bytes32_t_enum$_Operation_$1949_t_uint256_t_uint256_t_uint256_t_address_t_address_t_uint256__to_t_bytes32_t_address_t_uint256_t_bytes32_t_uint8_t_uint256_t_uint256_t_uint256_t_address_t_address_t_uint256_(mload(30), mload(31), mload(32), mload(33), mload(34), mload(35), mload(36), mload(37), mload(38), mload(39), mload(40), mload(41)))
// }
// sstore(0, and(calldataload(_2), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
// let x0, x1, x2, x3, x4 := abi_decode_tuple_t_addresst_uint256t_bytes_calldata_ptrt_enum$_Operation_$1949(mload(7), mload(8))
// sstore(x1, x0)
// sstore(x3, x2)
// sstore(1, x4)
// pop(abi_encode_tuple_t_bytes32_t_address_t_uint256_t_bytes32_t_enum$_Operation_$1949_t_uint256_t_uint256_t_uint256_t_address_t_address_t_uint256__to_t_bytes32_t_address_t_uint256_t_bytes32_t_uint8_t_uint256_t_uint256_t_uint256_t_address_t_address_t_uint256_(mload(30), mload(31), mload(32), mload(33), mload(34), mload(35), mload(36), mload(37), mload(38), mload(39), mload(40), mload(41)))
// function abi_decode_tuple_t_addresst_uint256t_bytes_calldata_ptrt_enum$_Operation_$1949(headStart, dataEnd) -> value0, value1, value2, value3, value4
// {
// if slt(sub(dataEnd, headStart), 128)
Expand Down
98 changes: 50 additions & 48 deletions test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul
Original file line number Diff line number Diff line change
Expand Up @@ -459,62 +459,64 @@
// step: fullSuite
// ----
// {
// let _1 := 0x20
// let _2 := 0
// let _3 := mload(_2)
// let pos := _1
// let length := mload(_3)
// mstore(_1, length)
// pos := 64
// let srcPtr := add(_3, _1)
// let i := _2
// for {
// }
// lt(i, length)
// {
// i := add(i, 1)
// }
// {
// let _4 := mload(srcPtr)
// let pos_1 := pos
// let srcPtr_1 := _4
// let i_1 := _2
// let _1 := 0x20
// let _2 := 0
// let _3 := mload(_2)
// let pos := _1
// let length := mload(_3)
// mstore(_1, length)
// pos := 64
// let srcPtr := add(_3, _1)
// let i := _2
// for {
// }
// lt(i_1, 0x3)
// lt(i, length)
// {
// i_1 := add(i_1, 1)
// i := add(i, 1)
// }
// {
// mstore(pos_1, and(mload(srcPtr_1), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
// srcPtr_1 := add(srcPtr_1, _1)
// pos_1 := add(pos_1, _1)
// let _4 := mload(srcPtr)
// let pos_1 := pos
// let srcPtr_1 := _4
// let i_1 := _2
// for {
// }
// lt(i_1, 0x3)
// {
// i_1 := add(i_1, 1)
// }
// {
// mstore(pos_1, and(mload(srcPtr_1), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
// srcPtr_1 := add(srcPtr_1, _1)
// pos_1 := add(pos_1, _1)
// }
// srcPtr := add(srcPtr, _1)
// pos := add(pos, 0x60)
// }
// srcPtr := add(srcPtr, _1)
// pos := add(pos, 0x60)
// }
// let _5 := mload(64)
// let _6 := mload(_1)
// if slt(sub(_5, _6), 128)
// {
// revert(_2, _2)
// }
// let offset := calldataload(add(_6, 64))
// let _7 := 0xffffffffffffffff
// if gt(offset, _7)
// {
// revert(_2, _2)
// }
// let value2 := abi_decode_t_array$_t_uint256_$dyn_memory_ptr(add(_6, offset), _5)
// let offset_1 := calldataload(add(_6, 96))
// if gt(offset_1, _7)
// {
// revert(_2, _2)
// let _5 := mload(64)
// let _6 := mload(_1)
// if slt(sub(_5, _6), 128)
// {
// revert(_2, _2)
// }
// let offset := calldataload(add(_6, 64))
// let _7 := 0xffffffffffffffff
// if gt(offset, _7)
// {
// revert(_2, _2)
// }
// let value2 := abi_decode_t_array$_t_uint256_$dyn_memory_ptr(add(_6, offset), _5)
// let offset_1 := calldataload(add(_6, 96))
// if gt(offset_1, _7)
// {
// revert(_2, _2)
// }
// let value3 := abi_decode_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(add(_6, offset_1), _5)
// sstore(calldataload(_6), calldataload(add(_6, _1)))
// sstore(value2, value3)
// sstore(_2, pos)
// }
// let value3 := abi_decode_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(add(_6, offset_1), _5)
// sstore(calldataload(_6), calldataload(add(_6, _1)))
// sstore(value2, value3)
// sstore(_2, pos)
// function abi_decode_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(offset, end) -> array
// {
// if iszero(slt(add(offset, 0x1f), end))
Expand Down
Loading