diff --git a/.circleci/config.yml b/.circleci/config.yml index 64e3309f6..d5a5f67af 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -22,7 +22,7 @@ defaults: name: Build command: | set -ex - if [ "$CIRCLE_BRANCH" = release -o -n "$CIRCLE_TAG" ]; then echo -n > prerelease.txt; else date -u +"nightly.%Y.%-m.%-d" > prerelease.txt; fi + if [ "$CIRCLE_BRANCH" = release -o -n "$CIRCLE_TAG" -o -n "$FORCE_RELEASE" ]; then echo -n > prerelease.txt; else date -u +"nightly.%Y.%-m.%-d" > prerelease.txt; fi echo -n "$CIRCLE_SHA1" > commit_hash.txt mkdir -p build cd build @@ -151,6 +151,11 @@ defaults: requires: - b_ubu + - workflow_ubuntu1904_release: &workflow_ubuntu1904_release + <<: *workflow_trigger_on_tags + requires: + - b_ubu_release + - workflow_ubuntu1904_codecov: &workflow_ubuntu1904_codecov <<: *workflow_trigger_on_tags requires: @@ -284,6 +289,11 @@ jobs: - store_artifacts: *artifacts_solc - persist_to_workspace: *artifacts_executables + b_ubu_release: &build_ubuntu1904_release + <<: *build_ubuntu1904 + environment: + FORCE_RELEASE: ON + b_ubu18: &build_ubuntu1804 docker: - image: ethereum/solidity-buildpack-deps:ubuntu1804 @@ -485,6 +495,9 @@ jobs: t_ubu_soltest: &t_ubu_soltest <<: *test_ubuntu1904 + t_ubu_release_soltest: &t_ubu_release_soltest + <<: *t_ubu_soltest + t_ubu_cli: &t_ubu_cli docker: - image: ethereum/solidity-buildpack-deps:ubuntu1904 @@ -498,6 +511,9 @@ jobs: - store_test_results: *store_test_results - store_artifacts: *artifacts_test_results + t_ubu_release_cli: &t_ubu_release_cli + <<: *t_ubu_cli + t_ubu_asan_cli: <<: *t_ubu_cli environment: @@ -617,6 +633,11 @@ workflows: - t_ubu_cli: *workflow_ubuntu1904 - t_ubu_soltest: *workflow_ubuntu1904 + # Ubuntu fake release build and tests + - b_ubu_release: *workflow_trigger_on_tags + - t_ubu_release_cli: *workflow_ubuntu1904_release + - t_ubu_release_soltest: *workflow_ubuntu1904_release + # ASan build and tests - b_ubu_asan: *workflow_trigger_on_tags - t_ubu_asan_constantinople: *workflow_ubuntu1904_asan diff --git a/Changelog.md b/Changelog.md index 0817154cc..cadd3884a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -32,6 +32,7 @@ Compiler Features: * ABI Output: Change sorting order of functions from selector to kind, name. * Optimizer: Add rule that replaces the BYTE opcode by 0 if the first argument is larger than 31. * Yul Optimizer: Take side-effect-freeness of user-defined functions into account. + * Yul Optimizer: Remove redundant mload/sload operations. Bugfixes: diff --git a/docs/style-guide.rst b/docs/style-guide.rst index fb38f2d93..0493b4ffa 100644 --- a/docs/style-guide.rst +++ b/docs/style-guide.rst @@ -407,7 +407,7 @@ should: * open on the same line as the declaration * close on their own line at the same indentation level as the beginning of the declaration. -* The opening brace should be proceeded by a single space. +* The opening brace should be preceded by a single space. Yes:: @@ -1141,4 +1141,4 @@ added looks like the one below:: It is recommended that Solidity contracts are fully annontated using `NatSpec `_ for all public interfaces (everything in the ABI). -Please see the section about `NatSpec `_ for a detailed explanation. \ No newline at end of file +Please see the section about `NatSpec `_ for a detailed explanation. diff --git a/libevmasm/GasMeter.cpp b/libevmasm/GasMeter.cpp index d98b3efa9..5ff3a905e 100644 --- a/libevmasm/GasMeter.cpp +++ b/libevmasm/GasMeter.cpp @@ -188,6 +188,12 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _ case Instruction::BALANCE: gas = GasCosts::balanceGas(m_evmVersion); break; + case Instruction::CHAINID: + gas = runGas(Instruction::CHAINID); + break; + case Instruction::SELFBALANCE: + gas = runGas(Instruction::SELFBALANCE); + break; default: gas = runGas(_item.instruction()); break; diff --git a/libevmasm/Instruction.cpp b/libevmasm/Instruction.cpp index 6dd9da6b9..cc5561daf 100644 --- a/libevmasm/Instruction.cpp +++ b/libevmasm/Instruction.cpp @@ -81,6 +81,8 @@ std::map const dev::eth::c_instructions = { "NUMBER", Instruction::NUMBER }, { "DIFFICULTY", Instruction::DIFFICULTY }, { "GASLIMIT", Instruction::GASLIMIT }, + { "CHAINID", Instruction::CHAINID }, + { "SELFBALANCE", Instruction::SELFBALANCE }, { "POP", Instruction::POP }, { "MLOAD", Instruction::MLOAD }, { "MSTORE", Instruction::MSTORE }, @@ -225,6 +227,8 @@ static std::map const c_instructionInfo = { Instruction::NUMBER, { "NUMBER", 0, 0, 1, false, Tier::Base } }, { Instruction::DIFFICULTY, { "DIFFICULTY", 0, 0, 1, false, Tier::Base } }, { Instruction::GASLIMIT, { "GASLIMIT", 0, 0, 1, false, Tier::Base } }, + { Instruction::CHAINID, { "CHAINID", 0, 0, 1, false, Tier::Base } }, + { Instruction::SELFBALANCE, { "SELFBALANCE", 0, 0, 1, false, Tier::Low } }, { Instruction::POP, { "POP", 0, 1, 0, false, Tier::Base } }, { Instruction::MLOAD, { "MLOAD", 0, 1, 1, true, Tier::VeryLow } }, { Instruction::MSTORE, { "MSTORE", 0, 2, 0, true, Tier::VeryLow } }, diff --git a/libevmasm/Instruction.h b/libevmasm/Instruction.h index 9a0a5d4e3..f2f5879d9 100644 --- a/libevmasm/Instruction.h +++ b/libevmasm/Instruction.h @@ -90,6 +90,8 @@ enum class Instruction: uint8_t NUMBER, ///< get the block's number DIFFICULTY, ///< get the block's difficulty GASLIMIT, ///< get the block's gas limit + CHAINID, ///< get the config's chainid param + SELFBALANCE, ///< get balance of the current account POP = 0x50, ///< remove item from stack MLOAD, ///< load word from memory diff --git a/libevmasm/RuleList.h b/libevmasm/RuleList.h index ce00e95df..f2422ce58 100644 --- a/libevmasm/RuleList.h +++ b/libevmasm/RuleList.h @@ -271,9 +271,7 @@ std::vector> simplificationRuleListPart5( Instruction::ADDRESS, Instruction::CALLER, Instruction::ORIGIN, - Instruction::COINBASE, - Instruction::CREATE, - Instruction::CREATE2 + Instruction::COINBASE }) { u256 const mask = (u256(1) << 160) - 1; @@ -288,6 +286,7 @@ std::vector> simplificationRuleListPart5( false }); } + return rules; } @@ -565,8 +564,48 @@ std::vector> simplificationRuleListPart8( return rules; } +template +std::vector> simplificationRuleListPart9( + Pattern, + Pattern, + Pattern, + Pattern W, + Pattern X, + Pattern Y, + Pattern Z +) +{ + std::vector> rules; + + u256 const mask = (u256(1) << 160) - 1; + // CREATE + rules.push_back({ + {Instruction::AND, {{Instruction::CREATE, {W, X, Y}}, mask}}, + [=]() -> Pattern { return {Instruction::CREATE, {W, X, Y}}; }, + false + }); + rules.push_back({ + {Instruction::AND, {{mask, {Instruction::CREATE, {W, X, Y}}}}}, + [=]() -> Pattern { return {Instruction::CREATE, {W, X, Y}}; }, + false + }); + // CREATE2 + rules.push_back({ + {Instruction::AND, {{Instruction::CREATE2, {W, X, Y, Z}}, mask}}, + [=]() -> Pattern { return {Instruction::CREATE2, {W, X, Y, Z}}; }, + false + }); + rules.push_back({ + {Instruction::AND, {{mask, {Instruction::CREATE2, {W, X, Y, Z}}}}}, + [=]() -> Pattern { return {Instruction::CREATE2, {W, X, Y, Z}}; }, + false + }); + + return rules; +} + /// @returns a list of simplification rules given certain match placeholders. -/// A, B and C should represent constants, X and Y arbitrary expressions. +/// A, B and C should represent constants, W, X, Y, and Z arbitrary expressions. /// The simplifications should never change the order of evaluation of /// arbitrary operations. template @@ -574,19 +613,22 @@ std::vector> simplificationRuleList( Pattern A, Pattern B, Pattern C, + Pattern W, Pattern X, - Pattern Y + Pattern Y, + Pattern Z ) { std::vector> rules; - rules += simplificationRuleListPart1(A, B, C, X, Y); - rules += simplificationRuleListPart2(A, B, C, X, Y); - rules += simplificationRuleListPart3(A, B, C, X, Y); - rules += simplificationRuleListPart4(A, B, C, X, Y); - rules += simplificationRuleListPart5(A, B, C, X, Y); - rules += simplificationRuleListPart6(A, B, C, X, Y); - rules += simplificationRuleListPart7(A, B, C, X, Y); - rules += simplificationRuleListPart8(A, B, C, X, Y); + rules += simplificationRuleListPart1(A, B, C, W, X); + rules += simplificationRuleListPart2(A, B, C, W, X); + rules += simplificationRuleListPart3(A, B, C, W, X); + rules += simplificationRuleListPart4(A, B, C, W, X); + rules += simplificationRuleListPart5(A, B, C, W, X); + rules += simplificationRuleListPart6(A, B, C, W, X); + rules += simplificationRuleListPart7(A, B, C, W, X); + rules += simplificationRuleListPart8(A, B, C, W, X); + rules += simplificationRuleListPart9(A, B, C, W, X, Y, Z); return rules; } diff --git a/libevmasm/SemanticInformation.cpp b/libevmasm/SemanticInformation.cpp index 6b6b4611d..8932d4351 100644 --- a/libevmasm/SemanticInformation.cpp +++ b/libevmasm/SemanticInformation.cpp @@ -172,6 +172,7 @@ bool SemanticInformation::isDeterministic(AssemblyItem const& _item) case Instruction::PC: case Instruction::MSIZE: // depends on previous writes and reads, not only on content case Instruction::BALANCE: // depends on previous calls + case Instruction::SELFBALANCE: // depends on previous calls case Instruction::EXTCODESIZE: case Instruction::EXTCODEHASH: case Instruction::RETURNDATACOPY: // depends on previous calls @@ -194,6 +195,7 @@ bool SemanticInformation::movable(Instruction _instruction) { case Instruction::KECCAK256: case Instruction::BALANCE: + case Instruction::SELFBALANCE: case Instruction::EXTCODESIZE: case Instruction::EXTCODEHASH: case Instruction::RETURNDATASIZE: @@ -265,6 +267,7 @@ bool SemanticInformation::invalidInPureFunctions(Instruction _instruction) switch (_instruction) { case Instruction::ADDRESS: + case Instruction::SELFBALANCE: case Instruction::BALANCE: case Instruction::ORIGIN: case Instruction::CALLER: diff --git a/libevmasm/SimplificationRules.cpp b/libevmasm/SimplificationRules.cpp index 9fee79cf4..ca201862a 100644 --- a/libevmasm/SimplificationRules.cpp +++ b/libevmasm/SimplificationRules.cpp @@ -83,15 +83,19 @@ Rules::Rules() Pattern B(Push); Pattern C(Push); // Anything. + Pattern W; Pattern X; Pattern Y; + Pattern Z; A.setMatchGroup(1, m_matchGroups); B.setMatchGroup(2, m_matchGroups); C.setMatchGroup(3, m_matchGroups); - X.setMatchGroup(4, m_matchGroups); - Y.setMatchGroup(5, m_matchGroups); + W.setMatchGroup(4, m_matchGroups); + X.setMatchGroup(5, m_matchGroups); + Y.setMatchGroup(6, m_matchGroups); + Z.setMatchGroup(7, m_matchGroups); - addRules(simplificationRuleList(A, B, C, X, Y)); + addRules(simplificationRuleList(A, B, C, W, X, Y, Z)); assertThrow(isInitialized(), OptimizerException, "Rule list not properly initialized."); } diff --git a/liblangutil/EVMVersion.cpp b/liblangutil/EVMVersion.cpp index eb87d4832..3d546a9e4 100644 --- a/liblangutil/EVMVersion.cpp +++ b/liblangutil/EVMVersion.cpp @@ -40,6 +40,10 @@ bool EVMVersion::hasOpcode(Instruction _opcode) const return hasCreate2(); case Instruction::EXTCODEHASH: return hasExtCodeHash(); + case Instruction::CHAINID: + return hasChainID(); + case Instruction::SELFBALANCE: + return hasSelfBalance(); default: return true; } diff --git a/liblangutil/EVMVersion.h b/liblangutil/EVMVersion.h index 6fb6f7e3e..3c67e304d 100644 --- a/liblangutil/EVMVersion.h +++ b/liblangutil/EVMVersion.h @@ -84,6 +84,8 @@ public: bool hasBitwiseShifting() const { return *this >= constantinople(); } bool hasCreate2() const { return *this >= constantinople(); } bool hasExtCodeHash() const { return *this >= constantinople(); } + bool hasChainID() const { return *this >= istanbul(); } + bool hasSelfBalance() const { return *this >= istanbul(); } bool hasOpcode(dev::eth::Instruction _opcode) const; diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index 2622e413a..9c62737d8 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -732,6 +732,14 @@ void AsmAnalyzer::warnOnInstructions(dev::eth::Instruction _instr, SourceLocatio { errorForVM("only available for Constantinople-compatible"); } + else if (_instr == dev::eth::Instruction::CHAINID && !m_evmVersion.hasChainID()) + { + errorForVM("only available for Istanbul-compatible"); + } + else if (_instr == dev::eth::Instruction::SELFBALANCE && !m_evmVersion.hasSelfBalance()) + { + errorForVM("only available for Istanbul-compatible"); + } else if ( _instr == dev::eth::Instruction::JUMP || _instr == dev::eth::Instruction::JUMPI || diff --git a/libyul/optimiser/DataFlowAnalyzer.cpp b/libyul/optimiser/DataFlowAnalyzer.cpp index 3f3b31f2a..c2042a19c 100644 --- a/libyul/optimiser/DataFlowAnalyzer.cpp +++ b/libyul/optimiser/DataFlowAnalyzer.cpp @@ -297,7 +297,7 @@ void DataFlowAnalyzer::clearValues(set _variables) void DataFlowAnalyzer::clearKnowledgeIfInvalidated(Block const& _block) { - SideEffectsCollector sideEffects(m_dialect, _block); + SideEffectsCollector sideEffects(m_dialect, _block, &m_functionSideEffects); if (sideEffects.invalidatesStorage()) m_storage.clear(); if (sideEffects.invalidatesMemory()) @@ -306,7 +306,7 @@ void DataFlowAnalyzer::clearKnowledgeIfInvalidated(Block const& _block) void DataFlowAnalyzer::clearKnowledgeIfInvalidated(Expression const& _expr) { - SideEffectsCollector sideEffects(m_dialect, _expr); + SideEffectsCollector sideEffects(m_dialect, _expr, &m_functionSideEffects); if (sideEffects.invalidatesStorage()) m_storage.clear(); if (sideEffects.invalidatesMemory()) diff --git a/libyul/optimiser/LoadResolver.cpp b/libyul/optimiser/LoadResolver.cpp index 2a68149fe..3ff064fd7 100644 --- a/libyul/optimiser/LoadResolver.cpp +++ b/libyul/optimiser/LoadResolver.cpp @@ -23,6 +23,8 @@ #include #include +#include +#include #include using namespace std; @@ -32,35 +34,53 @@ using namespace yul; void LoadResolver::run(Dialect const& _dialect, Block& _ast) { bool containsMSize = MSizeFinder::containsMSize(_dialect, _ast); - LoadResolver{_dialect, !containsMSize}(_ast); + LoadResolver{ + _dialect, + SideEffectsPropagator::sideEffects(_dialect, CallGraphGenerator::callGraph(_ast)), + !containsMSize + }(_ast); } void LoadResolver::visit(Expression& _e) { + DataFlowAnalyzer::visit(_e); + + if (!dynamic_cast(&m_dialect)) + return; + if (_e.type() == typeid(FunctionCall)) { FunctionCall const& funCall = boost::get(_e); if (auto const* builtin = dynamic_cast(m_dialect).builtin(funCall.functionName.name)) - if (!builtin->parameters.empty() && funCall.arguments.at(0).type() == typeid(Identifier)) - { - YulString key = boost::get(funCall.arguments.at(0)).name; - if ( - builtin->instruction == dev::eth::Instruction::SLOAD && - m_storage.values.count(key) - ) - { - _e = Identifier{locationOf(_e), m_storage.values[key]}; - return; - } - else if ( - m_optimizeMLoad && - builtin->instruction == dev::eth::Instruction::MLOAD && - m_memory.values.count(key) - ) - { - _e = Identifier{locationOf(_e), m_memory.values[key]}; - return; - } - } + if (builtin->instruction) + tryResolve(_e, *builtin->instruction, funCall.arguments); + } + else if (_e.type() == typeid(FunctionalInstruction)) + { + FunctionalInstruction const& instruction = boost::get(_e); + tryResolve(_e, instruction.instruction, instruction.arguments); } } + +void LoadResolver::tryResolve( + Expression& _e, + dev::eth::Instruction _instruction, + vector const& _arguments +) +{ + if (_arguments.empty() || _arguments.at(0).type() != typeid(Identifier)) + return; + + YulString key = boost::get(_arguments.at(0)).name; + if ( + _instruction == dev::eth::Instruction::SLOAD && + m_storage.values.count(key) + ) + _e = Identifier{locationOf(_e), m_storage.values[key]}; + else if ( + m_optimizeMLoad && + _instruction == dev::eth::Instruction::MLOAD && + m_memory.values.count(key) + ) + _e = Identifier{locationOf(_e), m_memory.values[key]}; +} diff --git a/libyul/optimiser/LoadResolver.h b/libyul/optimiser/LoadResolver.h index 3db124594..37afc6b6e 100644 --- a/libyul/optimiser/LoadResolver.h +++ b/libyul/optimiser/LoadResolver.h @@ -22,11 +22,13 @@ #pragma once #include +#include namespace yul { struct EVMDialect; +struct BuiltinFunctionForEVM; /** * Optimisation stage that replaces expressions of type ``sload(x)`` and ``mload(x)`` by the value @@ -39,11 +41,16 @@ struct EVMDialect; class LoadResolver: public DataFlowAnalyzer { public: + /// Run the load resolver on the given complete AST. static void run(Dialect const& _dialect, Block& _ast); private: - LoadResolver(Dialect const& _dialect, bool _optimizeMLoad): - DataFlowAnalyzer(_dialect), + LoadResolver( + Dialect const& _dialect, + std::map _functionSideEffects, + bool _optimizeMLoad + ): + DataFlowAnalyzer(_dialect, std::move(_functionSideEffects)), m_optimizeMLoad(_optimizeMLoad) {} @@ -51,6 +58,12 @@ protected: using ASTModifier::visit; void visit(Expression& _e) override; + void tryResolve( + Expression& _e, + dev::eth::Instruction _instruction, + std::vector const& _arguments + ); + bool m_optimizeMLoad = false; }; diff --git a/libyul/optimiser/Semantics.cpp b/libyul/optimiser/Semantics.cpp index a4784af66..001193533 100644 --- a/libyul/optimiser/Semantics.cpp +++ b/libyul/optimiser/Semantics.cpp @@ -51,8 +51,12 @@ SideEffectsCollector::SideEffectsCollector(Dialect const& _dialect, Statement co visit(_statement); } -SideEffectsCollector::SideEffectsCollector(Dialect const& _dialect, Block const& _ast): - SideEffectsCollector(_dialect) +SideEffectsCollector::SideEffectsCollector( + Dialect const& _dialect, + Block const& _ast, + map const* _functionSideEffects +): + SideEffectsCollector(_dialect, _functionSideEffects) { operator()(_ast); } diff --git a/libyul/optimiser/Semantics.h b/libyul/optimiser/Semantics.h index 1135b7070..8953ab321 100644 --- a/libyul/optimiser/Semantics.h +++ b/libyul/optimiser/Semantics.h @@ -47,7 +47,11 @@ public: std::map const* _functionSideEffects = nullptr ); SideEffectsCollector(Dialect const& _dialect, Statement const& _statement); - SideEffectsCollector(Dialect const& _dialect, Block const& _ast); + SideEffectsCollector( + Dialect const& _dialect, + Block const& _ast, + std::map const* _functionSideEffects = nullptr + ); using ASTWalker::operator(); void operator()(FunctionalInstruction const& _functionalInstruction) override; diff --git a/libyul/optimiser/SimplificationRules.cpp b/libyul/optimiser/SimplificationRules.cpp index 48e883701..3f5d8541b 100644 --- a/libyul/optimiser/SimplificationRules.cpp +++ b/libyul/optimiser/SimplificationRules.cpp @@ -97,15 +97,19 @@ SimplificationRules::SimplificationRules() Pattern B(PatternKind::Constant); Pattern C(PatternKind::Constant); // Anything. + Pattern W; Pattern X; Pattern Y; + Pattern Z; A.setMatchGroup(1, m_matchGroups); B.setMatchGroup(2, m_matchGroups); C.setMatchGroup(3, m_matchGroups); - X.setMatchGroup(4, m_matchGroups); - Y.setMatchGroup(5, m_matchGroups); + W.setMatchGroup(4, m_matchGroups); + X.setMatchGroup(5, m_matchGroups); + Y.setMatchGroup(6, m_matchGroups); + Z.setMatchGroup(7, m_matchGroups); - addRules(simplificationRuleList(A, B, C, X, Y)); + addRules(simplificationRuleList(A, B, C, W, X, Y, Z)); assertThrow(isInitialized(), OptimizerException, "Rule list not properly initialized."); } diff --git a/libyul/optimiser/Suite.cpp b/libyul/optimiser/Suite.cpp index d1677bf53..ac92761d7 100644 --- a/libyul/optimiser/Suite.cpp +++ b/libyul/optimiser/Suite.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -118,6 +119,7 @@ void OptimiserSuite::run( ExpressionSimplifier::run(_dialect, ast); CommonSubexpressionEliminator::run(_dialect, ast); + LoadResolver::run(_dialect, ast); } { @@ -132,6 +134,7 @@ void OptimiserSuite::run( { // simplify again + LoadResolver::run(_dialect, ast); CommonSubexpressionEliminator::run(_dialect, ast); UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers); } @@ -161,6 +164,7 @@ void OptimiserSuite::run( RedundantAssignEliminator::run(_dialect, ast); RedundantAssignEliminator::run(_dialect, ast); CommonSubexpressionEliminator::run(_dialect, ast); + LoadResolver::run(_dialect, ast); } { @@ -176,6 +180,7 @@ void OptimiserSuite::run( SSATransform::run(ast, dispenser); RedundantAssignEliminator::run(_dialect, ast); RedundantAssignEliminator::run(_dialect, ast); + LoadResolver::run(_dialect, ast); ExpressionSimplifier::run(_dialect, ast); StructuralSimplifier{_dialect}(ast); BlockFlattener{}(ast); diff --git a/scripts/install_deps.sh b/scripts/install_deps.sh index c8e90b0d2..0617dd028 100755 --- a/scripts/install_deps.sh +++ b/scripts/install_deps.sh @@ -90,9 +90,12 @@ case $(uname -s) in 10.14) echo "Installing solidity dependencies on macOS 10.14 Mojave." ;; + 10.15) + echo "Installing solidity dependencies on macOS 10.15 Catalina." + ;; *) echo "Unsupported macOS version." - echo "We only support Mavericks, Yosemite, El Capitan, Sierra, High Sierra and Mojave." + echo "We only support Mavericks, Yosemite, El Capitan, Sierra, High Sierra, Mojave, and Catalina." exit 1 ;; esac diff --git a/test/liblll/Compiler.cpp b/test/liblll/Compiler.cpp index 27db45a5c..3e2b38889 100644 --- a/test/liblll/Compiler.cpp +++ b/test/liblll/Compiler.cpp @@ -299,6 +299,8 @@ BOOST_AUTO_TEST_CASE(valid_opcodes_functional) "(NUMBER)", "(DIFFICULTY)", "(GASLIMIT)", + "(CHAINID)", + "(SELFBALANCE)", "(POP 0)", "(MLOAD 0)", "(MSTORE 0 0)", diff --git a/test/libsolidity/semanticTests/smoke/failure.sol b/test/libsolidity/semanticTests/smoke/failure.sol index 9bad8c035..ee1064062 100644 --- a/test/libsolidity/semanticTests/smoke/failure.sol +++ b/test/libsolidity/semanticTests/smoke/failure.sol @@ -9,6 +9,9 @@ contract C { function g(bool _value) public pure { require(_value, "Value is false."); } + function h() public pure returns (uint) { + assert(false); + } } // ==== // EVMVersion: >homestead @@ -17,3 +20,4 @@ contract C { // e() -> FAILURE, hex"08c379a0", 0x20, 19, "Transaction failed." // f(bool): false -> FAILURE, hex"08c379a0", 0x20, 0 // g(bool): false -> FAILURE, hex"08c379a0", 0x20, 15, "Value is false." +// h() -> FAILURE \ No newline at end of file diff --git a/test/libsolidity/util/TestFunctionCall.cpp b/test/libsolidity/util/TestFunctionCall.cpp index a6fd22cb1..a63e02865 100644 --- a/test/libsolidity/util/TestFunctionCall.cpp +++ b/test/libsolidity/util/TestFunctionCall.cpp @@ -126,8 +126,11 @@ string TestFunctionCall::format( { boost::optional abiParams; - if (isFailure && !output.empty()) - abiParams = boost::make_optional(ContractABIUtils::failureParameters(output)); + if (isFailure) + { + if (!output.empty()) + abiParams = boost::make_optional(ContractABIUtils::failureParameters(output)); + } else abiParams = ContractABIUtils::parametersFromJsonOutputs( _errorReporter, diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/create2_and_mask.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/create2_and_mask.yul new file mode 100644 index 000000000..cd74d73ad --- /dev/null +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/create2_and_mask.yul @@ -0,0 +1,12 @@ +{ + let a := and(create2(0, 0, 0x20, 0), 0xffffffffffffffffffffffffffffffffffffffff) + let b := and(0xffffffffffffffffffffffffffffffffffffffff, create2(0, 0, 0x20, 0)) +} +// ==== +// step: expressionSimplifier +// EVMVersion: >=constantinople +// ---- +// { +// let a := create2(0, 0, 0x20, 0) +// let b := create2(0, 0, 0x20, 0) +// } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/create_and_mask.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/create_and_mask.yul new file mode 100644 index 000000000..c7cc887dc --- /dev/null +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/create_and_mask.yul @@ -0,0 +1,11 @@ +{ + let a := and(create(0, 0, 0x20), 0xffffffffffffffffffffffffffffffffffffffff) + let b := and(0xffffffffffffffffffffffffffffffffffffffff, create(0, 0, 0x20)) +} +// ==== +// step: expressionSimplifier +// ---- +// { +// let a := create(0, 0, 0x20) +// let b := create(0, 0, 0x20) +// } diff --git a/test/libyul/yulOptimizerTests/fullSuite/medium.yul b/test/libyul/yulOptimizerTests/fullSuite/medium.yul index bebb8c418..a27acf809 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/medium.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/medium.yul @@ -21,11 +21,10 @@ // ---- // { // { -// let _1 := 0x40 -// mstore(_1, add(mload(_1), 0x20)) -// let p := mload(_1) -// mstore(_1, add(p, _1)) -// mstore(add(p, 96), 2) -// mstore(_1, 0x20) +// let _1 := mload(0x40) +// mstore(0x40, add(_1, 0x20)) +// mstore(0x40, add(_1, 96)) +// mstore(add(_1, 128), 2) +// mstore(0x40, 0x20) // } // } diff --git a/test/libyul/yulOptimizerTests/fullSuite/storage.yul b/test/libyul/yulOptimizerTests/fullSuite/storage.yul index 9867345fa..4daff379f 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/storage.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/storage.yul @@ -10,6 +10,6 @@ // { // sstore(4, 5) // sstore(4, 3) -// sstore(8, sload(4)) +// sstore(8, 3) // } // } diff --git a/test/libyul/yulOptimizerTests/loadResolver/loop.yul b/test/libyul/yulOptimizerTests/loadResolver/loop.yul new file mode 100644 index 000000000..4f7b27734 --- /dev/null +++ b/test/libyul/yulOptimizerTests/loadResolver/loop.yul @@ -0,0 +1,18 @@ +{ + sstore(0, 123213) + for {let x := 0 let y} lt(x, sload(0)) { + x := add(x, 1)} {y := add(x, y) + } +} +// ==== +// step: loadResolver +// ---- +// { +// let _1 := 123213 +// let _2 := 0 +// sstore(_2, _1) +// let x := _2 +// let y +// for { } lt(x, _1) { x := add(x, 1) } +// { y := add(x, y) } +// } diff --git a/test/libyul/yulOptimizerTests/loadResolver/memory_with_different_kinds_of_invalidation.yul b/test/libyul/yulOptimizerTests/loadResolver/memory_with_different_kinds_of_invalidation.yul index 65312c8b4..a9487afa7 100644 --- a/test/libyul/yulOptimizerTests/loadResolver/memory_with_different_kinds_of_invalidation.yul +++ b/test/libyul/yulOptimizerTests/loadResolver/memory_with_different_kinds_of_invalidation.yul @@ -31,5 +31,5 @@ // mstore8(calldataload(_5), 4) // sstore(_5, mload(_2)) // mstore(_2, _17) -// sstore(_5, mload(_2)) +// sstore(_5, _17) // } diff --git a/test/libyul/yulOptimizerTests/loadResolver/side_effects_of_user_functions.yul b/test/libyul/yulOptimizerTests/loadResolver/side_effects_of_user_functions.yul new file mode 100644 index 000000000..b07883c3a --- /dev/null +++ b/test/libyul/yulOptimizerTests/loadResolver/side_effects_of_user_functions.yul @@ -0,0 +1,28 @@ +{ + function stores() { mstore(0, 1) } + function reads() { sstore(9, mload(7)) } + + mstore(2, 9) + reads() + sstore(0, mload(2)) + stores() + sstore(0, mload(2)) +} +// ==== +// step: loadResolver +// ---- +// { +// function stores() +// { mstore(0, 1) } +// function reads() +// { sstore(9, mload(7)) } +// let _6 := 9 +// let _7 := 2 +// mstore(_7, _6) +// reads() +// let _9 := _6 +// let _10 := 0 +// sstore(_10, _9) +// stores() +// sstore(_10, mload(_7)) +// } diff --git a/test/tools/ossfuzz/protoToAbiV2.cpp b/test/tools/ossfuzz/protoToAbiV2.cpp index bebaeb95e..f53205398 100644 --- a/test/tools/ossfuzz/protoToAbiV2.cpp +++ b/test/tools/ossfuzz/protoToAbiV2.cpp @@ -63,8 +63,6 @@ void ProtoConverter::visitType( std::string varName, paramName; createDeclAndParamList(_type, _dataType, varName, paramName); addCheckedVarDef(_dataType, varName, paramName, _value); - // Update right padding of type - m_isLastParamRightPadded = isDataTypeBytesOrString(_dataType); } void ProtoConverter::appendVarDeclToOutput( @@ -451,6 +449,8 @@ void ProtoConverter::visit(DynamicByteArrayType const& _x) isBytes ) ); + // Update right padding of type + m_isLastDynParamRightPadded = true; } // TODO: Implement struct visitor @@ -658,23 +658,23 @@ void ProtoConverter::visit(ArrayType const& _x) { case ArrayType::kInty: baseType = getIntTypeAsString(_x.inty()); - m_isLastParamRightPadded = false; + m_isLastDynParamRightPadded = false; break; case ArrayType::kByty: baseType = getFixedByteTypeAsString(_x.byty()); - m_isLastParamRightPadded = false; + m_isLastDynParamRightPadded = false; break; case ArrayType::kAdty: baseType = getAddressTypeAsString(_x.adty()); - m_isLastParamRightPadded = false; + m_isLastDynParamRightPadded = false; break; case ArrayType::kBoolty: baseType = getBoolTypeAsString(); - m_isLastParamRightPadded = false; + m_isLastDynParamRightPadded = false; break; case ArrayType::kDynbytesty: baseType = bytesArrayTypeAsString(_x.dynbytesty()); - m_isLastParamRightPadded = true; + m_isLastDynParamRightPadded = true; break; case ArrayType::kStty: case ArrayType::BASE_TYPE_ONEOF_NOT_SET: @@ -861,7 +861,7 @@ void ProtoConverter::visit(TestFunction const& _x) )") ("parameterNames", dev::suffixedVariableNameList(s_varNamePrefix, 0, m_varCounter)) ("invalidLengthFuzz", std::to_string(_x.invalid_encoding_length())) - ("isRightPadded", isLastParamRightPadded() ? "true" : "false") + ("isRightPadded", isLastDynParamRightPadded() ? "true" : "false") ("atLeastOneVar", m_varCounter > 0) .render(); } diff --git a/test/tools/ossfuzz/protoToAbiV2.h b/test/tools/ossfuzz/protoToAbiV2.h index 6e69d740b..401867364 100644 --- a/test/tools/ossfuzz/protoToAbiV2.h +++ b/test/tools/ossfuzz/protoToAbiV2.h @@ -103,7 +103,7 @@ public: m_counter(0), m_varCounter(0), m_returnValue(1), - m_isLastParamRightPadded(false) + m_isLastDynParamRightPadded(false) {} ProtoConverter(ProtoConverter const&) = delete; @@ -274,9 +274,9 @@ private: return ((isValueType(_dataType) || m_isStateVar) ? "" : "memory"); } - bool isLastParamRightPadded() + bool isLastDynParamRightPadded() { - return m_isLastParamRightPadded; + return m_isLastDynParamRightPadded; } // Static declarations @@ -466,10 +466,10 @@ private: unsigned m_varCounter; /// Monotonically increasing return value for error reporting unsigned m_returnValue; - /// Flag that indicates if last parameter passed to a function call - /// is of a type that is going to be right padded by the ABI - /// encoder. - bool m_isLastParamRightPadded; + /// Flag that indicates if last dynamically encoded parameter + /// passed to a function call is of a type that is going to be + /// right padded by the ABI encoder. + bool m_isLastDynParamRightPadded; static unsigned constexpr s_maxArrayLength = 4; static unsigned constexpr s_maxArrayDimensions = 4; static unsigned constexpr s_maxDynArrayLength = 256; diff --git a/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp b/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp index 45584a19f..d6011d8c7 100644 --- a/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp +++ b/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp @@ -180,6 +180,8 @@ u256 EVMInstructionInterpreter::eval( return m_state.address; case Instruction::BALANCE: return m_state.balance; + case Instruction::SELFBALANCE: + return m_state.selfbalance; case Instruction::ORIGIN: return m_state.origin; case Instruction::CALLER: @@ -208,6 +210,8 @@ u256 EVMInstructionInterpreter::eval( return 0; case Instruction::GASPRICE: return m_state.gasprice; + case Instruction::CHAINID: + return m_state.chainid; case Instruction::EXTCODESIZE: return u256(keccak256(h256(arg[0]))) & 0xffffff; case Instruction::EXTCODEHASH: diff --git a/test/tools/yulInterpreter/Interpreter.h b/test/tools/yulInterpreter/Interpreter.h index bce4928c1..04688a1ae 100644 --- a/test/tools/yulInterpreter/Interpreter.h +++ b/test/tools/yulInterpreter/Interpreter.h @@ -70,6 +70,7 @@ struct InterpreterState std::map storage; dev::u160 address = 0x11111111; dev::u256 balance = 0x22222222; + dev::u256 selfbalance = 0x22223333; dev::u160 origin = 0x33333333; dev::u160 caller = 0x44444444; dev::u256 callvalue = 0x55555555; @@ -81,6 +82,7 @@ struct InterpreterState dev::u256 blockNumber = 1024; dev::u256 difficulty = 0x9999999; dev::u256 gaslimit = 4000000; + dev::u256 chainid = 0x01; /// Log of changes / effects. Sholud be structured data in the future. std::vector trace; /// This is actually an input parameter that more or less limits the runtime.