/* 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 . */ /** * @date 2017 * Unit tests for the Yul function inliner. */ #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace dev; using namespace dev::julia; using namespace dev::julia::test; using namespace dev::solidity; namespace { string inlinableFunctions(string const& _source) { auto ast = disambiguate(_source); InlinableExpressionFunctionFinder funFinder; funFinder(ast); return boost::algorithm::join( funFinder.inlinableFunctions() | boost::adaptors::map_keys, "," ); } string inlineFunctions(string const& _source, bool _yul = true) { auto ast = disambiguate(_source, _yul); ExpressionInliner(ast).run(); return assembly::AsmPrinter(_yul)(ast); } string fullInline(string const& _source, bool _yul = true) { Block ast = disambiguate(_source, _yul); (FunctionHoister{})(ast); (FunctionGrouper{})(ast);\ FullInliner(ast).run(); return assembly::AsmPrinter(_yul)(ast); } } BOOST_AUTO_TEST_SUITE(YulInlinableFunctionFilter) BOOST_AUTO_TEST_CASE(smoke_test) { BOOST_CHECK_EQUAL(inlinableFunctions("{ }"), ""); } BOOST_AUTO_TEST_CASE(simple) { BOOST_CHECK_EQUAL(inlinableFunctions("{ function f() -> x:u256 { x := 2:u256 } }"), "f"); BOOST_CHECK_EQUAL(inlinableFunctions("{" "function g(a:u256) -> b:u256 { b := a }" "function f() -> x:u256 { x := g(2:u256) }" "}"), "f,g"); } BOOST_AUTO_TEST_CASE(simple_inside_structures) { BOOST_CHECK_EQUAL(inlinableFunctions("{" "switch 2:u256 " "case 2:u256 {" "function g(a:u256) -> b:u256 { b := a }" "function f() -> x:u256 { x := g(2:u256) }" "}" "}"), "f,g"); BOOST_CHECK_EQUAL(inlinableFunctions("{" "for {" "function g(a:u256) -> b:u256 { b := a }" "} 1:u256 {" "function f() -> x:u256 { x := g(2:u256) }" "}" "{" "function h() -> y:u256 { y := 2:u256 }" "}" "}"), "f,g,h"); } BOOST_AUTO_TEST_CASE(negative) { BOOST_CHECK_EQUAL(inlinableFunctions("{ function f() -> x:u256 { } }"), ""); BOOST_CHECK_EQUAL(inlinableFunctions("{ function f() -> x:u256 { x := 2:u256 {} } }"), ""); BOOST_CHECK_EQUAL(inlinableFunctions("{ function f() -> x:u256 { x := f() } }"), ""); BOOST_CHECK_EQUAL(inlinableFunctions("{ function f() -> x:u256 { x := x } }"), ""); BOOST_CHECK_EQUAL(inlinableFunctions("{ function f() -> x:u256, y:u256 { x := 2:u256 } }"), ""); BOOST_CHECK_EQUAL(inlinableFunctions( "{ function g() -> x:u256, y:u256 {} function f(y:u256) -> x:u256 { x,y := g() } }"), ""); BOOST_CHECK_EQUAL(inlinableFunctions("{ function f(y:u256) -> x:u256 { y := 2:u256 } }"), ""); } BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE(YulFunctionInliner) BOOST_AUTO_TEST_CASE(simple) { BOOST_CHECK_EQUAL( inlineFunctions("{ function f() -> x:u256 { x := 2:u256 } let y:u256 := f() }"), format("{ function f() -> x:u256 { x := 2:u256 } let y:u256 := 2:u256 }") ); } BOOST_AUTO_TEST_CASE(with_args) { BOOST_CHECK_EQUAL( inlineFunctions("{ function f(a:u256) -> x:u256 { x := a } let y:u256 := f(7:u256) }"), format("{ function f(a:u256) -> x:u256 { x := a } let y:u256 := 7:u256 }") ); } BOOST_AUTO_TEST_CASE(no_inline_with_mload) { // Does not inline because mload could be moved out of sequence BOOST_CHECK_EQUAL( inlineFunctions("{ function f(a) -> x { x := a } let y := f(mload(2)) }", false), format("{ function f(a) -> x { x := a } let y := f(mload(2)) }", false) ); } BOOST_AUTO_TEST_CASE(no_move_with_side_effects) { // The calls to g and h cannot be moved because g and h are not movable. Therefore, the call // to f is not inlined. BOOST_CHECK_EQUAL( inlineFunctions("{" "function f(a, b) -> x { x := add(b, a) }" "function g() -> y { y := mload(0) mstore(0, 4) }" "function h() -> z { mstore(0, 4) z := mload(0) }" "let r := f(g(), h())" "}", false), format("{" "function f(a, b) -> x { x := add(b, a) }" "function g() -> y { y := mload(0) mstore(0, 4) }" "function h() -> z { mstore(0, 4) z := mload(0) }" "let r := f(g(), h())" "}", false) ); } BOOST_AUTO_TEST_CASE(complex_with_evm) { BOOST_CHECK_EQUAL( inlineFunctions("{ function f(a) -> x { x := add(a, a) } let y := f(calldatasize()) }", false), format("{ function f(a) -> x { x := add(a, a) } let y := add(calldatasize(), calldatasize()) }", false) ); } BOOST_AUTO_TEST_CASE(double_calls) { BOOST_CHECK_EQUAL( inlineFunctions("{" "function f(a) -> x { x := add(a, a) }" "function g(b, c) -> y { y := mul(mload(c), f(b)) }" "let y := g(calldatasize(), 7)" "}", false), format("{" "function f(a) -> x { x := add(a, a) }" "function g(b, c) -> y { y := mul(mload(c), add(b, b)) }" "let y_1 := mul(mload(7), add(calldatasize(), calldatasize()))" "}", false) ); } BOOST_AUTO_TEST_CASE(double_recursive_calls) { BOOST_CHECK_EQUAL( inlineFunctions("{" "function f(a, r) -> x { x := g(a, g(r, r)) }" "function g(b, s) -> y { y := f(b, f(s, s)) }" "let y := g(calldatasize(), 7)" "}", false), format("{" "function f(a, r) -> x { x := g(a, f(r, f(r, r))) }" "function g(b, s) -> y { y := f(b, g(s, f(s, f(s, s))))}" "let y_1 := f(calldatasize(), g(7, f(7, f(7, 7))))" "}", false) ); } BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE(YulFullInliner) BOOST_AUTO_TEST_CASE(simple) { BOOST_CHECK_EQUAL( fullInline("{" "function f(a) -> x { let r := mul(a, a) x := add(r, r) }" "let y := add(f(sload(mload(2))), mload(7))" "}", false), format("{" "{" "let _1 := mload(7)" "let f_a := sload(mload(2))" "let f_x" "{" "let f_r := mul(f_a, f_a)" "f_x := add(f_r, f_r)" "}" "let y := add(f_x, _1)" "}" "function f(a) -> x" "{" "let r := mul(a, a)" "x := add(r, r)" "}" "}", false) ); } BOOST_AUTO_TEST_CASE(multi_fun) { BOOST_CHECK_EQUAL( fullInline("{" "function f(a) -> x { x := add(a, a) }" "function g(b, c) -> y { y := mul(mload(c), f(b)) }" "let y := g(f(3), 7)" "}", false), format("{" "{" "let g_c := 7 " "let f_a_1 := 3 " "let f_x_1 " "{ f_x_1 := add(f_a_1, f_a_1) } " "let g_y " "{" "let g_f_a := f_x_1 " "let g_f_x " "{" "g_f_x := add(g_f_a, g_f_a)" "}" "g_y := mul(mload(g_c), g_f_x)" "}" "let y_1 := g_y" "}" "function f(a) -> x" "{" "x := add(a, a)" "}" "function g(b, c) -> y" "{" "let f_a := b " "let f_x " "{" "f_x := add(f_a, f_a)" "}" "y := mul(mload(c), f_x)" "}" "}", false) ); } BOOST_AUTO_TEST_CASE(move_up_rightwards_arguments) { BOOST_CHECK_EQUAL( fullInline("{" "function f(a, b, c) -> x { x := add(a, b) x := mul(x, c) }" "let y := add(mload(1), add(f(mload(2), mload(3), mload(4)), mload(5)))" "}", false), format("{" "{" "let _1 := mload(5)" "let f_c := mload(4)" "let f_b := mload(3)" "let f_a := mload(2)" "let f_x" "{" "f_x := add(f_a, f_b)" "f_x := mul(f_x, f_c)" "}" "let y := add(mload(1), add(f_x, _1))" "}" "function f(a, b, c) -> x" "{" "x := add(a, b)" "x := mul(x, c)" "}" "}", false) ); } BOOST_AUTO_TEST_CASE(pop_result) { // This tests that `pop(r)` is removed. BOOST_CHECK_EQUAL( fullInline("{" "function f(a) -> x { let r := mul(a, a) x := add(r, r) }" "pop(add(f(7), 2))" "}", false), format("{" "{" "let _1 := 2 " "let f_a := 7 " "let f_x " "{" "let f_r := mul(f_a, f_a) " "f_x := add(f_r, f_r)" "}" "{" "}" "}" "function f(a) -> x" "{" "let r := mul(a, a) " "x := add(r, r)" "}" "}", false) ); } BOOST_AUTO_TEST_SUITE_END() 6 04:11:49 +0800'>2007-02-061-2/+2 * - Reflects the update of the Japanese message file.clsung2007-02-052-4/+5 * Put distfile on master_site_locallofi2007-02-051-1/+2 * - Update to 2.49rafan2007-02-042-5/+5 * fix build (by using libtool:15) with recent CURRENTs where objformat went awayoliver2007-02-042-1/+1 * - Update to 2.4.4rafan2007-02-032-4/+4 * - Update to 20070124acm2007-02-025-84/+78 * Use libtool port instead of included version to avoid objformat a.out botchkris2007-02-013-0/+3 * - add category gnustepdinoex2007-02-011-1/+1 * - Fix spelling of CONFLICTSpav2007-01-312-2/+2 * - Remove support for a.out format and PORTOBJFORMAT variable from individualpav2007-01-302-17/+2 * enhance the descriptionoliver2007-01-291-3/+5 * Use libtool port instead of included one to avoid objformat a.out botchkris2007-01-282-0/+2 * - Update to 1.7.1miwi2007-01-288-36/+82 * - Add PORTSCOUT variable.shaun2007-01-261-1/+3 * Update to 0.7.0.mezz2007-01-264-18/+13 * - Added files/ patch-api_model.c, patch-prnt_hpijs_configurenivit2007-01-2524-492/+654 * - Update to 20070120acm2007-01-252-5/+6 * - Changed master site (the old one has disappeared)nivit2007-01-241-2/+3 * - Update to 5.2.4miwi2007-01-242-4/+4 * - Fix build on gcc 4. These two changes are stole from print/ghostscript-afpl.rafan2007-01-234-34/+576 * - Fix build on gcc 4. Patch is stealed from print/ghostscript-afpl,rafan2007-01-232-0/+540 * - Update to 2.14rafan2007-01-232-4/+4 * Import xfce 4.4oliver2007-01-234-74/+63 * - Generalize libgcj dependency linepav2007-01-221-1/+1 * Undo the "verbosity reduction" hunk, that slipped with the last upgrade.mi2007-01-215-35/+35 * - Fix previous revision to DTRTpav2007-01-191-1/+1 * - Allow usage of gcc 4.2 and uppav2007-01-191-2/+2 * - Update to 1.4.3miwi2007-01-1815-85/+345 * - update to 0.81itetcu2007-01-185-176/+74 * Update to 7.0.9. Various security vulnerabilities have been fixed.hrs2007-01-1818-673/+32 * - update to 5.3itetcu2007-01-182-10/+7 * - update to 1.3.2itetcu2007-01-182-5/+5 * - Update to 2.48miwi2007-01-143-6/+7 * - Update to 20070108acm2007-01-142-4/+4 * - update to use new bsd.gnustep.mkdinoex2007-01-131-3/+2 * - Use USE_ICONV instead of LIB_DEPENDSrafan2007-01-121-4/+4 * - Update to 1.21.1erwin2007-01-064-17/+51 * 2007-01-04 net/tund: distfile disappeared and has no homepagemiwi2007-01-068-148/+0 * 2007-01-01 graphics/teddy: No new releases in the past 4 yearsmiwi2007-01-0636-1691/+0 * 2006-12-01 net-p2p/gnome-btdownload: does not run with BitTorrent 4.x yetmiwi2007-01-067-273/+0 * - Update to 0.9.5rafan2007-01-053-6/+11 * upgrade to 5.2.3ijliao2007-01-052-5/+5 * Took a lot of nice patches from Ubuntu Linux to make both of ports work bettermezz2007-01-0521-7/+1949 * Resurrect print/latex-pgf and print/latex-beamer and updatehrs2007-01-058-0/+1094 * - Chase security/gnutls updatenovel2007-01-021-2/+2 * -Update to 0.6.7.mezz2007-01-023-8/+10 * - Update to 0.16.0.mezz2007-01-021-0/+2 * Grab MAINTAINERahze2007-01-011-1/+1 * - Be compatible with Debian's font famliy name forrafan2007-01-012-2/+6 * ReportLab is a software library that lets you directly createmiwi2006-12-318-0/+883 * - Update to 2.13rafan2006-12-302-4/+4 * - add option WITH_I18Ndinoex2006-12-303-0/+46 * - RUN_DEPEND on Ghostscript which besides bringing in some needed fonts alsoitetcu2006-12-292-28/+20 * Use SF.net mirrors for MASTER_SITESitetcu2006-12-271-1/+3 * - Update to 20061224acm2006-12-273-6/+5 * Mark BROKEN: fails to fetch.linimon2006-12-271-0/+2 * -Update to final 5.0.0.mezz2006-12-256-152/+96 * Update to 0.6.6ahze2006-12-252-5/+4 * Update MAINTAINER email address of my portsnox2006-12-241-1/+1 * - honor PTHREAD_LIBSdinoex2006-12-221-39/+40 * In preparation to deprecate shells/bash2:bsam2006-12-221-1/+1 * - Don't install t1asm, depends on t1utils insteadrafan2006-12-213-1/+12 * - move RUN_DEPENDS to BUILD_DEPENDSdinoex2006-12-181-2/+2 * - drop empty filedinoex2006-12-181-1/+0 * - Update to 20061212acm2006-12-164-8/+16 * - Update to 20061214acm2006-12-165-25/+24 * - Add backup MASTER_SITESmiwi2006-12-141-1/+3 * - Honor CC in the lib subdirjmz2006-12-147-1/+101 * Update the ftp/curl port to 7.16.0.roam2006-12-131-1/+2 * Remove expired ports:vd2006-12-1341-1021/+0 * Remove expired leaf ports:vd2006-12-128-399/+0 * - take maintainershipdinoex2006-12-102-6/+3 * Fix the typo in my last commit. I accidentally committed the wrong versiongabor2006-12-101-1/+1 * - Updated email address in my portsnivit2006-12-104-4/+4 * - Fix fetchinggabor2006-12-093-11/+6 * - Update to 2.5.5gabor2006-12-093-51/+15 * - Respect X11BASErafan2006-12-091-0/+1 * - Fix Buildmiwi2006-12-091-1/+1 * This package used to extract the revision and file informationmiwi2006-12-075-0/+64 * Reset asa@agava.com after several months of inactivity and no response tolinimon2006-12-062-2/+2 * - Update to 1.2.7sat2006-12-065-610/+793 * - Update to 8.15.3miwi2006-12-067-32/+595 * - Update to 1.5.0miwi2006-12-067-83/+31 * - Deprecateerwin2006-12-051-0/+3 * - Deprecateerwin2006-12-051-0/+3 * - Deprecateerwin2006-12-051-0/+3 * Correct path to Compress::Zlib.pm after recent p5-Compress-Zlib update.demon2006-12-031-1/+1 * - Update to current snapshot (should fix compatiblity problems with the newstas2006-12-031-4/+10 * - Update to 2.12rafan2006-11-292-4/+4 * - Respect X11BASEmiwi2006-11-282-6/+15 * Make it compatible with a nonstandard X11BASE (untested).jmz2006-11-241-4/+2 * - Update to 2.4.3pav2006-11-243-13/+10 * Remove expired leaf port:vd2006-11-225-57/+0 * - Update to 3.6.2miwi2006-11-167-85/+18 * - Do not overwrite configuration file. Bump PORTREVISIONrafan2006-11-142-13/+23 * - Do not install t1asm, depending on print/t1utils instead.rafan2006-11-132-3/+5 * Remove expired ports:vd2006-11-094-40/+0 * Mark BROKEN and DEPRECATED, the project was born dead.ale2006-11-081-0/+4 * - Marked BROKEN on FreeBSD 7 as it doesn't compile.alepulver2006-11-081-6/+23 * Update my email address in all ports that I maintain.laszlof2006-11-071-1/+1 * Update to 2.1.2 release.ale2006-11-072-4/+4 * - Update to 20061031acm2006-11-072-4/+4 * - Update to 20061031acm2006-11-073-8/+17 * PDF generation using only PHP, without requiring any external libraries.miwi2006-11-064-0/+32 * - Update to 1.3.3.4miwi2006-11-066-176/+194 * INSTALLS_SHLIB -> USE_LDCONFIG.mezz2006-11-051-1/+2 * -INSTALLS_SHLIB -> USE_LDCONFIG.[1]mezz2006-11-051-2/+4 * - Some tweaks, no patch requiredrafan2006-11-033-26/+13 * Update to 2.1.1 release.ale2006-11-012-5/+4 * Update to 7.0.0p3 release and make it fetchable again.ale2006-11-012-5/+5 * - Pass maintainership to submittermiwi2006-11-011-1/+1 * - Update to 4.7.0rafan2006-10-313-31/+39 * GSPdf is a Postscript and Pdf Viewer for GNUstep.dinoex2006-10-315-0/+56 * - Update to 2.11rafan2006-10-312-4/+4 * - Update to 20061010acm2006-10-205-8/+164 * Restore major 7.0.0p1 PORTVERSION to make scripts happy.ale2006-10-161-4/+3 * Fix fetching.ale2006-10-151-2/+3 * Update to 7.0.0p1 release and make it fetchable again.ale2006-10-152-5/+5 * Correct a typo when WITH_CJK is defined.marcus2006-10-151-2/+2 * Chase the GNOME X11BASE to LOCALBASE move, and fix the build with themarcus2006-10-147-15/+73 * Presenting GNOME 2.16.1 for FreeBSD. This release represents a massivemarcus2006-10-1412-160/+113 * - Unbreakerwin2006-10-121-7/+9