mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #9805 from ethereum/develop
Merge develop into breaking.
This commit is contained in:
commit
efe829b4b2
@ -9,23 +9,23 @@ version: 2.1
|
|||||||
parameters:
|
parameters:
|
||||||
ubuntu-1804-docker-image:
|
ubuntu-1804-docker-image:
|
||||||
type: string
|
type: string
|
||||||
# solbuildpackpusher/solidity-buildpack-deps:ubuntu1804-2
|
# solbuildpackpusher/solidity-buildpack-deps:ubuntu1804-3
|
||||||
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:9ab317e583c395e50884ba82e9f99811c374344cea4c550725be8ec836e07acc"
|
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:19f613d2ac47fedff654dacef984d8a64726c4d67ae8f2667a85ee7d97ac4c1c"
|
||||||
ubuntu-2004-docker-image:
|
ubuntu-2004-docker-image:
|
||||||
type: string
|
type: string
|
||||||
# solbuildpackpusher/solidity-buildpack-deps:ubuntu2004-2
|
# solbuildpackpusher/solidity-buildpack-deps:ubuntu2004-3
|
||||||
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:cbfa42d8ecbe94391ba8837e218869242666de7a0da6ccac065a856c85b6a6a0"
|
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:aeedbe7390a7383815f0cf0f8a1b8bf84dc5e334a3b0043ebcdf8b1bdbe80a81"
|
||||||
ubuntu-2004-clang-docker-image:
|
ubuntu-2004-clang-docker-image:
|
||||||
type: string
|
type: string
|
||||||
# solbuildpackpusher/solidity-buildpack-deps:ubuntu2004.clang-2
|
# solbuildpackpusher/solidity-buildpack-deps:ubuntu2004.clang-3
|
||||||
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:7a4d5271b5552139d9f2caefc50d42f401bf74132cf8f253e199e11c80ab42de"
|
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:2593c15689dee5b5bdfff96a36c8c68a468cd3b147c41f75b820b8fabc257be9"
|
||||||
ubuntu-1604-clang-ossfuzz-docker-image:
|
ubuntu-1604-clang-ossfuzz-docker-image:
|
||||||
type: string
|
type: string
|
||||||
# solbuildpackpusher/solidity-buildpack-deps:ubuntu1604.clang.ossfuzz-3
|
# solbuildpackpusher/solidity-buildpack-deps:ubuntu1604.clang.ossfuzz-4
|
||||||
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:6fa6914bd81abcac4b162c738e6ff05d87cefe7655e3859c7a827e5a8ec20dc7"
|
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:842126b164b3542f05bff2611459e21edc7e3e2c81ca9d1f43396c8cf066f7ca"
|
||||||
emscripten-docker-image:
|
emscripten-docker-image:
|
||||||
type: string
|
type: string
|
||||||
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:d557d015918c3cf68b0d22839bab41013f0757b651a7fef21595f89721dbebcc"
|
default: "solbuildpackpusher/solidity-buildpack-deps@sha256:23dad3b34deae8107c8551804ef299f6a89c23ed506e8118fac151e2bdc9018c"
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
|
|
||||||
@ -208,6 +208,11 @@ defaults:
|
|||||||
requires:
|
requires:
|
||||||
- b_ubu_release
|
- b_ubu_release
|
||||||
|
|
||||||
|
- workflow_archlinux: &workflow_archlinux
|
||||||
|
<<: *workflow_trigger_on_tags
|
||||||
|
requires:
|
||||||
|
- b_archlinux
|
||||||
|
|
||||||
- workflow_ubuntu2004_codecov: &workflow_ubuntu2004_codecov
|
- workflow_ubuntu2004_codecov: &workflow_ubuntu2004_codecov
|
||||||
<<: *workflow_trigger_on_tags
|
<<: *workflow_trigger_on_tags
|
||||||
requires:
|
requires:
|
||||||
@ -657,6 +662,25 @@ jobs:
|
|||||||
t_ubu_soltest: &t_ubu_soltest
|
t_ubu_soltest: &t_ubu_soltest
|
||||||
<<: *test_ubuntu2004
|
<<: *test_ubuntu2004
|
||||||
|
|
||||||
|
t_archlinux_soltest: &t_archlinux_soltest
|
||||||
|
docker:
|
||||||
|
- image: archlinux/base
|
||||||
|
environment:
|
||||||
|
EVM: constantinople
|
||||||
|
OPTIMIZE: 0
|
||||||
|
TERM: xterm
|
||||||
|
steps:
|
||||||
|
- run:
|
||||||
|
name: Install runtime dependencies
|
||||||
|
command: |
|
||||||
|
pacman --noconfirm -Syu --noprogressbar --needed base-devel boost cmake z3 cvc4 git openssh tar
|
||||||
|
- checkout
|
||||||
|
- attach_workspace:
|
||||||
|
at: build
|
||||||
|
- run: *run_soltest
|
||||||
|
- store_test_results: *store_test_results
|
||||||
|
- store_artifacts: *artifacts_test_results
|
||||||
|
|
||||||
t_ubu_soltest_enforce_yul: &t_ubu_soltest_enforce_yul
|
t_ubu_soltest_enforce_yul: &t_ubu_soltest_enforce_yul
|
||||||
docker:
|
docker:
|
||||||
- image: << pipeline.parameters.ubuntu-2004-docker-image >>
|
- image: << pipeline.parameters.ubuntu-2004-docker-image >>
|
||||||
@ -870,7 +894,6 @@ workflows:
|
|||||||
|
|
||||||
# build-only
|
# build-only
|
||||||
- b_docs: *workflow_trigger_on_tags
|
- b_docs: *workflow_trigger_on_tags
|
||||||
- b_archlinux: *workflow_trigger_on_tags
|
|
||||||
- b_ubu_cxx20: *workflow_trigger_on_tags
|
- b_ubu_cxx20: *workflow_trigger_on_tags
|
||||||
- b_ubu_ossfuzz: *workflow_trigger_on_tags
|
- b_ubu_ossfuzz: *workflow_trigger_on_tags
|
||||||
|
|
||||||
@ -879,6 +902,10 @@ workflows:
|
|||||||
- t_osx_cli: *workflow_osx
|
- t_osx_cli: *workflow_osx
|
||||||
- t_osx_soltest: *workflow_osx
|
- t_osx_soltest: *workflow_osx
|
||||||
|
|
||||||
|
# ArchLinux build and tests
|
||||||
|
- b_archlinux: *workflow_trigger_on_tags
|
||||||
|
- t_archlinux_soltest: *workflow_archlinux
|
||||||
|
|
||||||
# Ubuntu build and tests
|
# Ubuntu build and tests
|
||||||
- b_ubu: *workflow_trigger_on_tags
|
- b_ubu: *workflow_trigger_on_tags
|
||||||
- b_ubu18: *workflow_trigger_on_tags
|
- b_ubu18: *workflow_trigger_on_tags
|
||||||
|
@ -43,13 +43,13 @@ then
|
|||||||
./scripts/install_obsolete_jsoncpp_1_7_4.sh
|
./scripts/install_obsolete_jsoncpp_1_7_4.sh
|
||||||
|
|
||||||
# z3
|
# z3
|
||||||
wget https://github.com/Z3Prover/z3/releases/download/z3-4.8.8/z3-4.8.8-x64-osx-10.14.6.zip
|
wget https://github.com/Z3Prover/z3/releases/download/z3-4.8.9/z3-4.8.9-x64-osx-10.14.6.zip
|
||||||
unzip z3-4.8.8-x64-osx-10.14.6.zip
|
unzip z3-4.8.9-x64-osx-10.14.6.zip
|
||||||
rm -f z3-4.8.8-x64-osx-10.14.6.zip
|
rm -f z3-4.8.9-x64-osx-10.14.6.zip
|
||||||
cp z3-4.8.8-x64-osx-10.14.6/bin/libz3.a /usr/local/lib
|
cp z3-4.8.9-x64-osx-10.14.6/bin/libz3.a /usr/local/lib
|
||||||
cp z3-4.8.8-x64-osx-10.14.6/bin/z3 /usr/local/bin
|
cp z3-4.8.9-x64-osx-10.14.6/bin/z3 /usr/local/bin
|
||||||
cp z3-4.8.8-x64-osx-10.14.6/include/* /usr/local/include
|
cp z3-4.8.9-x64-osx-10.14.6/include/* /usr/local/include
|
||||||
rm -rf z3-4.8.8-x64-osx-10.14.6
|
rm -rf z3-4.8.9-x64-osx-10.14.6
|
||||||
|
|
||||||
# evmone
|
# evmone
|
||||||
wget https://github.com/ethereum/evmone/releases/download/v0.4.0/evmone-0.4.0-darwin-x86_64.tar.gz
|
wget https://github.com/ethereum/evmone/releases/download/v0.4.0/evmone-0.4.0-darwin-x86_64.tar.gz
|
||||||
|
@ -113,7 +113,7 @@ matrix:
|
|||||||
before_install:
|
before_install:
|
||||||
- nvm install 10
|
- nvm install 10
|
||||||
- nvm use 10
|
- nvm use 10
|
||||||
- docker pull solbuildpackpusher/solidity-buildpack-deps@sha256:d557d015918c3cf68b0d22839bab41013f0757b651a7fef21595f89721dbebcc
|
- docker pull solbuildpackpusher/solidity-buildpack-deps@sha256:23dad3b34deae8107c8551804ef299f6a89c23ed506e8118fac151e2bdc9018c
|
||||||
env:
|
env:
|
||||||
- SOLC_EMSCRIPTEN=On
|
- SOLC_EMSCRIPTEN=On
|
||||||
- SOLC_INSTALL_DEPS_TRAVIS=Off
|
- SOLC_INSTALL_DEPS_TRAVIS=Off
|
||||||
|
@ -8,12 +8,19 @@ Language Features:
|
|||||||
|
|
||||||
|
|
||||||
Compiler Features:
|
Compiler Features:
|
||||||
|
* SMTChecker: Support shifts.
|
||||||
* SMTChecker: Support structs.
|
* SMTChecker: Support structs.
|
||||||
|
* SMTChecker: Support ``type(T).min`` and ``type(T).max``.
|
||||||
* Yul Optimizer: Prune unused parameters in functions.
|
* Yul Optimizer: Prune unused parameters in functions.
|
||||||
|
* Yul Optimizer: Inline into functions further down in the call graph first.
|
||||||
|
* Yul Optimizer: Try to simplify function names.
|
||||||
|
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
* Type Checker: Disallow ``virtual`` for modifiers in libraries.
|
* Type Checker: Disallow ``virtual`` for modifiers in libraries.
|
||||||
* ViewPureChecker: Prevent visibility check on constructors.
|
* ViewPureChecker: Prevent visibility check on constructors.
|
||||||
|
* Type system: Fix internal error on implicit conversion of contract instance to the type of its ``super``.
|
||||||
|
* Type system: Fix named parameters in overloaded function and event calls being matched incorrectly if the order differs from the declaration.
|
||||||
|
|
||||||
### 0.7.1 (2020-09-02)
|
### 0.7.1 (2020-09-02)
|
||||||
|
|
||||||
@ -43,6 +50,7 @@ Bugfixes:
|
|||||||
* SMTChecker: Fix internal error on lvalue unary operators with tuples.
|
* SMTChecker: Fix internal error on lvalue unary operators with tuples.
|
||||||
* SMTChecker: Fix internal error on tuple assignment.
|
* SMTChecker: Fix internal error on tuple assignment.
|
||||||
* SMTChecker: Fix internal error on tuples of one element that have tuple type.
|
* SMTChecker: Fix internal error on tuples of one element that have tuple type.
|
||||||
|
* SMTChecker: Fix internal error when using imported code.
|
||||||
* SMTChecker: Fix soundness of array ``pop``.
|
* SMTChecker: Fix soundness of array ``pop``.
|
||||||
* Type Checker: Disallow ``using for`` directive inside interfaces.
|
* Type Checker: Disallow ``using for`` directive inside interfaces.
|
||||||
* Type Checker: Disallow signed literals as exponent in exponentiation operator.
|
* Type Checker: Disallow signed literals as exponent in exponentiation operator.
|
||||||
|
@ -19,7 +19,7 @@ Solidity also supports exception handling in the form of ``try``/``catch``-state
|
|||||||
but only for :ref:`external function calls <external-function-calls>` and
|
but only for :ref:`external function calls <external-function-calls>` and
|
||||||
contract creation calls.
|
contract creation calls.
|
||||||
|
|
||||||
Parentheses can *not* be omitted for conditionals, but curly brances can be omitted
|
Parentheses can *not* be omitted for conditionals, but curly braces can be omitted
|
||||||
around single-statement bodies.
|
around single-statement bodies.
|
||||||
|
|
||||||
Note that there is no type conversion from non-boolean to boolean types as
|
Note that there is no type conversion from non-boolean to boolean types as
|
||||||
|
@ -61,12 +61,11 @@ For a contract that fulfils payments, the signed message must include:
|
|||||||
2. The amount to be transferred.
|
2. The amount to be transferred.
|
||||||
3. Protection against replay attacks.
|
3. Protection against replay attacks.
|
||||||
|
|
||||||
A replay attack is when a signed message is reused to claim authorization for
|
A replay attack is when a signed message is reused to claim
|
||||||
a second action.
|
authorization for a second action. To avoid replay attacks
|
||||||
To avoid replay attacks we use the same as in Ethereum transactions
|
we use the same technique as in Ethereum transactions themselves,
|
||||||
themselves, a so-called nonce, which is the number of transactions sent by an
|
a so-called nonce, which is the number of transactions sent by
|
||||||
account.
|
an account. The smart contract checks if a nonce is used multiple times.
|
||||||
The smart contract checks if a nonce is used multiple times.
|
|
||||||
|
|
||||||
Another type of replay attack can occur when the owner
|
Another type of replay attack can occur when the owner
|
||||||
deploys a ``ReceiverPays`` smart contract, makes some
|
deploys a ``ReceiverPays`` smart contract, makes some
|
||||||
|
@ -243,7 +243,7 @@ Since variables are stored on the stack, they do not directly
|
|||||||
influence memory or storage, but they can be used as pointers
|
influence memory or storage, but they can be used as pointers
|
||||||
to memory or storage locations in the built-in functions
|
to memory or storage locations in the built-in functions
|
||||||
``mstore``, ``mload``, ``sstore`` and ``sload``.
|
``mstore``, ``mload``, ``sstore`` and ``sload``.
|
||||||
Future dialects migh introduce specific types for such pointers.
|
Future dialects might introduce specific types for such pointers.
|
||||||
|
|
||||||
When a variable is referenced, its current value is copied.
|
When a variable is referenced, its current value is copied.
|
||||||
For the EVM, this translates to a ``DUP`` instruction.
|
For the EVM, this translates to a ``DUP`` instruction.
|
||||||
|
@ -71,51 +71,51 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart1(
|
|||||||
{
|
{
|
||||||
using Word = typename Pattern::Word;
|
using Word = typename Pattern::Word;
|
||||||
using Builtins = typename Pattern::Builtins;
|
using Builtins = typename Pattern::Builtins;
|
||||||
return std::vector<SimplificationRule<Pattern>> {
|
return std::vector<SimplificationRule<Pattern>>{
|
||||||
// arithmetic on constants
|
// arithmetic on constants
|
||||||
{Builtins::ADD(A, B), [=]{ return A.d() + B.d(); }, false},
|
{Builtins::ADD(A, B), [=]{ return A.d() + B.d(); }},
|
||||||
{Builtins::MUL(A, B), [=]{ return A.d() * B.d(); }, false},
|
{Builtins::MUL(A, B), [=]{ return A.d() * B.d(); }},
|
||||||
{Builtins::SUB(A, B), [=]{ return A.d() - B.d(); }, false},
|
{Builtins::SUB(A, B), [=]{ return A.d() - B.d(); }},
|
||||||
{Builtins::DIV(A, B), [=]{ return B.d() == 0 ? 0 : divWorkaround(A.d(), B.d()); }, false},
|
{Builtins::DIV(A, B), [=]{ return B.d() == 0 ? 0 : divWorkaround(A.d(), B.d()); }},
|
||||||
{Builtins::SDIV(A, B), [=]{ return B.d() == 0 ? 0 : s2u(divWorkaround(u2s(A.d()), u2s(B.d()))); }, false},
|
{Builtins::SDIV(A, B), [=]{ return B.d() == 0 ? 0 : s2u(divWorkaround(u2s(A.d()), u2s(B.d()))); }},
|
||||||
{Builtins::MOD(A, B), [=]{ return B.d() == 0 ? 0 : modWorkaround(A.d(), B.d()); }, false},
|
{Builtins::MOD(A, B), [=]{ return B.d() == 0 ? 0 : modWorkaround(A.d(), B.d()); }},
|
||||||
{Builtins::SMOD(A, B), [=]{ return B.d() == 0 ? 0 : s2u(modWorkaround(u2s(A.d()), u2s(B.d()))); }, false},
|
{Builtins::SMOD(A, B), [=]{ return B.d() == 0 ? 0 : s2u(modWorkaround(u2s(A.d()), u2s(B.d()))); }},
|
||||||
{Builtins::EXP(A, B), [=]{ return Word(boost::multiprecision::powm(bigint(A.d()), bigint(B.d()), bigint(1) << Pattern::WordSize)); }, false},
|
{Builtins::EXP(A, B), [=]{ return Word(boost::multiprecision::powm(bigint(A.d()), bigint(B.d()), bigint(1) << Pattern::WordSize)); }},
|
||||||
{Builtins::NOT(A), [=]{ return ~A.d(); }, false},
|
{Builtins::NOT(A), [=]{ return ~A.d(); }},
|
||||||
{Builtins::LT(A, B), [=]() -> Word { return A.d() < B.d() ? 1 : 0; }, false},
|
{Builtins::LT(A, B), [=]() -> Word { return A.d() < B.d() ? 1 : 0; }},
|
||||||
{Builtins::GT(A, B), [=]() -> Word { return A.d() > B.d() ? 1 : 0; }, false},
|
{Builtins::GT(A, B), [=]() -> Word { return A.d() > B.d() ? 1 : 0; }},
|
||||||
{Builtins::SLT(A, B), [=]() -> Word { return u2s(A.d()) < u2s(B.d()) ? 1 : 0; }, false},
|
{Builtins::SLT(A, B), [=]() -> Word { return u2s(A.d()) < u2s(B.d()) ? 1 : 0; }},
|
||||||
{Builtins::SGT(A, B), [=]() -> Word { return u2s(A.d()) > u2s(B.d()) ? 1 : 0; }, false},
|
{Builtins::SGT(A, B), [=]() -> Word { return u2s(A.d()) > u2s(B.d()) ? 1 : 0; }},
|
||||||
{Builtins::EQ(A, B), [=]() -> Word { return A.d() == B.d() ? 1 : 0; }, false},
|
{Builtins::EQ(A, B), [=]() -> Word { return A.d() == B.d() ? 1 : 0; }},
|
||||||
{Builtins::ISZERO(A), [=]() -> Word { return A.d() == 0 ? 1 : 0; }, false},
|
{Builtins::ISZERO(A), [=]() -> Word { return A.d() == 0 ? 1 : 0; }},
|
||||||
{Builtins::AND(A, B), [=]{ return A.d() & B.d(); }, false},
|
{Builtins::AND(A, B), [=]{ return A.d() & B.d(); }},
|
||||||
{Builtins::OR(A, B), [=]{ return A.d() | B.d(); }, false},
|
{Builtins::OR(A, B), [=]{ return A.d() | B.d(); }},
|
||||||
{Builtins::XOR(A, B), [=]{ return A.d() ^ B.d(); }, false},
|
{Builtins::XOR(A, B), [=]{ return A.d() ^ B.d(); }},
|
||||||
{Builtins::BYTE(A, B), [=]{
|
{Builtins::BYTE(A, B), [=]{
|
||||||
return
|
return
|
||||||
A.d() >= Pattern::WordSize / 8 ?
|
A.d() >= Pattern::WordSize / 8 ?
|
||||||
0 :
|
0 :
|
||||||
(B.d() >> unsigned(8 * (Pattern::WordSize / 8 - 1 - A.d()))) & 0xff;
|
(B.d() >> unsigned(8 * (Pattern::WordSize / 8 - 1 - A.d()))) & 0xff;
|
||||||
}, false},
|
}},
|
||||||
{Builtins::ADDMOD(A, B, C), [=]{ return C.d() == 0 ? 0 : Word((bigint(A.d()) + bigint(B.d())) % C.d()); }, false},
|
{Builtins::ADDMOD(A, B, C), [=]{ return C.d() == 0 ? 0 : Word((bigint(A.d()) + bigint(B.d())) % C.d()); }},
|
||||||
{Builtins::MULMOD(A, B, C), [=]{ return C.d() == 0 ? 0 : Word((bigint(A.d()) * bigint(B.d())) % C.d()); }, false},
|
{Builtins::MULMOD(A, B, C), [=]{ return C.d() == 0 ? 0 : Word((bigint(A.d()) * bigint(B.d())) % C.d()); }},
|
||||||
{Builtins::SIGNEXTEND(A, B), [=]() -> Word {
|
{Builtins::SIGNEXTEND(A, B), [=]() -> Word {
|
||||||
if (A.d() >= Pattern::WordSize / 8 - 1)
|
if (A.d() >= Pattern::WordSize / 8 - 1)
|
||||||
return B.d();
|
return B.d();
|
||||||
unsigned testBit = unsigned(A.d()) * 8 + 7;
|
unsigned testBit = unsigned(A.d()) * 8 + 7;
|
||||||
Word mask = (Word(1) << testBit) - 1;
|
Word mask = (Word(1) << testBit) - 1;
|
||||||
return boost::multiprecision::bit_test(B.d(), testBit) ? B.d() | ~mask : B.d() & mask;
|
return boost::multiprecision::bit_test(B.d(), testBit) ? B.d() | ~mask : B.d() & mask;
|
||||||
}, false},
|
}},
|
||||||
{Builtins::SHL(A, B), [=]{
|
{Builtins::SHL(A, B), [=]{
|
||||||
if (A.d() >= Pattern::WordSize)
|
if (A.d() >= Pattern::WordSize)
|
||||||
return Word(0);
|
return Word(0);
|
||||||
return shlWorkaround(B.d(), unsigned(A.d()));
|
return shlWorkaround(B.d(), unsigned(A.d()));
|
||||||
}, false},
|
}},
|
||||||
{Builtins::SHR(A, B), [=]{
|
{Builtins::SHR(A, B), [=]{
|
||||||
if (A.d() >= Pattern::WordSize)
|
if (A.d() >= Pattern::WordSize)
|
||||||
return Word(0);
|
return Word(0);
|
||||||
return B.d() >> unsigned(A.d());
|
return B.d() >> unsigned(A.d());
|
||||||
}, false}
|
}}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,48 +133,48 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart2(
|
|||||||
using Builtins = typename Pattern::Builtins;
|
using Builtins = typename Pattern::Builtins;
|
||||||
return std::vector<SimplificationRule<Pattern>> {
|
return std::vector<SimplificationRule<Pattern>> {
|
||||||
// invariants involving known constants
|
// invariants involving known constants
|
||||||
{Builtins::ADD(X, 0), [=]{ return X; }, false},
|
{Builtins::ADD(X, 0), [=]{ return X; }},
|
||||||
{Builtins::ADD(0, X), [=]{ return X; }, false},
|
{Builtins::ADD(0, X), [=]{ return X; }},
|
||||||
{Builtins::SUB(X, 0), [=]{ return X; }, false},
|
{Builtins::SUB(X, 0), [=]{ return X; }},
|
||||||
{Builtins::SUB(~Word(0), X), [=]() -> Pattern { return Builtins::NOT(X); }, false},
|
{Builtins::SUB(~Word(0), X), [=]() -> Pattern { return Builtins::NOT(X); }},
|
||||||
{Builtins::MUL(X, 0), [=]{ return Word(0); }, true},
|
{Builtins::MUL(X, 0), [=]{ return Word(0); }},
|
||||||
{Builtins::MUL(0, X), [=]{ return Word(0); }, true},
|
{Builtins::MUL(0, X), [=]{ return Word(0); }},
|
||||||
{Builtins::MUL(X, 1), [=]{ return X; }, false},
|
{Builtins::MUL(X, 1), [=]{ return X; }},
|
||||||
{Builtins::MUL(1, X), [=]{ return X; }, false},
|
{Builtins::MUL(1, X), [=]{ return X; }},
|
||||||
{Builtins::MUL(X, Word(-1)), [=]() -> Pattern { return Builtins::SUB(0, X); }, false},
|
{Builtins::MUL(X, Word(-1)), [=]() -> Pattern { return Builtins::SUB(0, X); }},
|
||||||
{Builtins::MUL(Word(-1), X), [=]() -> Pattern { return Builtins::SUB(0, X); }, false},
|
{Builtins::MUL(Word(-1), X), [=]() -> Pattern { return Builtins::SUB(0, X); }},
|
||||||
{Builtins::DIV(X, 0), [=]{ return Word(0); }, true},
|
{Builtins::DIV(X, 0), [=]{ return Word(0); }},
|
||||||
{Builtins::DIV(0, X), [=]{ return Word(0); }, true},
|
{Builtins::DIV(0, X), [=]{ return Word(0); }},
|
||||||
{Builtins::DIV(X, 1), [=]{ return X; }, false},
|
{Builtins::DIV(X, 1), [=]{ return X; }},
|
||||||
{Builtins::SDIV(X, 0), [=]{ return Word(0); }, true},
|
{Builtins::SDIV(X, 0), [=]{ return Word(0); }},
|
||||||
{Builtins::SDIV(0, X), [=]{ return Word(0); }, true},
|
{Builtins::SDIV(0, X), [=]{ return Word(0); }},
|
||||||
{Builtins::SDIV(X, 1), [=]{ return X; }, false},
|
{Builtins::SDIV(X, 1), [=]{ return X; }},
|
||||||
{Builtins::AND(X, ~Word(0)), [=]{ return X; }, false},
|
{Builtins::AND(X, ~Word(0)), [=]{ return X; }},
|
||||||
{Builtins::AND(~Word(0), X), [=]{ return X; }, false},
|
{Builtins::AND(~Word(0), X), [=]{ return X; }},
|
||||||
{Builtins::AND(X, 0), [=]{ return Word(0); }, true},
|
{Builtins::AND(X, 0), [=]{ return Word(0); }},
|
||||||
{Builtins::AND(0, X), [=]{ return Word(0); }, true},
|
{Builtins::AND(0, X), [=]{ return Word(0); }},
|
||||||
{Builtins::OR(X, 0), [=]{ return X; }, false},
|
{Builtins::OR(X, 0), [=]{ return X; }},
|
||||||
{Builtins::OR(0, X), [=]{ return X; }, false},
|
{Builtins::OR(0, X), [=]{ return X; }},
|
||||||
{Builtins::OR(X, ~Word(0)), [=]{ return ~Word(0); }, true},
|
{Builtins::OR(X, ~Word(0)), [=]{ return ~Word(0); }},
|
||||||
{Builtins::OR(~Word(0), X), [=]{ return ~Word(0); }, true},
|
{Builtins::OR(~Word(0), X), [=]{ return ~Word(0); }},
|
||||||
{Builtins::XOR(X, 0), [=]{ return X; }, false},
|
{Builtins::XOR(X, 0), [=]{ return X; }},
|
||||||
{Builtins::XOR(0, X), [=]{ return X; }, false},
|
{Builtins::XOR(0, X), [=]{ return X; }},
|
||||||
{Builtins::MOD(X, 0), [=]{ return Word(0); }, true},
|
{Builtins::MOD(X, 0), [=]{ return Word(0); }},
|
||||||
{Builtins::MOD(0, X), [=]{ return Word(0); }, true},
|
{Builtins::MOD(0, X), [=]{ return Word(0); }},
|
||||||
{Builtins::EQ(X, 0), [=]() -> Pattern { return Builtins::ISZERO(X); }, false },
|
{Builtins::EQ(X, 0), [=]() -> Pattern { return Builtins::ISZERO(X); },},
|
||||||
{Builtins::EQ(0, X), [=]() -> Pattern { return Builtins::ISZERO(X); }, false },
|
{Builtins::EQ(0, X), [=]() -> Pattern { return Builtins::ISZERO(X); },},
|
||||||
{Builtins::SHL(0, X), [=]{ return X; }, false},
|
{Builtins::SHL(0, X), [=]{ return X; }},
|
||||||
{Builtins::SHR(0, X), [=]{ return X; }, false},
|
{Builtins::SHR(0, X), [=]{ return X; }},
|
||||||
{Builtins::SHL(X, 0), [=]{ return Word(0); }, true},
|
{Builtins::SHL(X, 0), [=]{ return Word(0); }},
|
||||||
{Builtins::SHR(X, 0), [=]{ return Word(0); }, true},
|
{Builtins::SHR(X, 0), [=]{ return Word(0); }},
|
||||||
{Builtins::GT(X, 0), [=]() -> Pattern { return Builtins::ISZERO(Builtins::ISZERO(X)); }, false},
|
{Builtins::GT(X, 0), [=]() -> Pattern { return Builtins::ISZERO(Builtins::ISZERO(X)); }},
|
||||||
{Builtins::LT(0, X), [=]() -> Pattern { return Builtins::ISZERO(Builtins::ISZERO(X)); }, false},
|
{Builtins::LT(0, X), [=]() -> Pattern { return Builtins::ISZERO(Builtins::ISZERO(X)); }},
|
||||||
{Builtins::GT(X, ~Word(0)), [=]{ return Word(0); }, true},
|
{Builtins::GT(X, ~Word(0)), [=]{ return Word(0); }},
|
||||||
{Builtins::LT(~Word(0), X), [=]{ return Word(0); }, true},
|
{Builtins::LT(~Word(0), X), [=]{ return Word(0); }},
|
||||||
{Builtins::GT(0, X), [=]{ return Word(0); }, true},
|
{Builtins::GT(0, X), [=]{ return Word(0); }},
|
||||||
{Builtins::LT(X, 0), [=]{ return Word(0); }, true},
|
{Builtins::LT(X, 0), [=]{ return Word(0); }},
|
||||||
{Builtins::AND(Builtins::BYTE(X, Y), Word(0xff)), [=]() -> Pattern { return Builtins::BYTE(X, Y); }, false},
|
{Builtins::AND(Builtins::BYTE(X, Y), Word(0xff)), [=]() -> Pattern { return Builtins::BYTE(X, Y); }},
|
||||||
{Builtins::BYTE(Word(Pattern::WordSize / 8 - 1), X), [=]() -> Pattern { return Builtins::AND(X, Word(0xff)); }, false}
|
{Builtins::BYTE(Word(Pattern::WordSize / 8 - 1), X), [=]() -> Pattern { return Builtins::AND(X, Word(0xff)); }},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,16 +191,16 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart3(
|
|||||||
using Builtins = typename Pattern::Builtins;
|
using Builtins = typename Pattern::Builtins;
|
||||||
return std::vector<SimplificationRule<Pattern>> {
|
return std::vector<SimplificationRule<Pattern>> {
|
||||||
// operations involving an expression and itself
|
// operations involving an expression and itself
|
||||||
{Builtins::AND(X, X), [=]{ return X; }, true},
|
{Builtins::AND(X, X), [=]{ return X; }},
|
||||||
{Builtins::OR(X, X), [=]{ return X; }, true},
|
{Builtins::OR(X, X), [=]{ return X; }},
|
||||||
{Builtins::XOR(X, X), [=]{ return Word(0); }, true},
|
{Builtins::XOR(X, X), [=]{ return Word(0); }},
|
||||||
{Builtins::SUB(X, X), [=]{ return Word(0); }, true},
|
{Builtins::SUB(X, X), [=]{ return Word(0); }},
|
||||||
{Builtins::EQ(X, X), [=]{ return Word(1); }, true},
|
{Builtins::EQ(X, X), [=]{ return Word(1); }},
|
||||||
{Builtins::LT(X, X), [=]{ return Word(0); }, true},
|
{Builtins::LT(X, X), [=]{ return Word(0); }},
|
||||||
{Builtins::SLT(X, X), [=]{ return Word(0); }, true},
|
{Builtins::SLT(X, X), [=]{ return Word(0); }},
|
||||||
{Builtins::GT(X, X), [=]{ return Word(0); }, true},
|
{Builtins::GT(X, X), [=]{ return Word(0); }},
|
||||||
{Builtins::SGT(X, X), [=]{ return Word(0); }, true},
|
{Builtins::SGT(X, X), [=]{ return Word(0); }},
|
||||||
{Builtins::MOD(X, X), [=]{ return Word(0); }, true}
|
{Builtins::MOD(X, X), [=]{ return Word(0); }}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,23 +217,23 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart4(
|
|||||||
using Builtins = typename Pattern::Builtins;
|
using Builtins = typename Pattern::Builtins;
|
||||||
return std::vector<SimplificationRule<Pattern>> {
|
return std::vector<SimplificationRule<Pattern>> {
|
||||||
// logical instruction combinations
|
// logical instruction combinations
|
||||||
{Builtins::NOT(Builtins::NOT(X)), [=]{ return X; }, false},
|
{Builtins::NOT(Builtins::NOT(X)), [=]{ return X; }},
|
||||||
{Builtins::XOR(X, Builtins::XOR(X, Y)), [=]{ return Y; }, true},
|
{Builtins::XOR(X, Builtins::XOR(X, Y)), [=]{ return Y; }},
|
||||||
{Builtins::XOR(X, Builtins::XOR(Y, X)), [=]{ return Y; }, true},
|
{Builtins::XOR(X, Builtins::XOR(Y, X)), [=]{ return Y; }},
|
||||||
{Builtins::XOR(Builtins::XOR(X, Y), X), [=]{ return Y; }, true},
|
{Builtins::XOR(Builtins::XOR(X, Y), X), [=]{ return Y; }},
|
||||||
{Builtins::XOR(Builtins::XOR(Y, X), X), [=]{ return Y; }, true},
|
{Builtins::XOR(Builtins::XOR(Y, X), X), [=]{ return Y; }},
|
||||||
{Builtins::OR(X, Builtins::AND(X, Y)), [=]{ return X; }, true},
|
{Builtins::OR(X, Builtins::AND(X, Y)), [=]{ return X; }},
|
||||||
{Builtins::OR(X, Builtins::AND(Y, X)), [=]{ return X; }, true},
|
{Builtins::OR(X, Builtins::AND(Y, X)), [=]{ return X; }},
|
||||||
{Builtins::OR(Builtins::AND(X, Y), X), [=]{ return X; }, true},
|
{Builtins::OR(Builtins::AND(X, Y), X), [=]{ return X; }},
|
||||||
{Builtins::OR(Builtins::AND(Y, X), X), [=]{ return X; }, true},
|
{Builtins::OR(Builtins::AND(Y, X), X), [=]{ return X; }},
|
||||||
{Builtins::AND(X, Builtins::OR(X, Y)), [=]{ return X; }, true},
|
{Builtins::AND(X, Builtins::OR(X, Y)), [=]{ return X; }},
|
||||||
{Builtins::AND(X, Builtins::OR(Y, X)), [=]{ return X; }, true},
|
{Builtins::AND(X, Builtins::OR(Y, X)), [=]{ return X; }},
|
||||||
{Builtins::AND(Builtins::OR(X, Y), X), [=]{ return X; }, true},
|
{Builtins::AND(Builtins::OR(X, Y), X), [=]{ return X; }},
|
||||||
{Builtins::AND(Builtins::OR(Y, X), X), [=]{ return X; }, true},
|
{Builtins::AND(Builtins::OR(Y, X), X), [=]{ return X; }},
|
||||||
{Builtins::AND(X, Builtins::NOT(X)), [=]{ return Word(0); }, true},
|
{Builtins::AND(X, Builtins::NOT(X)), [=]{ return Word(0); }},
|
||||||
{Builtins::AND(Builtins::NOT(X), X), [=]{ return Word(0); }, true},
|
{Builtins::AND(Builtins::NOT(X), X), [=]{ return Word(0); }},
|
||||||
{Builtins::OR(X, Builtins::NOT(X)), [=]{ return ~Word(0); }, true},
|
{Builtins::OR(X, Builtins::NOT(X)), [=]{ return ~Word(0); }},
|
||||||
{Builtins::OR(Builtins::NOT(X), X), [=]{ return ~Word(0); }, true},
|
{Builtins::OR(Builtins::NOT(X), X), [=]{ return ~Word(0); }},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,14 +249,14 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart4_5(
|
|||||||
using Builtins = typename Pattern::Builtins;
|
using Builtins = typename Pattern::Builtins;
|
||||||
return std::vector<SimplificationRule<Pattern>>{
|
return std::vector<SimplificationRule<Pattern>>{
|
||||||
// idempotent operations
|
// idempotent operations
|
||||||
{Builtins::AND(Builtins::AND(X, Y), Y), [=]{ return Builtins::AND(X, Y); }, true},
|
{Builtins::AND(Builtins::AND(X, Y), Y), [=]{ return Builtins::AND(X, Y); }},
|
||||||
{Builtins::AND(Y, Builtins::AND(X, Y)), [=]{ return Builtins::AND(X, Y); }, true},
|
{Builtins::AND(Y, Builtins::AND(X, Y)), [=]{ return Builtins::AND(X, Y); }},
|
||||||
{Builtins::AND(Builtins::AND(Y, X), Y), [=]{ return Builtins::AND(Y, X); }, true},
|
{Builtins::AND(Builtins::AND(Y, X), Y), [=]{ return Builtins::AND(Y, X); }},
|
||||||
{Builtins::AND(Y, Builtins::AND(Y, X)), [=]{ return Builtins::AND(Y, X); }, true},
|
{Builtins::AND(Y, Builtins::AND(Y, X)), [=]{ return Builtins::AND(Y, X); }},
|
||||||
{Builtins::OR(Builtins::OR(X, Y), Y), [=]{ return Builtins::OR(X, Y); }, true},
|
{Builtins::OR(Builtins::OR(X, Y), Y), [=]{ return Builtins::OR(X, Y); }},
|
||||||
{Builtins::OR(Y, Builtins::OR(X, Y)), [=]{ return Builtins::OR(X, Y); }, true},
|
{Builtins::OR(Y, Builtins::OR(X, Y)), [=]{ return Builtins::OR(X, Y); }},
|
||||||
{Builtins::OR(Builtins::OR(Y, X), Y), [=]{ return Builtins::OR(Y, X); }, true},
|
{Builtins::OR(Builtins::OR(Y, X), Y), [=]{ return Builtins::OR(Y, X); }},
|
||||||
{Builtins::OR(Y, Builtins::OR(Y, X)), [=]{ return Builtins::OR(Y, X); }, true},
|
{Builtins::OR(Y, Builtins::OR(Y, X)), [=]{ return Builtins::OR(Y, X); }},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,8 +280,7 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart5(
|
|||||||
Word value = Word(1) << i;
|
Word value = Word(1) << i;
|
||||||
rules.push_back({
|
rules.push_back({
|
||||||
Builtins::MOD(X, value),
|
Builtins::MOD(X, value),
|
||||||
[=]() -> Pattern { return Builtins::AND(X, value - 1); },
|
[=]() -> Pattern { return Builtins::AND(X, value - 1); }
|
||||||
false
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,7 +288,6 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart5(
|
|||||||
rules.push_back({
|
rules.push_back({
|
||||||
Builtins::SHL(A, X),
|
Builtins::SHL(A, X),
|
||||||
[=]() -> Pattern { return Word(0); },
|
[=]() -> Pattern { return Word(0); },
|
||||||
true,
|
|
||||||
[=]() { return A.d() >= Pattern::WordSize; }
|
[=]() { return A.d() >= Pattern::WordSize; }
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -297,7 +295,6 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart5(
|
|||||||
rules.push_back({
|
rules.push_back({
|
||||||
Builtins::SHR(A, X),
|
Builtins::SHR(A, X),
|
||||||
[=]() -> Pattern { return Word(0); },
|
[=]() -> Pattern { return Word(0); },
|
||||||
true,
|
|
||||||
[=]() { return A.d() >= Pattern::WordSize; }
|
[=]() { return A.d() >= Pattern::WordSize; }
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -305,7 +302,6 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart5(
|
|||||||
rules.push_back({
|
rules.push_back({
|
||||||
Builtins::BYTE(A, X),
|
Builtins::BYTE(A, X),
|
||||||
[=]() -> Pattern { return Word(0); },
|
[=]() -> Pattern { return Word(0); },
|
||||||
true,
|
|
||||||
[=]() { return A.d() >= Pattern::WordSize / 8; }
|
[=]() { return A.d() >= Pattern::WordSize / 8; }
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -320,13 +316,11 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart5(
|
|||||||
Word const mask = (Word(1) << 160) - 1;
|
Word const mask = (Word(1) << 160) - 1;
|
||||||
rules.push_back({
|
rules.push_back({
|
||||||
Builtins::AND(Pattern{instr}, mask),
|
Builtins::AND(Pattern{instr}, mask),
|
||||||
[=]() -> Pattern { return {instr}; },
|
[=]() -> Pattern { return {instr}; }
|
||||||
false
|
|
||||||
});
|
});
|
||||||
rules.push_back({
|
rules.push_back({
|
||||||
Builtins::AND(mask, Pattern{instr}),
|
Builtins::AND(mask, Pattern{instr}),
|
||||||
[=]() -> Pattern { return {instr}; },
|
[=]() -> Pattern { return {instr}; }
|
||||||
false
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,21 +351,18 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart6(
|
|||||||
typename Builtins::PatternGeneratorInstance op{instr};
|
typename Builtins::PatternGeneratorInstance op{instr};
|
||||||
rules.push_back({
|
rules.push_back({
|
||||||
Builtins::ISZERO(Builtins::ISZERO(op(X, Y))),
|
Builtins::ISZERO(Builtins::ISZERO(op(X, Y))),
|
||||||
[=]() -> Pattern { return op(X, Y); },
|
[=]() -> Pattern { return op(X, Y); }
|
||||||
false
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
rules.push_back({
|
rules.push_back({
|
||||||
Builtins::ISZERO(Builtins::ISZERO(Builtins::ISZERO(X))),
|
Builtins::ISZERO(Builtins::ISZERO(Builtins::ISZERO(X))),
|
||||||
[=]() -> Pattern { return Builtins::ISZERO(X); },
|
[=]() -> Pattern { return Builtins::ISZERO(X); }
|
||||||
false
|
|
||||||
});
|
});
|
||||||
|
|
||||||
rules.push_back({
|
rules.push_back({
|
||||||
Builtins::ISZERO(Builtins::XOR(X, Y)),
|
Builtins::ISZERO(Builtins::XOR(X, Y)),
|
||||||
[=]() -> Pattern { return Builtins::EQ(X, Y); },
|
[=]() -> Pattern { return Builtins::EQ(X, Y); }
|
||||||
false
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return rules;
|
return rules;
|
||||||
@ -409,23 +400,19 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart7(
|
|||||||
rules += std::vector<SimplificationRule<Pattern>>{{
|
rules += std::vector<SimplificationRule<Pattern>>{{
|
||||||
// (X+A)+B -> X+(A+B)
|
// (X+A)+B -> X+(A+B)
|
||||||
op(opXA, B),
|
op(opXA, B),
|
||||||
[=]() -> Pattern { return op(X, fun(A.d(), B.d())); },
|
[=]() -> Pattern { return op(X, fun(A.d(), B.d())); }
|
||||||
false
|
|
||||||
}, {
|
}, {
|
||||||
// (X+A)+Y -> (X+Y)+A
|
// (X+A)+Y -> (X+Y)+A
|
||||||
op(opXA, Y),
|
op(opXA, Y),
|
||||||
[=]() -> Pattern { return op(op(X, Y), A); },
|
[=]() -> Pattern { return op(op(X, Y), A); }
|
||||||
false
|
|
||||||
}, {
|
}, {
|
||||||
// B+(X+A) -> X+(A+B)
|
// B+(X+A) -> X+(A+B)
|
||||||
op(B, opXA),
|
op(B, opXA),
|
||||||
[=]() -> Pattern { return op(X, fun(A.d(), B.d())); },
|
[=]() -> Pattern { return op(X, fun(A.d(), B.d())); }
|
||||||
false
|
|
||||||
}, {
|
}, {
|
||||||
// Y+(X+A) -> (Y+X)+A
|
// Y+(X+A) -> (Y+X)+A
|
||||||
op(Y, opXA),
|
op(Y, opXA),
|
||||||
[=]() -> Pattern { return op(op(Y, X), A); },
|
[=]() -> Pattern { return op(op(Y, X), A); }
|
||||||
false
|
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -440,8 +427,7 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart7(
|
|||||||
return Builtins::AND(X, Word(0));
|
return Builtins::AND(X, Word(0));
|
||||||
else
|
else
|
||||||
return Builtins::SHL(Word(sum), X);
|
return Builtins::SHL(Word(sum), X);
|
||||||
},
|
}
|
||||||
false
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Combine two SHR by constant
|
// Combine two SHR by constant
|
||||||
@ -454,8 +440,7 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart7(
|
|||||||
return Builtins::AND(X, Word(0));
|
return Builtins::AND(X, Word(0));
|
||||||
else
|
else
|
||||||
return Builtins::SHR(Word(sum), X);
|
return Builtins::SHR(Word(sum), X);
|
||||||
},
|
}
|
||||||
false
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Combine SHL-SHR by constant
|
// Combine SHL-SHR by constant
|
||||||
@ -472,7 +457,6 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart7(
|
|||||||
else
|
else
|
||||||
return Builtins::AND(X, mask);
|
return Builtins::AND(X, mask);
|
||||||
},
|
},
|
||||||
false,
|
|
||||||
[=] { return A.d() < Pattern::WordSize && B.d() < Pattern::WordSize; }
|
[=] { return A.d() < Pattern::WordSize && B.d() < Pattern::WordSize; }
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -490,7 +474,6 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart7(
|
|||||||
else
|
else
|
||||||
return Builtins::AND(X, mask);
|
return Builtins::AND(X, mask);
|
||||||
},
|
},
|
||||||
false,
|
|
||||||
[=] { return A.d() < Pattern::WordSize && B.d() < Pattern::WordSize; }
|
[=] { return A.d() < Pattern::WordSize && B.d() < Pattern::WordSize; }
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -509,14 +492,12 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart7(
|
|||||||
// SH[L/R](B, AND(X, A)) -> AND(SH[L/R](B, X), [ A << B / A >> B ])
|
// SH[L/R](B, AND(X, A)) -> AND(SH[L/R](B, X), [ A << B / A >> B ])
|
||||||
shiftOp(B, Builtins::AND(X, A)),
|
shiftOp(B, Builtins::AND(X, A)),
|
||||||
replacement,
|
replacement,
|
||||||
false,
|
|
||||||
[=] { return B.d() < Pattern::WordSize; }
|
[=] { return B.d() < Pattern::WordSize; }
|
||||||
});
|
});
|
||||||
rules.push_back({
|
rules.push_back({
|
||||||
// SH[L/R](B, AND(A, X)) -> AND(SH[L/R](B, X), [ A << B / A >> B ])
|
// SH[L/R](B, AND(A, X)) -> AND(SH[L/R](B, X), [ A << B / A >> B ])
|
||||||
shiftOp(B, Builtins::AND(A, X)),
|
shiftOp(B, Builtins::AND(A, X)),
|
||||||
replacement,
|
replacement,
|
||||||
false,
|
|
||||||
[=] { return B.d() < Pattern::WordSize; }
|
[=] { return B.d() < Pattern::WordSize; }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -526,17 +507,14 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart7(
|
|||||||
Builtins::MUL(X, Builtins::SHL(Y, Word(1))),
|
Builtins::MUL(X, Builtins::SHL(Y, Word(1))),
|
||||||
[=]() -> Pattern {
|
[=]() -> Pattern {
|
||||||
return Builtins::SHL(Y, X);
|
return Builtins::SHL(Y, X);
|
||||||
},
|
}
|
||||||
// Actually only changes the order, does not remove.
|
|
||||||
true
|
|
||||||
});
|
});
|
||||||
rules.push_back({
|
rules.push_back({
|
||||||
// MUL(SHL(X, 1), Y) -> SHL(X, Y)
|
// MUL(SHL(X, 1), Y) -> SHL(X, Y)
|
||||||
Builtins::MUL(Builtins::SHL(X, Word(1)), Y),
|
Builtins::MUL(Builtins::SHL(X, Word(1)), Y),
|
||||||
[=]() -> Pattern {
|
[=]() -> Pattern {
|
||||||
return Builtins::SHL(X, Y);
|
return Builtins::SHL(X, Y);
|
||||||
},
|
}
|
||||||
false
|
|
||||||
});
|
});
|
||||||
|
|
||||||
rules.push_back({
|
rules.push_back({
|
||||||
@ -544,9 +522,7 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart7(
|
|||||||
Builtins::DIV(X, Builtins::SHL(Y, Word(1))),
|
Builtins::DIV(X, Builtins::SHL(Y, Word(1))),
|
||||||
[=]() -> Pattern {
|
[=]() -> Pattern {
|
||||||
return Builtins::SHR(Y, X);
|
return Builtins::SHR(Y, X);
|
||||||
},
|
}
|
||||||
// Actually only changes the order, does not remove.
|
|
||||||
true
|
|
||||||
});
|
});
|
||||||
|
|
||||||
std::function<bool()> feasibilityFunction = [=]() {
|
std::function<bool()> feasibilityFunction = [=]() {
|
||||||
@ -560,7 +536,6 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart7(
|
|||||||
// AND(A, SHR(B, X)) -> A & ((2^256-1) >> B) == ((2^256-1) >> B)
|
// AND(A, SHR(B, X)) -> A & ((2^256-1) >> B) == ((2^256-1) >> B)
|
||||||
Builtins::AND(A, Builtins::SHR(B, X)),
|
Builtins::AND(A, Builtins::SHR(B, X)),
|
||||||
[=]() -> Pattern { return Builtins::SHR(B, X); },
|
[=]() -> Pattern { return Builtins::SHR(B, X); },
|
||||||
false,
|
|
||||||
feasibilityFunction
|
feasibilityFunction
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -568,28 +543,24 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart7(
|
|||||||
// AND(SHR(B, X), A) -> ((2^256-1) >> B) & A == ((2^256-1) >> B)
|
// AND(SHR(B, X), A) -> ((2^256-1) >> B) & A == ((2^256-1) >> B)
|
||||||
Builtins::AND(Builtins::SHR(B, X), A),
|
Builtins::AND(Builtins::SHR(B, X), A),
|
||||||
[=]() -> Pattern { return Builtins::SHR(B, X); },
|
[=]() -> Pattern { return Builtins::SHR(B, X); },
|
||||||
false,
|
|
||||||
feasibilityFunction
|
feasibilityFunction
|
||||||
});
|
});
|
||||||
|
|
||||||
rules.push_back({
|
rules.push_back({
|
||||||
Builtins::BYTE(A, Builtins::SHL(B, X)),
|
Builtins::BYTE(A, Builtins::SHL(B, X)),
|
||||||
[=]() -> Pattern { return Builtins::BYTE(A.d() + B.d() / 8, X); },
|
[=]() -> Pattern { return Builtins::BYTE(A.d() + B.d() / 8, X); },
|
||||||
false,
|
|
||||||
[=] { return B.d() % 8 == 0 && A.d() <= 32 && B.d() <= 256; }
|
[=] { return B.d() % 8 == 0 && A.d() <= 32 && B.d() <= 256; }
|
||||||
});
|
});
|
||||||
|
|
||||||
rules.push_back({
|
rules.push_back({
|
||||||
Builtins::BYTE(A, Builtins::SHR(B, X)),
|
Builtins::BYTE(A, Builtins::SHR(B, X)),
|
||||||
[=]() -> Pattern { return Word(0); },
|
[=]() -> Pattern { return Word(0); },
|
||||||
true,
|
|
||||||
[=] { return A.d() < B.d() / 8; }
|
[=] { return A.d() < B.d() / 8; }
|
||||||
});
|
});
|
||||||
|
|
||||||
rules.push_back({
|
rules.push_back({
|
||||||
Builtins::BYTE(A, Builtins::SHR(B, X)),
|
Builtins::BYTE(A, Builtins::SHR(B, X)),
|
||||||
[=]() -> Pattern { return Builtins::BYTE(A.d() - B.d() / 8, X); },
|
[=]() -> Pattern { return Builtins::BYTE(A.d() - B.d() / 8, X); },
|
||||||
false,
|
|
||||||
[=] {
|
[=] {
|
||||||
return B.d() % 8 == 0 && A.d() < Pattern::WordSize / 8 && B.d() <= Pattern::WordSize && A.d() >= B.d() / 8;
|
return B.d() % 8 == 0 && A.d() < Pattern::WordSize / 8 && B.d() <= Pattern::WordSize && A.d() >= B.d() / 8;
|
||||||
}
|
}
|
||||||
@ -615,76 +586,28 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart8(
|
|||||||
{
|
{
|
||||||
// X - A -> X + (-A)
|
// X - A -> X + (-A)
|
||||||
Builtins::SUB(X, A),
|
Builtins::SUB(X, A),
|
||||||
[=]() -> Pattern { return Builtins::ADD(X, 0 - A.d()); },
|
[=]() -> Pattern { return Builtins::ADD(X, 0 - A.d()); }
|
||||||
false
|
|
||||||
}, {
|
}, {
|
||||||
// (X + A) - Y -> (X - Y) + A
|
// (X + A) - Y -> (X - Y) + A
|
||||||
Builtins::SUB(Builtins::ADD(X, A), Y),
|
Builtins::SUB(Builtins::ADD(X, A), Y),
|
||||||
[=]() -> Pattern { return Builtins::ADD(Builtins::SUB(X, Y), A); },
|
[=]() -> Pattern { return Builtins::ADD(Builtins::SUB(X, Y), A); }
|
||||||
false
|
|
||||||
}, {
|
}, {
|
||||||
// (A + X) - Y -> (X - Y) + A
|
// (A + X) - Y -> (X - Y) + A
|
||||||
Builtins::SUB(Builtins::ADD(A, X), Y),
|
Builtins::SUB(Builtins::ADD(A, X), Y),
|
||||||
[=]() -> Pattern { return Builtins::ADD(Builtins::SUB(X, Y), A); },
|
[=]() -> Pattern { return Builtins::ADD(Builtins::SUB(X, Y), A); }
|
||||||
false
|
|
||||||
}, {
|
}, {
|
||||||
// X - (Y + A) -> (X - Y) + (-A)
|
// X - (Y + A) -> (X - Y) + (-A)
|
||||||
Builtins::SUB(X, Builtins::ADD(Y, A)),
|
Builtins::SUB(X, Builtins::ADD(Y, A)),
|
||||||
[=]() -> Pattern { return Builtins::ADD(Builtins::SUB(X, Y), 0 - A.d()); },
|
[=]() -> Pattern { return Builtins::ADD(Builtins::SUB(X, Y), 0 - A.d()); }
|
||||||
false
|
|
||||||
}, {
|
}, {
|
||||||
// X - (A + Y) -> (X - Y) + (-A)
|
// X - (A + Y) -> (X - Y) + (-A)
|
||||||
Builtins::SUB(X, Builtins::ADD(A, Y)),
|
Builtins::SUB(X, Builtins::ADD(A, Y)),
|
||||||
[=]() -> Pattern { return Builtins::ADD(Builtins::SUB(X, Y), 0 - A.d()); },
|
[=]() -> Pattern { return Builtins::ADD(Builtins::SUB(X, Y), 0 - A.d()); }
|
||||||
false
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return rules;
|
return rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Pattern>
|
|
||||||
std::vector<SimplificationRule<Pattern>> simplificationRuleListPart9(
|
|
||||||
Pattern,
|
|
||||||
Pattern,
|
|
||||||
Pattern,
|
|
||||||
Pattern W,
|
|
||||||
Pattern X,
|
|
||||||
Pattern Y,
|
|
||||||
Pattern Z
|
|
||||||
)
|
|
||||||
{
|
|
||||||
using Word = typename Pattern::Word;
|
|
||||||
using Builtins = typename Pattern::Builtins;
|
|
||||||
std::vector<SimplificationRule<Pattern>> rules;
|
|
||||||
|
|
||||||
assertThrow(Pattern::WordSize > 160, OptimizerException, "");
|
|
||||||
Word const mask = (Word(1) << 160) - 1;
|
|
||||||
// CREATE
|
|
||||||
rules.push_back({
|
|
||||||
Builtins::AND(Builtins::CREATE(W, X, Y), mask),
|
|
||||||
[=]() -> Pattern { return Builtins::CREATE(W, X, Y); },
|
|
||||||
false
|
|
||||||
});
|
|
||||||
rules.push_back({
|
|
||||||
Builtins::AND(mask, Builtins::CREATE(W, X, Y)),
|
|
||||||
[=]() -> Pattern { return Builtins::CREATE(W, X, Y); },
|
|
||||||
false
|
|
||||||
});
|
|
||||||
// CREATE2
|
|
||||||
rules.push_back({
|
|
||||||
Builtins::AND(Builtins::CREATE2(W, X, Y, Z), mask),
|
|
||||||
[=]() -> Pattern { return Builtins::CREATE2(W, X, Y, Z); },
|
|
||||||
false
|
|
||||||
});
|
|
||||||
rules.push_back({
|
|
||||||
Builtins::AND(mask, Builtins::CREATE2(W, X, Y, Z)),
|
|
||||||
[=]() -> Pattern { return Builtins::CREATE2(W, X, Y, Z); },
|
|
||||||
false
|
|
||||||
});
|
|
||||||
|
|
||||||
return rules;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Pattern>
|
template<class Pattern>
|
||||||
std::vector<SimplificationRule<Pattern>> evmRuleList(
|
std::vector<SimplificationRule<Pattern>> evmRuleList(
|
||||||
langutil::EVMVersion _evmVersion,
|
langutil::EVMVersion _evmVersion,
|
||||||
@ -703,7 +626,7 @@ std::vector<SimplificationRule<Pattern>> evmRuleList(
|
|||||||
if (_evmVersion.hasSelfBalance())
|
if (_evmVersion.hasSelfBalance())
|
||||||
rules.push_back({
|
rules.push_back({
|
||||||
Builtins::BALANCE(Instruction::ADDRESS),
|
Builtins::BALANCE(Instruction::ADDRESS),
|
||||||
[]() -> Pattern { return Instruction::SELFBALANCE; }, false
|
[]() -> Pattern { return Instruction::SELFBALANCE; }
|
||||||
});
|
});
|
||||||
|
|
||||||
return rules;
|
return rules;
|
||||||
@ -743,7 +666,6 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleList(
|
|||||||
rules += simplificationRuleListPart6(A, B, C, W, X);
|
rules += simplificationRuleListPart6(A, B, C, W, X);
|
||||||
rules += simplificationRuleListPart7(A, B, C, W, X);
|
rules += simplificationRuleListPart7(A, B, C, W, X);
|
||||||
rules += simplificationRuleListPart8(A, B, C, W, X);
|
rules += simplificationRuleListPart8(A, B, C, W, X);
|
||||||
rules += simplificationRuleListPart9(A, B, C, W, X, Y, Z);
|
|
||||||
|
|
||||||
if (_evmVersion.has_value())
|
if (_evmVersion.has_value())
|
||||||
rules += evmRuleList(*_evmVersion, A, B, C, W, X, Y, Z);
|
rules += evmRuleList(*_evmVersion, A, B, C, W, X, Y, Z);
|
||||||
|
@ -30,9 +30,8 @@ namespace solidity::evmasm
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Rule that contains a pattern, an action that can be applied
|
* Rule that contains a pattern, an action that can be applied
|
||||||
* after the pattern has matched and a bool that indicates
|
* after the pattern has matched and optional condition to check if the
|
||||||
* whether the action would remove something from the expression
|
* action should be applied.
|
||||||
* than is not a constant literal.
|
|
||||||
*/
|
*/
|
||||||
template <class Pattern>
|
template <class Pattern>
|
||||||
struct SimplificationRule
|
struct SimplificationRule
|
||||||
@ -40,18 +39,15 @@ struct SimplificationRule
|
|||||||
SimplificationRule(
|
SimplificationRule(
|
||||||
Pattern _pattern,
|
Pattern _pattern,
|
||||||
std::function<Pattern()> _action,
|
std::function<Pattern()> _action,
|
||||||
bool _removesNonConstants,
|
|
||||||
std::function<bool()> _feasible = {}
|
std::function<bool()> _feasible = {}
|
||||||
):
|
):
|
||||||
pattern(std::move(_pattern)),
|
pattern(std::move(_pattern)),
|
||||||
action(std::move(_action)),
|
action(std::move(_action)),
|
||||||
removesNonConstants(_removesNonConstants),
|
|
||||||
feasible(std::move(_feasible))
|
feasible(std::move(_feasible))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Pattern pattern;
|
Pattern pattern;
|
||||||
std::function<Pattern()> action;
|
std::function<Pattern()> action;
|
||||||
bool removesNonConstants;
|
|
||||||
std::function<bool()> feasible;
|
std::function<bool()> feasible;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -50,6 +50,7 @@ void CHCSmtLib2Interface::reset()
|
|||||||
{
|
{
|
||||||
m_accumulatedOutput.clear();
|
m_accumulatedOutput.clear();
|
||||||
m_variables.clear();
|
m_variables.clear();
|
||||||
|
m_unhandledQueries.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHCSmtLib2Interface::registerRelation(Expression const& _expr)
|
void CHCSmtLib2Interface::registerRelation(Expression const& _expr)
|
||||||
|
@ -196,6 +196,12 @@ CVC4::Expr CVC4Interface::toCVC4Expr(Expression const& _expr)
|
|||||||
return m_context.mkExpr(CVC4::kind::BITVECTOR_OR, arguments[0], arguments[1]);
|
return m_context.mkExpr(CVC4::kind::BITVECTOR_OR, arguments[0], arguments[1]);
|
||||||
else if (n == "bvxor")
|
else if (n == "bvxor")
|
||||||
return m_context.mkExpr(CVC4::kind::BITVECTOR_XOR, arguments[0], arguments[1]);
|
return m_context.mkExpr(CVC4::kind::BITVECTOR_XOR, arguments[0], arguments[1]);
|
||||||
|
else if (n == "bvshl")
|
||||||
|
return m_context.mkExpr(CVC4::kind::BITVECTOR_SHL, arguments[0], arguments[1]);
|
||||||
|
else if (n == "bvlshr")
|
||||||
|
return m_context.mkExpr(CVC4::kind::BITVECTOR_LSHR, arguments[0], arguments[1]);
|
||||||
|
else if (n == "bvashr")
|
||||||
|
return m_context.mkExpr(CVC4::kind::BITVECTOR_ASHR, arguments[0], arguments[1]);
|
||||||
else if (n == "int2bv")
|
else if (n == "int2bv")
|
||||||
{
|
{
|
||||||
size_t size = std::stoul(_expr.arguments[1].name);
|
size_t size = std::stoul(_expr.arguments[1].name);
|
||||||
@ -289,6 +295,8 @@ CVC4::Type CVC4Interface::cvc4Sort(Sort const& _sort)
|
|||||||
return m_context.booleanType();
|
return m_context.booleanType();
|
||||||
case Kind::Int:
|
case Kind::Int:
|
||||||
return m_context.integerType();
|
return m_context.integerType();
|
||||||
|
case Kind::BitVector:
|
||||||
|
return m_context.mkBitVectorType(dynamic_cast<BitVectorSort const&>(_sort).size);
|
||||||
case Kind::Function:
|
case Kind::Function:
|
||||||
{
|
{
|
||||||
FunctionSort const& fSort = dynamic_cast<FunctionSort const&>(_sort);
|
FunctionSort const& fSort = dynamic_cast<FunctionSort const&>(_sort);
|
||||||
|
@ -38,11 +38,11 @@ using namespace solidity::frontend;
|
|||||||
using namespace solidity::smtutil;
|
using namespace solidity::smtutil;
|
||||||
|
|
||||||
SMTLib2Interface::SMTLib2Interface(
|
SMTLib2Interface::SMTLib2Interface(
|
||||||
map<h256, string> const& _queryResponses,
|
map<h256, string> _queryResponses,
|
||||||
ReadCallback::Callback _smtCallback
|
ReadCallback::Callback _smtCallback
|
||||||
):
|
):
|
||||||
m_queryResponses(_queryResponses),
|
m_queryResponses(move(_queryResponses)),
|
||||||
m_smtCallback(std::move(_smtCallback))
|
m_smtCallback(move(_smtCallback))
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
@ -215,6 +215,8 @@ string SMTLib2Interface::toSmtLibSort(Sort const& _sort)
|
|||||||
return "Int";
|
return "Int";
|
||||||
case Kind::Bool:
|
case Kind::Bool:
|
||||||
return "Bool";
|
return "Bool";
|
||||||
|
case Kind::BitVector:
|
||||||
|
return "(_ BitVec " + to_string(dynamic_cast<BitVectorSort const&>(_sort).size) + ")";
|
||||||
case Kind::Array:
|
case Kind::Array:
|
||||||
{
|
{
|
||||||
auto const& arraySort = dynamic_cast<ArraySort const&>(_sort);
|
auto const& arraySort = dynamic_cast<ArraySort const&>(_sort);
|
||||||
|
@ -39,8 +39,8 @@ class SMTLib2Interface: public SolverInterface, public boost::noncopyable
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit SMTLib2Interface(
|
explicit SMTLib2Interface(
|
||||||
std::map<util::h256, std::string> const& _queryResponses,
|
std::map<util::h256, std::string> _queryResponses = {},
|
||||||
frontend::ReadCallback::Callback _smtCallback
|
frontend::ReadCallback::Callback _smtCallback = {}
|
||||||
);
|
);
|
||||||
|
|
||||||
void reset() override;
|
void reset() override;
|
||||||
@ -77,7 +77,7 @@ private:
|
|||||||
std::map<std::string, SortPointer> m_variables;
|
std::map<std::string, SortPointer> m_variables;
|
||||||
std::set<std::string> m_userSorts;
|
std::set<std::string> m_userSorts;
|
||||||
|
|
||||||
std::map<util::h256, std::string> const& m_queryResponses;
|
std::map<util::h256, std::string> m_queryResponses;
|
||||||
std::vector<std::string> m_unhandledQueries;
|
std::vector<std::string> m_unhandledQueries;
|
||||||
|
|
||||||
frontend::ReadCallback::Callback m_smtCallback;
|
frontend::ReadCallback::Callback m_smtCallback;
|
||||||
|
@ -33,12 +33,12 @@ using namespace solidity::frontend;
|
|||||||
using namespace solidity::smtutil;
|
using namespace solidity::smtutil;
|
||||||
|
|
||||||
SMTPortfolio::SMTPortfolio(
|
SMTPortfolio::SMTPortfolio(
|
||||||
map<h256, string> const& _smtlib2Responses,
|
map<h256, string> _smtlib2Responses,
|
||||||
frontend::ReadCallback::Callback const& _smtCallback,
|
frontend::ReadCallback::Callback _smtCallback,
|
||||||
[[maybe_unused]] SMTSolverChoice _enabledSolvers
|
[[maybe_unused]] SMTSolverChoice _enabledSolvers
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
m_solvers.emplace_back(make_unique<SMTLib2Interface>(_smtlib2Responses, _smtCallback));
|
m_solvers.emplace_back(make_unique<SMTLib2Interface>(move(_smtlib2Responses), move(_smtCallback)));
|
||||||
#ifdef HAVE_Z3
|
#ifdef HAVE_Z3
|
||||||
if (_enabledSolvers.z3)
|
if (_enabledSolvers.z3)
|
||||||
m_solvers.emplace_back(make_unique<Z3Interface>());
|
m_solvers.emplace_back(make_unique<Z3Interface>());
|
||||||
|
@ -40,9 +40,9 @@ class SMTPortfolio: public SolverInterface, public boost::noncopyable
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SMTPortfolio(
|
SMTPortfolio(
|
||||||
std::map<util::h256, std::string> const& _smtlib2Responses,
|
std::map<util::h256, std::string> _smtlib2Responses = {},
|
||||||
frontend::ReadCallback::Callback const& _smtCallback,
|
frontend::ReadCallback::Callback _smtCallback = {},
|
||||||
SMTSolverChoice _enabledSolvers
|
SMTSolverChoice _enabledSolvers = SMTSolverChoice::All()
|
||||||
);
|
);
|
||||||
|
|
||||||
void reset() override;
|
void reset() override;
|
||||||
|
@ -99,6 +99,9 @@ public:
|
|||||||
{"bvand", 2},
|
{"bvand", 2},
|
||||||
{"bvor", 2},
|
{"bvor", 2},
|
||||||
{"bvxor", 2},
|
{"bvxor", 2},
|
||||||
|
{"bvshl", 2},
|
||||||
|
{"bvlshr", 2},
|
||||||
|
{"bvashr", 2},
|
||||||
{"int2bv", 2},
|
{"int2bv", 2},
|
||||||
{"bv2int", 1},
|
{"bv2int", 1},
|
||||||
{"select", 2},
|
{"select", 2},
|
||||||
@ -299,15 +302,30 @@ public:
|
|||||||
auto bvSort = _a.sort;
|
auto bvSort = _a.sort;
|
||||||
return Expression("bvand", {std::move(_a), std::move(_b)}, bvSort);
|
return Expression("bvand", {std::move(_a), std::move(_b)}, bvSort);
|
||||||
}
|
}
|
||||||
|
friend Expression operator|(Expression _a, Expression _b)
|
||||||
|
{
|
||||||
|
auto bvSort = _a.sort;
|
||||||
|
return Expression("bvor", {std::move(_a), std::move(_b)}, bvSort);
|
||||||
|
}
|
||||||
friend Expression operator^(Expression _a, Expression _b)
|
friend Expression operator^(Expression _a, Expression _b)
|
||||||
{
|
{
|
||||||
auto bvSort = _a.sort;
|
auto bvSort = _a.sort;
|
||||||
return Expression("bvxor", {std::move(_a), std::move(_b)}, bvSort);
|
return Expression("bvxor", {std::move(_a), std::move(_b)}, bvSort);
|
||||||
}
|
}
|
||||||
friend Expression operator|(Expression _a, Expression _b)
|
friend Expression operator<<(Expression _a, Expression _b)
|
||||||
{
|
{
|
||||||
auto bvSort = _a.sort;
|
auto bvSort = _a.sort;
|
||||||
return Expression("bvor", {std::move(_a), std::move(_b)}, bvSort);
|
return Expression("bvshl", {std::move(_a), std::move(_b)}, bvSort);
|
||||||
|
}
|
||||||
|
friend Expression operator>>(Expression _a, Expression _b)
|
||||||
|
{
|
||||||
|
auto bvSort = _a.sort;
|
||||||
|
return Expression("bvlshr", {std::move(_a), std::move(_b)}, bvSort);
|
||||||
|
}
|
||||||
|
static Expression ashr(Expression _a, Expression _b)
|
||||||
|
{
|
||||||
|
auto bvSort = _a.sort;
|
||||||
|
return Expression("bvashr", {std::move(_a), std::move(_b)}, bvSort);
|
||||||
}
|
}
|
||||||
Expression operator()(std::vector<Expression> _arguments) const
|
Expression operator()(std::vector<Expression> _arguments) const
|
||||||
{
|
{
|
||||||
|
@ -35,4 +35,6 @@ shared_ptr<IntSort> SortProvider::intSort(bool _signed)
|
|||||||
return uintSort;
|
return uintSort;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shared_ptr<BitVectorSort> const SortProvider::bitVectorSort{make_shared<BitVectorSort>(256)};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -195,6 +195,7 @@ struct SortProvider
|
|||||||
static std::shared_ptr<IntSort> const uintSort;
|
static std::shared_ptr<IntSort> const uintSort;
|
||||||
static std::shared_ptr<IntSort> const sintSort;
|
static std::shared_ptr<IntSort> const sintSort;
|
||||||
static std::shared_ptr<IntSort> intSort(bool _signed = false);
|
static std::shared_ptr<IntSort> intSort(bool _signed = false);
|
||||||
|
static std::shared_ptr<BitVectorSort> const bitVectorSort;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -189,6 +189,12 @@ z3::expr Z3Interface::toZ3Expr(Expression const& _expr)
|
|||||||
return arguments[0] | arguments[1];
|
return arguments[0] | arguments[1];
|
||||||
else if (n == "bvxor")
|
else if (n == "bvxor")
|
||||||
return arguments[0] ^ arguments[1];
|
return arguments[0] ^ arguments[1];
|
||||||
|
else if (n == "bvshl")
|
||||||
|
return z3::shl(arguments[0], arguments[1]);
|
||||||
|
else if (n == "bvlshr")
|
||||||
|
return z3::lshr(arguments[0], arguments[1]);
|
||||||
|
else if (n == "bvashr")
|
||||||
|
return z3::ashr(arguments[0], arguments[1]);
|
||||||
else if (n == "int2bv")
|
else if (n == "int2bv")
|
||||||
{
|
{
|
||||||
size_t size = std::stoul(_expr.arguments[1].name);
|
size_t size = std::stoul(_expr.arguments[1].name);
|
||||||
@ -245,6 +251,8 @@ z3::sort Z3Interface::z3Sort(Sort const& _sort)
|
|||||||
return m_context.bool_sort();
|
return m_context.bool_sort();
|
||||||
case Kind::Int:
|
case Kind::Int:
|
||||||
return m_context.int_sort();
|
return m_context.int_sort();
|
||||||
|
case Kind::BitVector:
|
||||||
|
return m_context.bv_sort(dynamic_cast<BitVectorSort const&>(_sort).size);
|
||||||
case Kind::Array:
|
case Kind::Array:
|
||||||
{
|
{
|
||||||
auto const& arraySort = dynamic_cast<ArraySort const&>(_sort);
|
auto const& arraySort = dynamic_cast<ArraySort const&>(_sort);
|
||||||
|
@ -30,6 +30,8 @@ set(sources
|
|||||||
analysis/PostTypeChecker.h
|
analysis/PostTypeChecker.h
|
||||||
analysis/ReferencesResolver.cpp
|
analysis/ReferencesResolver.cpp
|
||||||
analysis/ReferencesResolver.h
|
analysis/ReferencesResolver.h
|
||||||
|
analysis/Scoper.cpp
|
||||||
|
analysis/Scoper.h
|
||||||
analysis/StaticAnalyzer.cpp
|
analysis/StaticAnalyzer.cpp
|
||||||
analysis/StaticAnalyzer.h
|
analysis/StaticAnalyzer.h
|
||||||
analysis/SyntaxChecker.cpp
|
analysis/SyntaxChecker.cpp
|
||||||
|
@ -519,14 +519,13 @@ bool DeclarationRegistrationHelper::visit(SourceUnit& _sourceUnit)
|
|||||||
if (!m_scopes[&_sourceUnit])
|
if (!m_scopes[&_sourceUnit])
|
||||||
// By importing, it is possible that the container already exists.
|
// By importing, it is possible that the container already exists.
|
||||||
m_scopes[&_sourceUnit] = make_shared<DeclarationContainer>(m_currentScope, m_scopes[m_currentScope].get());
|
m_scopes[&_sourceUnit] = make_shared<DeclarationContainer>(m_currentScope, m_scopes[m_currentScope].get());
|
||||||
m_currentScope = &_sourceUnit;
|
return ASTVisitor::visit(_sourceUnit);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeclarationRegistrationHelper::endVisit(SourceUnit& _sourceUnit)
|
void DeclarationRegistrationHelper::endVisit(SourceUnit& _sourceUnit)
|
||||||
{
|
{
|
||||||
_sourceUnit.annotation().exportedSymbols = m_scopes[&_sourceUnit]->declarations();
|
_sourceUnit.annotation().exportedSymbols = m_scopes[&_sourceUnit]->declarations();
|
||||||
closeCurrentScope();
|
ASTVisitor::endVisit(_sourceUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeclarationRegistrationHelper::visit(ImportDirective& _import)
|
bool DeclarationRegistrationHelper::visit(ImportDirective& _import)
|
||||||
@ -536,8 +535,7 @@ bool DeclarationRegistrationHelper::visit(ImportDirective& _import)
|
|||||||
if (!m_scopes[importee])
|
if (!m_scopes[importee])
|
||||||
m_scopes[importee] = make_shared<DeclarationContainer>(nullptr, m_scopes[nullptr].get());
|
m_scopes[importee] = make_shared<DeclarationContainer>(nullptr, m_scopes[nullptr].get());
|
||||||
m_scopes[&_import] = m_scopes[importee];
|
m_scopes[&_import] = m_scopes[importee];
|
||||||
registerDeclaration(_import, false);
|
return ASTVisitor::visit(_import);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeclarationRegistrationHelper::visit(ContractDefinition& _contract)
|
bool DeclarationRegistrationHelper::visit(ContractDefinition& _contract)
|
||||||
@ -547,122 +545,17 @@ bool DeclarationRegistrationHelper::visit(ContractDefinition& _contract)
|
|||||||
m_scopes[nullptr]->registerDeclaration(*m_globalContext.currentSuper(), nullptr, false, true);
|
m_scopes[nullptr]->registerDeclaration(*m_globalContext.currentSuper(), nullptr, false, true);
|
||||||
m_currentContract = &_contract;
|
m_currentContract = &_contract;
|
||||||
|
|
||||||
registerDeclaration(_contract, true);
|
return ASTVisitor::visit(_contract);
|
||||||
_contract.annotation().canonicalName = currentCanonicalName();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeclarationRegistrationHelper::endVisit(ContractDefinition&)
|
void DeclarationRegistrationHelper::endVisit(ContractDefinition& _contract)
|
||||||
{
|
{
|
||||||
// make "this" and "super" invisible.
|
// make "this" and "super" invisible.
|
||||||
m_scopes[nullptr]->registerDeclaration(*m_globalContext.currentThis(), nullptr, true, true);
|
m_scopes[nullptr]->registerDeclaration(*m_globalContext.currentThis(), nullptr, true, true);
|
||||||
m_scopes[nullptr]->registerDeclaration(*m_globalContext.currentSuper(), nullptr, true, true);
|
m_scopes[nullptr]->registerDeclaration(*m_globalContext.currentSuper(), nullptr, true, true);
|
||||||
m_globalContext.resetCurrentContract();
|
m_globalContext.resetCurrentContract();
|
||||||
m_currentContract = nullptr;
|
m_currentContract = nullptr;
|
||||||
closeCurrentScope();
|
ASTVisitor::endVisit(_contract);
|
||||||
}
|
|
||||||
|
|
||||||
bool DeclarationRegistrationHelper::visit(StructDefinition& _struct)
|
|
||||||
{
|
|
||||||
registerDeclaration(_struct, true);
|
|
||||||
_struct.annotation().canonicalName = currentCanonicalName();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeclarationRegistrationHelper::endVisit(StructDefinition&)
|
|
||||||
{
|
|
||||||
closeCurrentScope();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DeclarationRegistrationHelper::visit(EnumDefinition& _enum)
|
|
||||||
{
|
|
||||||
registerDeclaration(_enum, true);
|
|
||||||
_enum.annotation().canonicalName = currentCanonicalName();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeclarationRegistrationHelper::endVisit(EnumDefinition&)
|
|
||||||
{
|
|
||||||
closeCurrentScope();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DeclarationRegistrationHelper::visit(EnumValue& _value)
|
|
||||||
{
|
|
||||||
registerDeclaration(_value, false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DeclarationRegistrationHelper::visit(FunctionDefinition& _function)
|
|
||||||
{
|
|
||||||
registerDeclaration(_function, true);
|
|
||||||
m_currentFunction = &_function;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeclarationRegistrationHelper::endVisit(FunctionDefinition&)
|
|
||||||
{
|
|
||||||
m_currentFunction = nullptr;
|
|
||||||
closeCurrentScope();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DeclarationRegistrationHelper::visit(TryCatchClause& _tryCatchClause)
|
|
||||||
{
|
|
||||||
_tryCatchClause.annotation().scope = m_currentScope;
|
|
||||||
enterNewSubScope(_tryCatchClause);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeclarationRegistrationHelper::endVisit(TryCatchClause&)
|
|
||||||
{
|
|
||||||
closeCurrentScope();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DeclarationRegistrationHelper::visit(ModifierDefinition& _modifier)
|
|
||||||
{
|
|
||||||
registerDeclaration(_modifier, true);
|
|
||||||
m_currentFunction = &_modifier;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeclarationRegistrationHelper::endVisit(ModifierDefinition&)
|
|
||||||
{
|
|
||||||
m_currentFunction = nullptr;
|
|
||||||
closeCurrentScope();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DeclarationRegistrationHelper::visit(FunctionTypeName& _funTypeName)
|
|
||||||
{
|
|
||||||
enterNewSubScope(_funTypeName);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeclarationRegistrationHelper::endVisit(FunctionTypeName&)
|
|
||||||
{
|
|
||||||
closeCurrentScope();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DeclarationRegistrationHelper::visit(Block& _block)
|
|
||||||
{
|
|
||||||
_block.annotation().scope = m_currentScope;
|
|
||||||
enterNewSubScope(_block);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeclarationRegistrationHelper::endVisit(Block&)
|
|
||||||
{
|
|
||||||
closeCurrentScope();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DeclarationRegistrationHelper::visit(ForStatement& _for)
|
|
||||||
{
|
|
||||||
_for.annotation().scope = m_currentScope;
|
|
||||||
enterNewSubScope(_for);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeclarationRegistrationHelper::endVisit(ForStatement&)
|
|
||||||
{
|
|
||||||
closeCurrentScope();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeclarationRegistrationHelper::endVisit(VariableDeclarationStatement& _variableDeclarationStatement)
|
void DeclarationRegistrationHelper::endVisit(VariableDeclarationStatement& _variableDeclarationStatement)
|
||||||
@ -673,32 +566,42 @@ void DeclarationRegistrationHelper::endVisit(VariableDeclarationStatement& _vari
|
|||||||
for (ASTPointer<VariableDeclaration> const& var: _variableDeclarationStatement.declarations())
|
for (ASTPointer<VariableDeclaration> const& var: _variableDeclarationStatement.declarations())
|
||||||
if (var)
|
if (var)
|
||||||
m_currentFunction->addLocalVariable(*var);
|
m_currentFunction->addLocalVariable(*var);
|
||||||
|
ASTVisitor::endVisit(_variableDeclarationStatement);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeclarationRegistrationHelper::visit(VariableDeclaration& _declaration)
|
bool DeclarationRegistrationHelper::visitNode(ASTNode& _node)
|
||||||
{
|
{
|
||||||
registerDeclaration(_declaration, false);
|
if (auto const* scopable = dynamic_cast<Scopable const*>(&_node))
|
||||||
|
solAssert(scopable->annotation().scope == m_currentScope, "");
|
||||||
|
|
||||||
|
if (auto* declaration = dynamic_cast<Declaration*>(&_node))
|
||||||
|
registerDeclaration(*declaration);
|
||||||
|
if (dynamic_cast<ScopeOpener const*>(&_node))
|
||||||
|
enterNewSubScope(_node);
|
||||||
|
|
||||||
|
if (auto* variableScope = dynamic_cast<VariableScope*>(&_node))
|
||||||
|
m_currentFunction = variableScope;
|
||||||
|
if (auto* annotation = dynamic_cast<TypeDeclarationAnnotation*>(&_node.annotation()))
|
||||||
|
annotation->canonicalName = currentCanonicalName();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeclarationRegistrationHelper::visit(EventDefinition& _event)
|
void DeclarationRegistrationHelper::endVisitNode(ASTNode& _node)
|
||||||
{
|
{
|
||||||
registerDeclaration(_event, true);
|
if (dynamic_cast<ScopeOpener const*>(&_node))
|
||||||
return true;
|
closeCurrentScope();
|
||||||
}
|
if (dynamic_cast<VariableScope*>(&_node))
|
||||||
|
m_currentFunction = nullptr;
|
||||||
void DeclarationRegistrationHelper::endVisit(EventDefinition&)
|
|
||||||
{
|
|
||||||
closeCurrentScope();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeclarationRegistrationHelper::enterNewSubScope(ASTNode& _subScope)
|
void DeclarationRegistrationHelper::enterNewSubScope(ASTNode& _subScope)
|
||||||
{
|
{
|
||||||
map<ASTNode const*, shared_ptr<DeclarationContainer>>::iterator iter;
|
|
||||||
bool newlyAdded;
|
|
||||||
shared_ptr<DeclarationContainer> container{make_shared<DeclarationContainer>(m_currentScope, m_scopes[m_currentScope].get())};
|
shared_ptr<DeclarationContainer> container{make_shared<DeclarationContainer>(m_currentScope, m_scopes[m_currentScope].get())};
|
||||||
tie(iter, newlyAdded) = m_scopes.emplace(&_subScope, move(container));
|
bool newlyAdded = m_scopes.emplace(&_subScope, move(container)).second;
|
||||||
solAssert(newlyAdded, "Unable to add new scope.");
|
// Source units are the only AST nodes for which containers can be created from multiple places
|
||||||
|
// due to imports.
|
||||||
|
solAssert(newlyAdded || dynamic_cast<SourceUnit const*>(&_subScope), "Unable to add new scope.");
|
||||||
m_currentScope = &_subScope;
|
m_currentScope = &_subScope;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -708,7 +611,7 @@ void DeclarationRegistrationHelper::closeCurrentScope()
|
|||||||
m_currentScope = m_scopes[m_currentScope]->enclosingNode();
|
m_currentScope = m_scopes[m_currentScope]->enclosingNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope)
|
void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration)
|
||||||
{
|
{
|
||||||
solAssert(m_currentScope && m_scopes.count(m_currentScope), "No current scope.");
|
solAssert(m_currentScope && m_scopes.count(m_currentScope), "No current scope.");
|
||||||
|
|
||||||
@ -729,10 +632,8 @@ void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaratio
|
|||||||
|
|
||||||
registerDeclaration(*m_scopes[m_currentScope], _declaration, nullptr, nullptr, warnAboutShadowing, inactive, m_errorReporter);
|
registerDeclaration(*m_scopes[m_currentScope], _declaration, nullptr, nullptr, warnAboutShadowing, inactive, m_errorReporter);
|
||||||
|
|
||||||
_declaration.annotation().scope = m_currentScope;
|
solAssert(_declaration.annotation().scope == m_currentScope, "");
|
||||||
_declaration.annotation().contract = m_currentContract;
|
solAssert(_declaration.annotation().contract == m_currentContract, "");
|
||||||
if (_opensScope)
|
|
||||||
enterNewSubScope(_declaration);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string DeclarationRegistrationHelper::currentCanonicalName() const
|
string DeclarationRegistrationHelper::currentCanonicalName() const
|
||||||
|
@ -163,31 +163,15 @@ private:
|
|||||||
bool visit(ImportDirective& _import) override;
|
bool visit(ImportDirective& _import) override;
|
||||||
bool visit(ContractDefinition& _contract) override;
|
bool visit(ContractDefinition& _contract) override;
|
||||||
void endVisit(ContractDefinition& _contract) override;
|
void endVisit(ContractDefinition& _contract) override;
|
||||||
bool visit(StructDefinition& _struct) override;
|
|
||||||
void endVisit(StructDefinition& _struct) override;
|
|
||||||
bool visit(EnumDefinition& _enum) override;
|
|
||||||
void endVisit(EnumDefinition& _enum) override;
|
|
||||||
bool visit(EnumValue& _value) override;
|
|
||||||
bool visit(FunctionDefinition& _function) override;
|
|
||||||
void endVisit(FunctionDefinition& _function) override;
|
|
||||||
bool visit(TryCatchClause& _tryCatchClause) override;
|
|
||||||
void endVisit(TryCatchClause& _tryCatchClause) override;
|
|
||||||
bool visit(ModifierDefinition& _modifier) override;
|
|
||||||
void endVisit(ModifierDefinition& _modifier) override;
|
|
||||||
bool visit(FunctionTypeName& _funTypeName) override;
|
|
||||||
void endVisit(FunctionTypeName& _funTypeName) override;
|
|
||||||
bool visit(Block& _block) override;
|
|
||||||
void endVisit(Block& _block) override;
|
|
||||||
bool visit(ForStatement& _forLoop) override;
|
|
||||||
void endVisit(ForStatement& _forLoop) override;
|
|
||||||
void endVisit(VariableDeclarationStatement& _variableDeclarationStatement) override;
|
void endVisit(VariableDeclarationStatement& _variableDeclarationStatement) override;
|
||||||
bool visit(VariableDeclaration& _declaration) override;
|
|
||||||
bool visit(EventDefinition& _event) override;
|
bool visitNode(ASTNode& _node) override;
|
||||||
void endVisit(EventDefinition& _event) override;
|
void endVisitNode(ASTNode& _node) override;
|
||||||
|
|
||||||
|
|
||||||
void enterNewSubScope(ASTNode& _subScope);
|
void enterNewSubScope(ASTNode& _subScope);
|
||||||
void closeCurrentScope();
|
void closeCurrentScope();
|
||||||
void registerDeclaration(Declaration& _declaration, bool _opensScope);
|
void registerDeclaration(Declaration& _declaration);
|
||||||
|
|
||||||
static bool isOverloadedFunction(Declaration const& _declaration1, Declaration const& _declaration2);
|
static bool isOverloadedFunction(Declaration const& _declaration1, Declaration const& _declaration2);
|
||||||
|
|
||||||
|
63
libsolidity/analysis/Scoper.cpp
Normal file
63
libsolidity/analysis/Scoper.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 <libsolidity/analysis/Scoper.h>
|
||||||
|
|
||||||
|
#include <libsolidity/ast/AST.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace solidity;
|
||||||
|
using namespace solidity::frontend;
|
||||||
|
|
||||||
|
void Scoper::assignScopes(ASTNode const& _astRoot)
|
||||||
|
{
|
||||||
|
Scoper scoper;
|
||||||
|
_astRoot.accept(scoper);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Scoper::visit(ContractDefinition const& _contract)
|
||||||
|
{
|
||||||
|
solAssert(m_contract == nullptr, "");
|
||||||
|
m_contract = &_contract;
|
||||||
|
return ASTConstVisitor::visit(_contract);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scoper::endVisit(ContractDefinition const& _contract)
|
||||||
|
{
|
||||||
|
solAssert(m_contract == &_contract, "");
|
||||||
|
m_contract = nullptr;
|
||||||
|
ASTConstVisitor::endVisit(_contract);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Scoper::visitNode(ASTNode const& _node)
|
||||||
|
{
|
||||||
|
if (auto const* scopable = dynamic_cast<Scopable const*>(&_node))
|
||||||
|
{
|
||||||
|
scopable->annotation().scope = m_scopes.empty() ? nullptr : m_scopes.back();
|
||||||
|
scopable->annotation().contract = m_contract;
|
||||||
|
}
|
||||||
|
if (dynamic_cast<ScopeOpener const*>(&_node))
|
||||||
|
m_scopes.push_back(&_node);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scoper::endVisitNode(ASTNode const& _node)
|
||||||
|
{
|
||||||
|
if (dynamic_cast<ScopeOpener const*>(&_node))
|
||||||
|
m_scopes.pop_back();
|
||||||
|
}
|
45
libsolidity/analysis/Scoper.h
Normal file
45
libsolidity/analysis/Scoper.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
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 <libsolidity/ast/ASTForward.h>
|
||||||
|
#include <libsolidity/ast/ASTVisitor.h>
|
||||||
|
|
||||||
|
namespace solidity::frontend
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AST visitor that assigns syntactic scopes.
|
||||||
|
*/
|
||||||
|
class Scoper: private ASTConstVisitor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void assignScopes(ASTNode const& _astRoot);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool visit(ContractDefinition const& _contract) override;
|
||||||
|
void endVisit(ContractDefinition const& _contract) override;
|
||||||
|
bool visitNode(ASTNode const& _node) override;
|
||||||
|
void endVisitNode(ASTNode const& _node) override;
|
||||||
|
|
||||||
|
ContractDefinition const* m_contract = nullptr;
|
||||||
|
std::vector<ASTNode const*> m_scopes;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -156,6 +156,20 @@ bool StaticAnalyzer::visit(VariableDeclaration const& _variable)
|
|||||||
// This is not a no-op, the entry might pre-exist.
|
// This is not a no-op, the entry might pre-exist.
|
||||||
m_localVarUseCount[make_pair(_variable.id(), &_variable)] += 0;
|
m_localVarUseCount[make_pair(_variable.id(), &_variable)] += 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_variable.isStateVariable() || _variable.referenceLocation() == VariableDeclaration::Location::Storage)
|
||||||
|
{
|
||||||
|
TypePointer varType = _variable.annotation().type;
|
||||||
|
for (Type const* subtype: frontend::oversizedSubtypes(*varType))
|
||||||
|
{
|
||||||
|
string message = "Type " + subtype->toString(true) +
|
||||||
|
" covers a large part of storage and thus makes collisions likely."
|
||||||
|
" Either use mappings or dynamic arrays and allow their size to be increased only"
|
||||||
|
" in small quantities per transaction.";
|
||||||
|
m_errorReporter.warning(7325_error, _variable.typeName().location(), message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -609,29 +609,6 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (varType->dataStoredIn(DataLocation::Storage))
|
|
||||||
{
|
|
||||||
auto collisionMessage = [&](string const& variableOrType, bool isVariable) -> string {
|
|
||||||
return
|
|
||||||
(isVariable ? "Variable " : "Type ") +
|
|
||||||
util::escapeAndQuoteString(variableOrType) +
|
|
||||||
" covers a large part of storage and thus makes collisions likely."
|
|
||||||
" Either use mappings or dynamic arrays and allow their size to be increased only"
|
|
||||||
" in small quantities per transaction.";
|
|
||||||
};
|
|
||||||
|
|
||||||
if (varType->storageSizeUpperBound() >= bigint(1) << 64)
|
|
||||||
{
|
|
||||||
if (_variable.isStateVariable())
|
|
||||||
m_errorReporter.warning(3408_error, _variable.location(), collisionMessage(_variable.name(), true));
|
|
||||||
else
|
|
||||||
m_errorReporter.warning(2332_error, _variable.typeName().location(), collisionMessage(varType->toString(true), false));
|
|
||||||
}
|
|
||||||
vector<Type const*> oversizedSubtypes = frontend::oversizedSubtypes(*varType);
|
|
||||||
for (Type const* subtype: oversizedSubtypes)
|
|
||||||
m_errorReporter.warning(7325_error, _variable.typeName().location(), collisionMessage(subtype->canonicalName(), false));
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,10 +152,19 @@ std::vector<T const*> ASTNode::filteredNodes(std::vector<ASTPointer<ASTNode>> co
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract marker class that specifies that this AST node opens a scope.
|
||||||
|
*/
|
||||||
|
class ScopeOpener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~ScopeOpener() = default;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Source unit containing import directives and contract definitions.
|
* Source unit containing import directives and contract definitions.
|
||||||
*/
|
*/
|
||||||
class SourceUnit: public ASTNode
|
class SourceUnit: public ASTNode, public ScopeOpener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SourceUnit(
|
SourceUnit(
|
||||||
@ -455,7 +464,7 @@ protected:
|
|||||||
* document order. It first visits all struct declarations, then all variable declarations and
|
* document order. It first visits all struct declarations, then all variable declarations and
|
||||||
* finally all function declarations.
|
* finally all function declarations.
|
||||||
*/
|
*/
|
||||||
class ContractDefinition: public Declaration, public StructurallyDocumented
|
class ContractDefinition: public Declaration, public StructurallyDocumented, public ScopeOpener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ContractDefinition(
|
ContractDefinition(
|
||||||
@ -593,7 +602,7 @@ private:
|
|||||||
ASTPointer<TypeName> m_typeName;
|
ASTPointer<TypeName> m_typeName;
|
||||||
};
|
};
|
||||||
|
|
||||||
class StructDefinition: public Declaration
|
class StructDefinition: public Declaration, public ScopeOpener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
StructDefinition(
|
StructDefinition(
|
||||||
@ -620,7 +629,7 @@ private:
|
|||||||
std::vector<ASTPointer<VariableDeclaration>> m_members;
|
std::vector<ASTPointer<VariableDeclaration>> m_members;
|
||||||
};
|
};
|
||||||
|
|
||||||
class EnumDefinition: public Declaration
|
class EnumDefinition: public Declaration, public ScopeOpener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
EnumDefinition(
|
EnumDefinition(
|
||||||
@ -765,7 +774,7 @@ protected:
|
|||||||
std::vector<ASTPointer<UserDefinedTypeName>> m_overrides;
|
std::vector<ASTPointer<UserDefinedTypeName>> m_overrides;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FunctionDefinition: public CallableDeclaration, public StructurallyDocumented, public ImplementationOptional
|
class FunctionDefinition: public CallableDeclaration, public StructurallyDocumented, public ImplementationOptional, public ScopeOpener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FunctionDefinition(
|
FunctionDefinition(
|
||||||
@ -989,7 +998,7 @@ private:
|
|||||||
/**
|
/**
|
||||||
* Definition of a function modifier.
|
* Definition of a function modifier.
|
||||||
*/
|
*/
|
||||||
class ModifierDefinition: public CallableDeclaration, public StructurallyDocumented, public ImplementationOptional
|
class ModifierDefinition: public CallableDeclaration, public StructurallyDocumented, public ImplementationOptional, public ScopeOpener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ModifierDefinition(
|
ModifierDefinition(
|
||||||
@ -1061,7 +1070,7 @@ private:
|
|||||||
/**
|
/**
|
||||||
* Definition of a (loggable) event.
|
* Definition of a (loggable) event.
|
||||||
*/
|
*/
|
||||||
class EventDefinition: public CallableDeclaration, public StructurallyDocumented
|
class EventDefinition: public CallableDeclaration, public StructurallyDocumented, public ScopeOpener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
EventDefinition(
|
EventDefinition(
|
||||||
@ -1199,7 +1208,7 @@ private:
|
|||||||
/**
|
/**
|
||||||
* A literal function type. Its source form is "function (paramType1, paramType2) internal / external returns (retType1, retType2)"
|
* A literal function type. Its source form is "function (paramType1, paramType2) internal / external returns (retType1, retType2)"
|
||||||
*/
|
*/
|
||||||
class FunctionTypeName: public TypeName
|
class FunctionTypeName: public TypeName, public ScopeOpener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FunctionTypeName(
|
FunctionTypeName(
|
||||||
@ -1334,7 +1343,7 @@ private:
|
|||||||
/**
|
/**
|
||||||
* Brace-enclosed block containing zero or more statements.
|
* Brace-enclosed block containing zero or more statements.
|
||||||
*/
|
*/
|
||||||
class Block: public Statement, public Scopable
|
class Block: public Statement, public Scopable, public ScopeOpener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Block(
|
Block(
|
||||||
@ -1411,7 +1420,7 @@ private:
|
|||||||
* unsuccessful cases.
|
* unsuccessful cases.
|
||||||
* Names are only allowed for the unsuccessful cases.
|
* Names are only allowed for the unsuccessful cases.
|
||||||
*/
|
*/
|
||||||
class TryCatchClause: public ASTNode, public Scopable
|
class TryCatchClause: public ASTNode, public Scopable, public ScopeOpener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TryCatchClause(
|
TryCatchClause(
|
||||||
@ -1526,7 +1535,7 @@ private:
|
|||||||
/**
|
/**
|
||||||
* For loop statement
|
* For loop statement
|
||||||
*/
|
*/
|
||||||
class ForStatement: public BreakableStatement, public Scopable
|
class ForStatement: public BreakableStatement, public Scopable, public ScopeOpener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ForStatement(
|
ForStatement(
|
||||||
|
@ -108,10 +108,10 @@ struct ScopableAnnotation
|
|||||||
virtual ~ScopableAnnotation() = default;
|
virtual ~ScopableAnnotation() = default;
|
||||||
|
|
||||||
/// The scope this declaration resides in. Can be nullptr if it is the global scope.
|
/// The scope this declaration resides in. Can be nullptr if it is the global scope.
|
||||||
/// Available only after name and type resolution step.
|
/// Filled by the Scoper.
|
||||||
ASTNode const* scope = nullptr;
|
ASTNode const* scope = nullptr;
|
||||||
/// Pointer to the contract this declaration resides in. Can be nullptr if the current scope
|
/// Pointer to the contract this declaration resides in. Can be nullptr if the current scope
|
||||||
/// is not part of a contract. Available only after name and type resolution step.
|
/// is not part of a contract. Filled by the Scoper.
|
||||||
ContractDefinition const* contract = nullptr;
|
ContractDefinition const* contract = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ namespace solidity::frontend
|
|||||||
{
|
{
|
||||||
|
|
||||||
class ASTNode;
|
class ASTNode;
|
||||||
|
class ScopeOpener;
|
||||||
class SourceUnit;
|
class SourceUnit;
|
||||||
class PragmaDirective;
|
class PragmaDirective;
|
||||||
class ImportDirective;
|
class ImportDirective;
|
||||||
|
@ -205,7 +205,7 @@ vector<frontend::Type const*> solidity::frontend::oversizedSubtypes(frontend::Ty
|
|||||||
{
|
{
|
||||||
set<StructDefinition const*> structsSeen;
|
set<StructDefinition const*> structsSeen;
|
||||||
TypeSet oversized;
|
TypeSet oversized;
|
||||||
oversizedSubtypesInner(_type, false, structsSeen, oversized);
|
oversizedSubtypesInner(_type, true, structsSeen, oversized);
|
||||||
vector<frontend::Type const*> res;
|
vector<frontend::Type const*> res;
|
||||||
copy(oversized.cbegin(), oversized.cend(), back_inserter(res));
|
copy(oversized.cbegin(), oversized.cend(), back_inserter(res));
|
||||||
return res;
|
return res;
|
||||||
@ -1569,12 +1569,15 @@ BoolResult ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const
|
|||||||
return true;
|
return true;
|
||||||
if (_convertTo.category() == Category::Contract)
|
if (_convertTo.category() == Category::Contract)
|
||||||
{
|
{
|
||||||
auto const& bases = contractDefinition().annotation().linearizedBaseContracts;
|
auto const& targetContractType = dynamic_cast<ContractType const&>(_convertTo);
|
||||||
if (m_super && bases.size() <= 1)
|
if (targetContractType.isSuper())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
auto const& bases = contractDefinition().annotation().linearizedBaseContracts;
|
||||||
return find(
|
return find(
|
||||||
m_super ? ++bases.begin() : bases.begin(), bases.end(),
|
bases.begin(),
|
||||||
&dynamic_cast<ContractType const&>(_convertTo).contractDefinition()
|
bases.end(),
|
||||||
|
&targetContractType.contractDefinition()
|
||||||
) != bases.end();
|
) != bases.end();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -3482,12 +3485,12 @@ bool FunctionType::canTakeArguments(
|
|||||||
|
|
||||||
size_t matchedNames = 0;
|
size_t matchedNames = 0;
|
||||||
|
|
||||||
for (auto const& argName: _arguments.names)
|
for (size_t a = 0; a < _arguments.names.size(); a++)
|
||||||
for (size_t i = 0; i < paramNames.size(); i++)
|
for (size_t p = 0; p < paramNames.size(); p++)
|
||||||
if (*argName == paramNames[i])
|
if (*_arguments.names[a] == paramNames[p])
|
||||||
{
|
{
|
||||||
matchedNames++;
|
matchedNames++;
|
||||||
if (!_arguments.types[i]->isImplicitlyConvertibleTo(*paramTypes[i]))
|
if (!_arguments.types[a]->isImplicitlyConvertibleTo(*paramTypes[p]))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1198,10 +1198,9 @@ string YulUtilFunctions::storageArrayIndexAccessFunction(ArrayType const& _type)
|
|||||||
slot := array
|
slot := array
|
||||||
}
|
}
|
||||||
<!isBytesArray>
|
<!isBytesArray>
|
||||||
let itemsPerSlot := div(0x20, <storageBytes>)
|
|
||||||
let dataArea := <dataAreaFunc>(array)
|
let dataArea := <dataAreaFunc>(array)
|
||||||
slot := add(dataArea, div(index, itemsPerSlot))
|
slot := add(dataArea, div(index, <itemsPerSlot>))
|
||||||
offset := mod(index, itemsPerSlot)
|
offset := mul(mod(index, <itemsPerSlot>), <storageBytes>)
|
||||||
</isBytesArray>
|
</isBytesArray>
|
||||||
<!multipleItemsPerSlot>
|
<!multipleItemsPerSlot>
|
||||||
let dataArea := <dataAreaFunc>(array)
|
let dataArea := <dataAreaFunc>(array)
|
||||||
@ -1217,6 +1216,7 @@ string YulUtilFunctions::storageArrayIndexAccessFunction(ArrayType const& _type)
|
|||||||
("isBytesArray", _type.isByteArray())
|
("isBytesArray", _type.isByteArray())
|
||||||
("storageSize", _type.baseType()->storageSize().str())
|
("storageSize", _type.baseType()->storageSize().str())
|
||||||
("storageBytes", toString(_type.baseType()->storageBytes()))
|
("storageBytes", toString(_type.baseType()->storageBytes()))
|
||||||
|
("itemsPerSlot", to_string(32 / _type.baseType()->storageBytes()))
|
||||||
.render();
|
.render();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -836,11 +836,11 @@ void BMC::checkCondition(
|
|||||||
case smtutil::CheckResult::SATISFIABLE:
|
case smtutil::CheckResult::SATISFIABLE:
|
||||||
{
|
{
|
||||||
std::ostringstream message;
|
std::ostringstream message;
|
||||||
message << _description << " happens here";
|
message << _description << " happens here.";
|
||||||
if (_callStack.size())
|
if (_callStack.size())
|
||||||
{
|
{
|
||||||
std::ostringstream modelMessage;
|
std::ostringstream modelMessage;
|
||||||
modelMessage << " for:\n";
|
modelMessage << "\nCounterexample:\n";
|
||||||
solAssert(values.size() == expressionNames.size(), "");
|
solAssert(values.size() == expressionNames.size(), "");
|
||||||
map<string, string> sortedModel;
|
map<string, string> sortedModel;
|
||||||
for (size_t i = 0; i < values.size(); ++i)
|
for (size_t i = 0; i < values.size(); ++i)
|
||||||
@ -859,10 +859,7 @@ void BMC::checkCondition(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
message << ".";
|
|
||||||
m_errorReporter.warning(6084_error, _location, message.str(), secondaryLocation);
|
m_errorReporter.warning(6084_error, _location, message.str(), secondaryLocation);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case smtutil::CheckResult::UNSATISFIABLE:
|
case smtutil::CheckResult::UNSATISFIABLE:
|
||||||
|
@ -43,19 +43,19 @@ using namespace solidity::frontend;
|
|||||||
CHC::CHC(
|
CHC::CHC(
|
||||||
smt::EncodingContext& _context,
|
smt::EncodingContext& _context,
|
||||||
ErrorReporter& _errorReporter,
|
ErrorReporter& _errorReporter,
|
||||||
map<util::h256, string> const& _smtlib2Responses,
|
[[maybe_unused]] map<util::h256, string> const& _smtlib2Responses,
|
||||||
ReadCallback::Callback const& _smtCallback,
|
[[maybe_unused]] ReadCallback::Callback const& _smtCallback,
|
||||||
[[maybe_unused]] smtutil::SMTSolverChoice _enabledSolvers
|
smtutil::SMTSolverChoice _enabledSolvers
|
||||||
):
|
):
|
||||||
SMTEncoder(_context),
|
SMTEncoder(_context),
|
||||||
m_outerErrorReporter(_errorReporter),
|
m_outerErrorReporter(_errorReporter),
|
||||||
m_enabledSolvers(_enabledSolvers)
|
m_enabledSolvers(_enabledSolvers)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_Z3
|
bool usesZ3 = _enabledSolvers.z3;
|
||||||
if (_enabledSolvers.z3)
|
#ifndef HAVE_Z3
|
||||||
m_interface = make_unique<smtutil::Z3CHCInterface>();
|
usesZ3 = false;
|
||||||
#endif
|
#endif
|
||||||
if (!m_interface)
|
if (!usesZ3)
|
||||||
m_interface = make_unique<smtutil::CHCSmtLib2Interface>(_smtlib2Responses, _smtCallback);
|
m_interface = make_unique<smtutil::CHCSmtLib2Interface>(_smtlib2Responses, _smtCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,30 +63,8 @@ void CHC::analyze(SourceUnit const& _source)
|
|||||||
{
|
{
|
||||||
solAssert(_source.annotation().experimentalFeatures.count(ExperimentalFeature::SMTChecker), "");
|
solAssert(_source.annotation().experimentalFeatures.count(ExperimentalFeature::SMTChecker), "");
|
||||||
|
|
||||||
bool usesZ3 = false;
|
|
||||||
#ifdef HAVE_Z3
|
|
||||||
usesZ3 = m_enabledSolvers.z3;
|
|
||||||
if (usesZ3)
|
|
||||||
{
|
|
||||||
auto z3Interface = dynamic_cast<smtutil::Z3CHCInterface const*>(m_interface.get());
|
|
||||||
solAssert(z3Interface, "");
|
|
||||||
m_context.setSolver(z3Interface->z3Interface());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (!usesZ3)
|
|
||||||
{
|
|
||||||
auto smtlib2Interface = dynamic_cast<smtutil::CHCSmtLib2Interface const*>(m_interface.get());
|
|
||||||
solAssert(smtlib2Interface, "");
|
|
||||||
m_context.setSolver(smtlib2Interface->smtlib2Interface());
|
|
||||||
}
|
|
||||||
m_context.clear();
|
|
||||||
m_context.setAssertionAccumulation(false);
|
|
||||||
|
|
||||||
resetSourceAnalysis();
|
resetSourceAnalysis();
|
||||||
|
|
||||||
m_genesisPredicate = createSymbolicBlock(arity0FunctionSort(), "genesis");
|
|
||||||
addRule(genesis(), "genesis");
|
|
||||||
|
|
||||||
set<SourceUnit const*, IdCompare> sources;
|
set<SourceUnit const*, IdCompare> sources;
|
||||||
sources.insert(&_source);
|
sources.insert(&_source);
|
||||||
for (auto const& source: _source.referencedSourceUnits(true))
|
for (auto const& source: _source.referencedSourceUnits(true))
|
||||||
@ -131,7 +109,7 @@ bool CHC::visit(ContractDefinition const& _contract)
|
|||||||
void CHC::endVisit(ContractDefinition const& _contract)
|
void CHC::endVisit(ContractDefinition const& _contract)
|
||||||
{
|
{
|
||||||
auto implicitConstructor = (*m_implicitConstructorPredicate)({});
|
auto implicitConstructor = (*m_implicitConstructorPredicate)({});
|
||||||
connectBlocks(genesis(), implicitConstructor);
|
addRule(implicitConstructor, implicitConstructor.name);
|
||||||
m_currentBlock = implicitConstructor;
|
m_currentBlock = implicitConstructor;
|
||||||
m_context.addAssertion(m_error.currentValue() == 0);
|
m_context.addAssertion(m_error.currentValue() == 0);
|
||||||
|
|
||||||
@ -156,7 +134,7 @@ bool CHC::visit(FunctionDefinition const& _function)
|
|||||||
{
|
{
|
||||||
if (!_function.isImplemented())
|
if (!_function.isImplemented())
|
||||||
{
|
{
|
||||||
connectBlocks(genesis(), summary(_function));
|
addRule(summary(_function), "summary_function_" + to_string(_function.id()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,7 +162,7 @@ bool CHC::visit(FunctionDefinition const& _function)
|
|||||||
if (_function.isConstructor())
|
if (_function.isConstructor())
|
||||||
connectBlocks(m_currentBlock, functionPred);
|
connectBlocks(m_currentBlock, functionPred);
|
||||||
else
|
else
|
||||||
connectBlocks(genesis(), functionPred);
|
addRule(functionPred, functionPred.name);
|
||||||
|
|
||||||
m_context.addAssertion(m_error.currentValue() == 0);
|
m_context.addAssertion(m_error.currentValue() == 0);
|
||||||
for (auto const* var: m_stateVariables)
|
for (auto const* var: m_stateVariables)
|
||||||
@ -676,6 +654,30 @@ void CHC::resetSourceAnalysis()
|
|||||||
m_interfaces.clear();
|
m_interfaces.clear();
|
||||||
m_nondetInterfaces.clear();
|
m_nondetInterfaces.clear();
|
||||||
Predicate::reset();
|
Predicate::reset();
|
||||||
|
m_blockCounter = 0;
|
||||||
|
|
||||||
|
bool usesZ3 = false;
|
||||||
|
#ifdef HAVE_Z3
|
||||||
|
usesZ3 = m_enabledSolvers.z3;
|
||||||
|
if (usesZ3)
|
||||||
|
{
|
||||||
|
/// z3::fixedpoint does not have a reset mechanism, so we need to create another.
|
||||||
|
m_interface.reset(new smtutil::Z3CHCInterface());
|
||||||
|
auto z3Interface = dynamic_cast<smtutil::Z3CHCInterface const*>(m_interface.get());
|
||||||
|
solAssert(z3Interface, "");
|
||||||
|
m_context.setSolver(z3Interface->z3Interface());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (!usesZ3)
|
||||||
|
{
|
||||||
|
auto smtlib2Interface = dynamic_cast<smtutil::CHCSmtLib2Interface*>(m_interface.get());
|
||||||
|
smtlib2Interface->reset();
|
||||||
|
solAssert(smtlib2Interface, "");
|
||||||
|
m_context.setSolver(smtlib2Interface->smtlib2Interface());
|
||||||
|
}
|
||||||
|
|
||||||
|
m_context.clear();
|
||||||
|
m_context.setAssertionAccumulation(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHC::resetContractAnalysis()
|
void CHC::resetContractAnalysis()
|
||||||
@ -861,27 +863,23 @@ void CHC::defineInterfacesAndSummaries(SourceUnit const& _source)
|
|||||||
{
|
{
|
||||||
for (auto const& node: _source.nodes())
|
for (auto const& node: _source.nodes())
|
||||||
if (auto const* contract = dynamic_cast<ContractDefinition const*>(node.get()))
|
if (auto const* contract = dynamic_cast<ContractDefinition const*>(node.get()))
|
||||||
|
{
|
||||||
|
string suffix = contract->name() + "_" + to_string(contract->id());
|
||||||
|
m_interfaces[contract] = createSymbolicBlock(interfaceSort(*contract), "interface_" + suffix);
|
||||||
|
m_nondetInterfaces[contract] = createSymbolicBlock(nondetInterfaceSort(*contract), "nondet_interface_" + suffix);
|
||||||
|
|
||||||
|
for (auto const* var: stateVariablesIncludingInheritedAndPrivate(*contract))
|
||||||
|
if (!m_context.knownVariable(*var))
|
||||||
|
createVariable(*var);
|
||||||
|
|
||||||
|
/// Base nondeterministic interface that allows
|
||||||
|
/// 0 steps to be taken, used as base for the inductive
|
||||||
|
/// rule for each function.
|
||||||
|
auto const& iface = *m_nondetInterfaces.at(contract);
|
||||||
|
auto state0 = stateVariablesAtIndex(0, *contract);
|
||||||
|
addRule(iface(state0 + state0), "base_nondet");
|
||||||
|
|
||||||
for (auto const* base: contract->annotation().linearizedBaseContracts)
|
for (auto const* base: contract->annotation().linearizedBaseContracts)
|
||||||
{
|
|
||||||
for (auto const* var: SMTEncoder::stateVariablesIncludingInheritedAndPrivate(*base))
|
|
||||||
if (!m_context.knownVariable(*var))
|
|
||||||
createVariable(*var);
|
|
||||||
|
|
||||||
if (!m_interfaces.count(base))
|
|
||||||
{
|
|
||||||
solAssert(!m_nondetInterfaces.count(base), "");
|
|
||||||
string suffix = base->name() + "_" + to_string(base->id());
|
|
||||||
m_interfaces.emplace(base, createSymbolicBlock(interfaceSort(*base), "interface_" + suffix, base));
|
|
||||||
m_nondetInterfaces.emplace(base, createSymbolicBlock(nondetInterfaceSort(*base), "nondet_interface_" + suffix, base));
|
|
||||||
|
|
||||||
/// Base nondeterministic interface that allows
|
|
||||||
/// 0 steps to be taken, used as base for the inductive
|
|
||||||
/// rule for each function.
|
|
||||||
auto const* iface = m_nondetInterfaces.at(base);
|
|
||||||
auto state0 = stateVariablesAtIndex(0, *base);
|
|
||||||
addRule((*iface)(state0 + state0), "base_nondet");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto const* function: base->definedFunctions())
|
for (auto const* function: base->definedFunctions())
|
||||||
{
|
{
|
||||||
for (auto var: function->parameters())
|
for (auto var: function->parameters())
|
||||||
@ -900,13 +898,11 @@ void CHC::defineInterfacesAndSummaries(SourceUnit const& _source)
|
|||||||
!base->isInterface()
|
!base->isInterface()
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
auto state1 = stateVariablesAtIndex(1, *base);
|
auto state1 = stateVariablesAtIndex(1, *contract);
|
||||||
auto state2 = stateVariablesAtIndex(2, *base);
|
auto state2 = stateVariablesAtIndex(2, *contract);
|
||||||
|
|
||||||
auto const* iface = m_nondetInterfaces.at(base);
|
auto nondetPre = iface(state0 + state1);
|
||||||
auto state0 = stateVariablesAtIndex(0, *base);
|
auto nondetPost = iface(state0 + state2);
|
||||||
auto nondetPre = (*iface)(state0 + state1);
|
|
||||||
auto nondetPost = (*iface)(state0 + state2);
|
|
||||||
|
|
||||||
vector<smtutil::Expression> args{m_error.currentValue()};
|
vector<smtutil::Expression> args{m_error.currentValue()};
|
||||||
args += state1 +
|
args += state1 +
|
||||||
@ -915,10 +911,10 @@ void CHC::defineInterfacesAndSummaries(SourceUnit const& _source)
|
|||||||
applyMap(function->parameters(), [this](auto _var) { return valueAtIndex(*_var, 1); }) +
|
applyMap(function->parameters(), [this](auto _var) { return valueAtIndex(*_var, 1); }) +
|
||||||
applyMap(function->returnParameters(), [this](auto _var) { return valueAtIndex(*_var, 1); });
|
applyMap(function->returnParameters(), [this](auto _var) { return valueAtIndex(*_var, 1); });
|
||||||
|
|
||||||
connectBlocks(nondetPre, nondetPost, (*m_summaries.at(base).at(function))(args));
|
connectBlocks(nondetPre, nondetPost, (*m_summaries.at(contract).at(function))(args));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
smtutil::Expression CHC::interface()
|
smtutil::Expression CHC::interface()
|
||||||
@ -1210,6 +1206,16 @@ void CHC::addVerificationTarget(
|
|||||||
smtutil::Expression _errorId
|
smtutil::Expression _errorId
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
solAssert(m_currentContract || m_currentFunction, "");
|
||||||
|
SourceUnit const* source = nullptr;
|
||||||
|
if (m_currentContract)
|
||||||
|
source = sourceUnitContaining(*m_currentContract);
|
||||||
|
else
|
||||||
|
source = sourceUnitContaining(*m_currentFunction);
|
||||||
|
solAssert(source, "");
|
||||||
|
if (!source->annotation().experimentalFeatures.count(ExperimentalFeature::SMTChecker))
|
||||||
|
return;
|
||||||
|
|
||||||
m_verificationTargets.emplace(_scope, CHCVerificationTarget{{_type, _from, _constraints}, _errorId});
|
m_verificationTargets.emplace(_scope, CHCVerificationTarget{{_type, _from, _constraints}, _errorId});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1251,7 +1257,7 @@ void CHC::checkVerificationTargets()
|
|||||||
if (target.type == VerificationTarget::Type::PopEmptyArray)
|
if (target.type == VerificationTarget::Type::PopEmptyArray)
|
||||||
{
|
{
|
||||||
solAssert(dynamic_cast<FunctionCall const*>(scope), "");
|
solAssert(dynamic_cast<FunctionCall const*>(scope), "");
|
||||||
satMsg = "Empty array \"pop\" detected here";
|
satMsg = "Empty array \"pop\" detected here.";
|
||||||
unknownMsg = "Empty array \"pop\" might happen here.";
|
unknownMsg = "Empty array \"pop\" might happen here.";
|
||||||
errorReporterId = 2529_error;
|
errorReporterId = 2529_error;
|
||||||
}
|
}
|
||||||
@ -1267,8 +1273,8 @@ void CHC::checkVerificationTargets()
|
|||||||
if (!intType)
|
if (!intType)
|
||||||
intType = TypeProvider::uint256();
|
intType = TypeProvider::uint256();
|
||||||
|
|
||||||
satMsgUnderflow = "Underflow (resulting value less than " + formatNumberReadable(intType->minValue()) + ") happens here";
|
satMsgUnderflow = "Underflow (resulting value less than " + formatNumberReadable(intType->minValue()) + ") happens here.";
|
||||||
satMsgOverflow = "Overflow (resulting value larger than " + formatNumberReadable(intType->maxValue()) + ") happens here";
|
satMsgOverflow = "Overflow (resulting value larger than " + formatNumberReadable(intType->maxValue()) + ") happens here.";
|
||||||
if (target.type == VerificationTarget::Type::Underflow)
|
if (target.type == VerificationTarget::Type::Underflow)
|
||||||
{
|
{
|
||||||
satMsg = satMsgUnderflow;
|
satMsg = satMsgUnderflow;
|
||||||
@ -1314,7 +1320,7 @@ void CHC::checkAssertTarget(ASTNode const* _scope, CHCVerificationTarget const&
|
|||||||
solAssert(it != m_errorIds.end(), "");
|
solAssert(it != m_errorIds.end(), "");
|
||||||
unsigned errorId = it->second;
|
unsigned errorId = it->second;
|
||||||
|
|
||||||
checkAndReportTarget(assertion, _target, errorId, 6328_error, "Assertion violation happens here");
|
checkAndReportTarget(assertion, _target, errorId, 6328_error, "Assertion violation happens here.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1345,13 +1351,13 @@ void CHC::checkAndReportTarget(
|
|||||||
_errorReporterId,
|
_errorReporterId,
|
||||||
_scope->location(),
|
_scope->location(),
|
||||||
_satMsg,
|
_satMsg,
|
||||||
SecondarySourceLocation().append(" for:\n" + *cex, SourceLocation{})
|
SecondarySourceLocation().append("\nCounterexample:\n" + *cex, SourceLocation{})
|
||||||
);
|
);
|
||||||
else
|
else
|
||||||
m_outerErrorReporter.warning(
|
m_outerErrorReporter.warning(
|
||||||
_errorReporterId,
|
_errorReporterId,
|
||||||
_scope->location(),
|
_scope->location(),
|
||||||
_satMsg + "."
|
_satMsg
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if (!_unknownMsg.empty())
|
else if (!_unknownMsg.empty())
|
||||||
@ -1459,7 +1465,11 @@ optional<string> CHC::generateCounterexample(CHCSolverInterface::CexGraph const&
|
|||||||
/// Recurse on the next interface node which represents the previous transaction
|
/// Recurse on the next interface node which represents the previous transaction
|
||||||
/// or stop.
|
/// or stop.
|
||||||
if (interfaceId)
|
if (interfaceId)
|
||||||
|
{
|
||||||
|
Predicate const* interfacePredicate = Predicate::predicate(_graph.nodes.at(*interfaceId).first);
|
||||||
|
solAssert(interfacePredicate && interfacePredicate->isInterface(), "");
|
||||||
node = *interfaceId;
|
node = *interfaceId;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -141,8 +141,6 @@ private:
|
|||||||
/// in a given _source.
|
/// in a given _source.
|
||||||
void defineInterfacesAndSummaries(SourceUnit const& _source);
|
void defineInterfacesAndSummaries(SourceUnit const& _source);
|
||||||
|
|
||||||
/// Genesis predicate.
|
|
||||||
smtutil::Expression genesis() { return (*m_genesisPredicate)({}); }
|
|
||||||
/// Interface predicate over current variables.
|
/// Interface predicate over current variables.
|
||||||
smtutil::Expression interface();
|
smtutil::Expression interface();
|
||||||
smtutil::Expression interface(ContractDefinition const& _contract);
|
smtutil::Expression interface(ContractDefinition const& _contract);
|
||||||
@ -259,9 +257,6 @@ private:
|
|||||||
|
|
||||||
/// Predicates.
|
/// Predicates.
|
||||||
//@{
|
//@{
|
||||||
/// Genesis predicate.
|
|
||||||
Predicate const* m_genesisPredicate = nullptr;
|
|
||||||
|
|
||||||
/// Implicit constructor predicate.
|
/// Implicit constructor predicate.
|
||||||
/// Explicit constructors are handled as functions.
|
/// Explicit constructors are handled as functions.
|
||||||
Predicate const* m_implicitConstructorPredicate = nullptr;
|
Predicate const* m_implicitConstructorPredicate = nullptr;
|
||||||
@ -293,9 +288,6 @@ private:
|
|||||||
"error",
|
"error",
|
||||||
m_context
|
m_context
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Maps predicate names to the ASTNodes they came from.
|
|
||||||
std::map<std::string, ASTNode const*> m_symbolFunction;
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
/// Variables.
|
/// Variables.
|
||||||
|
@ -133,10 +133,7 @@ bool SMTEncoder::visit(FunctionDefinition const& _function)
|
|||||||
if (_function.isConstructor())
|
if (_function.isConstructor())
|
||||||
inlineConstructorHierarchy(dynamic_cast<ContractDefinition const&>(*_function.scope()));
|
inlineConstructorHierarchy(dynamic_cast<ContractDefinition const&>(*_function.scope()));
|
||||||
|
|
||||||
// Base constructors' parameters should be set by explicit calls,
|
initializeLocalVariables(_function);
|
||||||
// but the most derived one needs to be initialized.
|
|
||||||
if (_function.scope() == m_currentContract)
|
|
||||||
initializeLocalVariables(_function);
|
|
||||||
|
|
||||||
_function.parameterList().accept(*this);
|
_function.parameterList().accept(*this);
|
||||||
if (_function.returnParameterList())
|
if (_function.returnParameterList())
|
||||||
@ -571,7 +568,7 @@ void SMTEncoder::endVisit(BinaryOperation const& _op)
|
|||||||
arithmeticOperation(_op);
|
arithmeticOperation(_op);
|
||||||
else if (TokenTraits::isCompareOp(_op.getOperator()))
|
else if (TokenTraits::isCompareOp(_op.getOperator()))
|
||||||
compareOperation(_op);
|
compareOperation(_op);
|
||||||
else if (TokenTraits::isBitOp(_op.getOperator()))
|
else if (TokenTraits::isBitOp(_op.getOperator()) || TokenTraits::isShiftOp(_op.getOperator()))
|
||||||
bitwiseOperation(_op);
|
bitwiseOperation(_op);
|
||||||
else
|
else
|
||||||
m_errorReporter.warning(
|
m_errorReporter.warning(
|
||||||
@ -881,16 +878,31 @@ bool SMTEncoder::visit(MemberAccess const& _memberAccess)
|
|||||||
auto identifier = dynamic_cast<Identifier const*>(&_memberAccess.expression());
|
auto identifier = dynamic_cast<Identifier const*>(&_memberAccess.expression());
|
||||||
if (exprType->category() == Type::Category::Magic)
|
if (exprType->category() == Type::Category::Magic)
|
||||||
{
|
{
|
||||||
string accessedName;
|
|
||||||
if (identifier)
|
if (identifier)
|
||||||
accessedName = identifier->name();
|
defineGlobalVariable(identifier->name() + "." + _memberAccess.memberName(), _memberAccess);
|
||||||
|
else if (auto magicType = dynamic_cast<MagicType const*>(exprType); magicType->kind() == MagicType::Kind::MetaType)
|
||||||
|
{
|
||||||
|
auto const& memberName = _memberAccess.memberName();
|
||||||
|
if (memberName == "min" || memberName == "max")
|
||||||
|
{
|
||||||
|
IntegerType const& integerType = dynamic_cast<IntegerType const&>(*magicType->typeArgument());
|
||||||
|
defineExpr(_memberAccess, memberName == "min" ? integerType.minValue() : integerType.maxValue());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// NOTE: supporting name, creationCode, runtimeCode would be easy enough, but the bytes/string they return are not
|
||||||
|
// at all useable in the SMT checker currently
|
||||||
|
m_errorReporter.warning(
|
||||||
|
7507_error,
|
||||||
|
_memberAccess.location(),
|
||||||
|
"Assertion checker does not yet support this expression."
|
||||||
|
);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
m_errorReporter.warning(
|
m_errorReporter.warning(
|
||||||
9551_error,
|
9551_error,
|
||||||
_memberAccess.location(),
|
_memberAccess.location(),
|
||||||
"Assertion checker does not yet support this expression."
|
"Assertion checker does not yet support this expression."
|
||||||
);
|
);
|
||||||
defineGlobalVariable(accessedName + "." + _memberAccess.memberName(), _memberAccess);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (smt::isNonRecursiveStruct(*exprType))
|
else if (smt::isNonRecursiveStruct(*exprType))
|
||||||
@ -1422,7 +1434,8 @@ void SMTEncoder::booleanOperation(BinaryOperation const& _op)
|
|||||||
|
|
||||||
void SMTEncoder::bitwiseOperation(BinaryOperation const& _op)
|
void SMTEncoder::bitwiseOperation(BinaryOperation const& _op)
|
||||||
{
|
{
|
||||||
solAssert(TokenTraits::isBitOp(_op.getOperator()), "");
|
auto op = _op.getOperator();
|
||||||
|
solAssert(TokenTraits::isBitOp(op) || TokenTraits::isShiftOp(op), "");
|
||||||
auto commonType = _op.annotation().commonType;
|
auto commonType = _op.annotation().commonType;
|
||||||
solAssert(commonType, "");
|
solAssert(commonType, "");
|
||||||
|
|
||||||
@ -1432,16 +1445,33 @@ void SMTEncoder::bitwiseOperation(BinaryOperation const& _op)
|
|||||||
auto bvRight = smtutil::Expression::int2bv(expr(_op.rightExpression(), commonType), bvSize);
|
auto bvRight = smtutil::Expression::int2bv(expr(_op.rightExpression(), commonType), bvSize);
|
||||||
|
|
||||||
optional<smtutil::Expression> result;
|
optional<smtutil::Expression> result;
|
||||||
if (_op.getOperator() == Token::BitAnd)
|
switch (op)
|
||||||
|
{
|
||||||
|
case Token::BitAnd:
|
||||||
result = bvLeft & bvRight;
|
result = bvLeft & bvRight;
|
||||||
else if (_op.getOperator() == Token::BitOr)
|
break;
|
||||||
|
case Token::BitOr:
|
||||||
result = bvLeft | bvRight;
|
result = bvLeft | bvRight;
|
||||||
else if (_op.getOperator() == Token::BitXor)
|
break;
|
||||||
|
case Token::BitXor:
|
||||||
result = bvLeft ^ bvRight;
|
result = bvLeft ^ bvRight;
|
||||||
|
break;
|
||||||
|
case Token::SHL:
|
||||||
|
result = bvLeft << bvRight;
|
||||||
|
break;
|
||||||
|
case Token::SHR:
|
||||||
|
solAssert(false, "");
|
||||||
|
case Token::SAR:
|
||||||
|
result = isSigned ?
|
||||||
|
smtutil::Expression::ashr(bvLeft, bvRight) :
|
||||||
|
bvLeft >> bvRight;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
solAssert(false, "");
|
||||||
|
}
|
||||||
|
|
||||||
solAssert(result, "");
|
solAssert(result, "");
|
||||||
if (result)
|
defineExpr(_op, smtutil::Expression::bv2int(*result, isSigned));
|
||||||
defineExpr(_op, smtutil::Expression::bv2int(*result, isSigned));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMTEncoder::bitwiseNotOperation(UnaryOperation const& _op)
|
void SMTEncoder::bitwiseNotOperation(UnaryOperation const& _op)
|
||||||
@ -2022,6 +2052,14 @@ vector<VariableDeclaration const*> SMTEncoder::stateVariablesIncludingInheritedA
|
|||||||
return stateVariablesIncludingInheritedAndPrivate(dynamic_cast<ContractDefinition const&>(*_function.scope()));
|
return stateVariablesIncludingInheritedAndPrivate(dynamic_cast<ContractDefinition const&>(*_function.scope()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SourceUnit const* SMTEncoder::sourceUnitContaining(Scopable const& _scopable)
|
||||||
|
{
|
||||||
|
for (auto const* s = &_scopable; s; s = dynamic_cast<Scopable const*>(s->scope()))
|
||||||
|
if (auto const* source = dynamic_cast<SourceUnit const*>(s->scope()))
|
||||||
|
return source;
|
||||||
|
solAssert(false, "");
|
||||||
|
}
|
||||||
|
|
||||||
void SMTEncoder::createReturnedExpressions(FunctionCall const& _funCall)
|
void SMTEncoder::createReturnedExpressions(FunctionCall const& _funCall)
|
||||||
{
|
{
|
||||||
FunctionDefinition const* funDef = functionCallToDefinition(_funCall);
|
FunctionDefinition const* funDef = functionCallToDefinition(_funCall);
|
||||||
|
@ -65,6 +65,9 @@ public:
|
|||||||
static std::vector<VariableDeclaration const*> stateVariablesIncludingInheritedAndPrivate(ContractDefinition const& _contract);
|
static std::vector<VariableDeclaration const*> stateVariablesIncludingInheritedAndPrivate(ContractDefinition const& _contract);
|
||||||
static std::vector<VariableDeclaration const*> stateVariablesIncludingInheritedAndPrivate(FunctionDefinition const& _function);
|
static std::vector<VariableDeclaration const*> stateVariablesIncludingInheritedAndPrivate(FunctionDefinition const& _function);
|
||||||
|
|
||||||
|
/// @returns the SourceUnit that contains _scopable.
|
||||||
|
static SourceUnit const* sourceUnitContaining(Scopable const& _scopable);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// TODO: Check that we do not have concurrent reads and writes to a variable,
|
// TODO: Check that we do not have concurrent reads and writes to a variable,
|
||||||
// because the order of expression evaluation is undefined
|
// because the order of expression evaluation is undefined
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include <libsolidity/analysis/PostTypeChecker.h>
|
#include <libsolidity/analysis/PostTypeChecker.h>
|
||||||
#include <libsolidity/analysis/StaticAnalyzer.h>
|
#include <libsolidity/analysis/StaticAnalyzer.h>
|
||||||
#include <libsolidity/analysis/SyntaxChecker.h>
|
#include <libsolidity/analysis/SyntaxChecker.h>
|
||||||
|
#include <libsolidity/analysis/Scoper.h>
|
||||||
#include <libsolidity/analysis/TypeChecker.h>
|
#include <libsolidity/analysis/TypeChecker.h>
|
||||||
#include <libsolidity/analysis/ViewPureChecker.h>
|
#include <libsolidity/analysis/ViewPureChecker.h>
|
||||||
#include <libsolidity/analysis/ImmutableValidator.h>
|
#include <libsolidity/analysis/ImmutableValidator.h>
|
||||||
@ -297,6 +298,10 @@ bool CompilerStack::analyze()
|
|||||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must call analyze only after parsing was performed."));
|
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must call analyze only after parsing was performed."));
|
||||||
resolveImports();
|
resolveImports();
|
||||||
|
|
||||||
|
for (Source const* source: m_sourceOrder)
|
||||||
|
if (source->ast)
|
||||||
|
Scoper::assignScopes(*source->ast);
|
||||||
|
|
||||||
bool noErrors = true;
|
bool noErrors = true;
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -32,7 +32,7 @@ namespace solidity::frontend
|
|||||||
struct OptimiserSettings
|
struct OptimiserSettings
|
||||||
{
|
{
|
||||||
static char constexpr DefaultYulOptimiserSteps[] =
|
static char constexpr DefaultYulOptimiserSteps[] =
|
||||||
"dhfoDgvulfnTUtnIf" // None of these can make stack problems worse
|
"NdhfoDgvulfnTUtnIf" // None of these can make stack problems worse
|
||||||
"["
|
"["
|
||||||
"xarrscLM" // Turn into SSA and simplify
|
"xarrscLM" // Turn into SSA and simplify
|
||||||
"cCTUtTOntnfDIul" // Perform structural simplification
|
"cCTUtTOntnfDIul" // Perform structural simplification
|
||||||
@ -47,7 +47,7 @@ struct OptimiserSettings
|
|||||||
"gvif" // Run full inliner
|
"gvif" // Run full inliner
|
||||||
"CTUcarrLsTOtfDncarrIulc" // SSA plus simplify
|
"CTUcarrLsTOtfDncarrIulc" // SSA plus simplify
|
||||||
"]"
|
"]"
|
||||||
"jmuljuljul VcTOcul jmul"; // Make source short and pretty
|
"jmuljuljul VcTOcul jmulN"; // Make source short and pretty
|
||||||
|
|
||||||
/// No optimisations at all - not recommended.
|
/// No optimisations at all - not recommended.
|
||||||
static OptimiserSettings none()
|
static OptimiserSettings none()
|
||||||
|
@ -127,6 +127,8 @@ add_library(yul
|
|||||||
optimiser/NameDispenser.h
|
optimiser/NameDispenser.h
|
||||||
optimiser/NameDisplacer.cpp
|
optimiser/NameDisplacer.cpp
|
||||||
optimiser/NameDisplacer.h
|
optimiser/NameDisplacer.h
|
||||||
|
optimiser/NameSimplifier.cpp
|
||||||
|
optimiser/NameSimplifier.h
|
||||||
optimiser/OptimiserStep.h
|
optimiser/OptimiserStep.h
|
||||||
optimiser/OptimizerUtilities.cpp
|
optimiser/OptimizerUtilities.cpp
|
||||||
optimiser/OptimizerUtilities.h
|
optimiser/OptimizerUtilities.h
|
||||||
|
@ -22,12 +22,9 @@
|
|||||||
#include <libyul/optimiser/ExpressionSimplifier.h>
|
#include <libyul/optimiser/ExpressionSimplifier.h>
|
||||||
|
|
||||||
#include <libyul/optimiser/SimplificationRules.h>
|
#include <libyul/optimiser/SimplificationRules.h>
|
||||||
#include <libyul/optimiser/Semantics.h>
|
|
||||||
#include <libyul/optimiser/OptimiserStep.h>
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
#include <libyul/AsmData.h>
|
#include <libyul/AsmData.h>
|
||||||
|
|
||||||
#include <libsolutil/CommonData.h>
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace solidity;
|
using namespace solidity;
|
||||||
using namespace solidity::yul;
|
using namespace solidity::yul;
|
||||||
@ -40,17 +37,7 @@ void ExpressionSimplifier::run(OptimiserStepContext& _context, Block& _ast)
|
|||||||
void ExpressionSimplifier::visit(Expression& _expression)
|
void ExpressionSimplifier::visit(Expression& _expression)
|
||||||
{
|
{
|
||||||
ASTModifier::visit(_expression);
|
ASTModifier::visit(_expression);
|
||||||
while (auto match = SimplificationRules::findFirstMatch(_expression, m_dialect, m_value))
|
|
||||||
{
|
|
||||||
// Do not apply the rule if it removes non-constant parts of the expression.
|
|
||||||
// TODO: The check could actually be less strict than "movable".
|
|
||||||
// We only require "Does not cause side-effects".
|
|
||||||
// Note: References to variables that are only assigned once are always movable,
|
|
||||||
// so if the value of the variable is not movable, the expression that references
|
|
||||||
// the variable still is.
|
|
||||||
|
|
||||||
if (match->removesNonConstants && !SideEffectsCollector(m_dialect, _expression).movable())
|
while (auto const* match = SimplificationRules::findFirstMatch(_expression, m_dialect, m_value))
|
||||||
return;
|
|
||||||
_expression = match->action().toExpression(locationOf(_expression));
|
_expression = match->action().toExpression(locationOf(_expression));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,8 @@ struct OptimiserStepContext;
|
|||||||
/**
|
/**
|
||||||
* Applies simplification rules to all expressions.
|
* Applies simplification rules to all expressions.
|
||||||
* The component will work best if the code is in SSA form, but
|
* The component will work best if the code is in SSA form, but
|
||||||
* this is not required for correctness.
|
* this is not required for correctness. Using CommonSubexpressionEliminator
|
||||||
|
* also helps this component track equivalent sub-expressions.
|
||||||
*
|
*
|
||||||
* It tracks the current values of variables using the DataFlowAnalyzer
|
* It tracks the current values of variables using the DataFlowAnalyzer
|
||||||
* and takes them into account for replacements.
|
* and takes them into account for replacements.
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <libyul/optimiser/Metrics.h>
|
#include <libyul/optimiser/Metrics.h>
|
||||||
#include <libyul/optimiser/SSAValueTracker.h>
|
#include <libyul/optimiser/SSAValueTracker.h>
|
||||||
#include <libyul/optimiser/Semantics.h>
|
#include <libyul/optimiser/Semantics.h>
|
||||||
|
#include <libyul/optimiser/CallGraphGenerator.h>
|
||||||
#include <libyul/Exceptions.h>
|
#include <libyul/Exceptions.h>
|
||||||
#include <libyul/AsmData.h>
|
#include <libyul/AsmData.h>
|
||||||
#include <libyul/Dialect.h>
|
#include <libyul/Dialect.h>
|
||||||
@ -41,7 +42,9 @@ using namespace solidity::yul;
|
|||||||
|
|
||||||
void FullInliner::run(OptimiserStepContext& _context, Block& _ast)
|
void FullInliner::run(OptimiserStepContext& _context, Block& _ast)
|
||||||
{
|
{
|
||||||
FullInliner{_ast, _context.dispenser, _context.dialect}.run();
|
FullInliner inliner{_ast, _context.dispenser, _context.dialect};
|
||||||
|
inliner.run(Pass::InlineTiny);
|
||||||
|
inliner.run(Pass::InlineRest);
|
||||||
}
|
}
|
||||||
|
|
||||||
FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser, Dialect const& _dialect):
|
FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser, Dialect const& _dialect):
|
||||||
@ -72,14 +75,9 @@ FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser, Dialect const&
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FullInliner::run()
|
void FullInliner::run(Pass _pass)
|
||||||
{
|
{
|
||||||
for (auto& statement: m_ast.statements)
|
m_pass = _pass;
|
||||||
if (holds_alternative<Block>(statement))
|
|
||||||
handleBlock({}, std::get<Block>(statement));
|
|
||||||
|
|
||||||
// TODO it might be good to determine a visiting order:
|
|
||||||
// first handle functions that are called from many places.
|
|
||||||
|
|
||||||
// Note that the order of inlining can result in very different code.
|
// Note that the order of inlining can result in very different code.
|
||||||
// Since AST IDs and thus function names depend on whether or not a contract
|
// Since AST IDs and thus function names depend on whether or not a contract
|
||||||
@ -87,14 +85,76 @@ void FullInliner::run()
|
|||||||
// should have as little an impact as possible. This is the case
|
// should have as little an impact as possible. This is the case
|
||||||
// if we handle inlining in source (and thus, for the IR generator,
|
// if we handle inlining in source (and thus, for the IR generator,
|
||||||
// function name) order.
|
// function name) order.
|
||||||
|
// We use stable_sort below to keep the inlining order of two functions
|
||||||
|
// with the same depth.
|
||||||
|
map<YulString, size_t> depths = callDepths();
|
||||||
|
vector<FunctionDefinition*> functions;
|
||||||
for (auto& statement: m_ast.statements)
|
for (auto& statement: m_ast.statements)
|
||||||
|
if (holds_alternative<FunctionDefinition>(statement))
|
||||||
|
functions.emplace_back(&std::get<FunctionDefinition>(statement));
|
||||||
|
std::stable_sort(functions.begin(), functions.end(), [depths](
|
||||||
|
FunctionDefinition const* _a,
|
||||||
|
FunctionDefinition const* _b
|
||||||
|
) {
|
||||||
|
return depths.at(_a->name) < depths.at(_b->name);
|
||||||
|
});
|
||||||
|
for (FunctionDefinition* fun: functions)
|
||||||
{
|
{
|
||||||
if (!holds_alternative<FunctionDefinition>(statement))
|
handleBlock(fun->name, fun->body);
|
||||||
continue;
|
updateCodeSize(*fun);
|
||||||
FunctionDefinition& fun = std::get<FunctionDefinition>(statement);
|
|
||||||
handleBlock(fun.name, fun.body);
|
|
||||||
updateCodeSize(fun);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto& statement: m_ast.statements)
|
||||||
|
if (holds_alternative<Block>(statement))
|
||||||
|
handleBlock({}, std::get<Block>(statement));
|
||||||
|
}
|
||||||
|
|
||||||
|
map<YulString, size_t> FullInliner::callDepths() const
|
||||||
|
{
|
||||||
|
CallGraph cg = CallGraphGenerator::callGraph(m_ast);
|
||||||
|
cg.functionCalls.erase(""_yulstring);
|
||||||
|
|
||||||
|
// Remove calls to builtin functions.
|
||||||
|
for (auto& call: cg.functionCalls)
|
||||||
|
for (auto it = call.second.begin(); it != call.second.end();)
|
||||||
|
if (m_dialect.builtin(*it))
|
||||||
|
it = call.second.erase(it);
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
|
||||||
|
map<YulString, size_t> depths;
|
||||||
|
size_t currentDepth = 0;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
vector<YulString> removed;
|
||||||
|
for (auto it = cg.functionCalls.begin(); it != cg.functionCalls.end();)
|
||||||
|
{
|
||||||
|
auto const& [fun, callees] = *it;
|
||||||
|
if (callees.empty())
|
||||||
|
{
|
||||||
|
removed.emplace_back(fun);
|
||||||
|
depths[fun] = currentDepth;
|
||||||
|
it = cg.functionCalls.erase(it);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& call: cg.functionCalls)
|
||||||
|
call.second -= removed;
|
||||||
|
|
||||||
|
currentDepth++;
|
||||||
|
|
||||||
|
if (removed.empty())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only recursive functions left here.
|
||||||
|
for (auto const& fun: cg.functionCalls)
|
||||||
|
depths[fun.first] = currentDepth;
|
||||||
|
|
||||||
|
return depths;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FullInliner::shallInline(FunctionCall const& _funCall, YulString _callSite)
|
bool FullInliner::shallInline(FunctionCall const& _funCall, YulString _callSite)
|
||||||
@ -115,6 +175,10 @@ bool FullInliner::shallInline(FunctionCall const& _funCall, YulString _callSite)
|
|||||||
if (size <= 1)
|
if (size <= 1)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
// In the first pass, only inline tiny functions.
|
||||||
|
if (m_pass == Pass::InlineTiny)
|
||||||
|
return false;
|
||||||
|
|
||||||
// Do not inline into already big functions.
|
// Do not inline into already big functions.
|
||||||
if (m_functionSizes.at(_callSite) > 45)
|
if (m_functionSizes.at(_callSite) > 45)
|
||||||
return false;
|
return false;
|
||||||
|
@ -91,13 +91,20 @@ public:
|
|||||||
void tentativelyUpdateCodeSize(YulString _function, YulString _callSite);
|
void tentativelyUpdateCodeSize(YulString _function, YulString _callSite);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
enum Pass { InlineTiny, InlineRest };
|
||||||
|
|
||||||
FullInliner(Block& _ast, NameDispenser& _dispenser, Dialect const& _dialect);
|
FullInliner(Block& _ast, NameDispenser& _dispenser, Dialect const& _dialect);
|
||||||
void run();
|
void run(Pass _pass);
|
||||||
|
|
||||||
|
/// @returns a map containing the maximum depths of a call chain starting at each
|
||||||
|
/// function. For recursive functions, the value is one larger than for all others.
|
||||||
|
std::map<YulString, size_t> callDepths() const;
|
||||||
|
|
||||||
void updateCodeSize(FunctionDefinition const& _fun);
|
void updateCodeSize(FunctionDefinition const& _fun);
|
||||||
void handleBlock(YulString _currentFunctionName, Block& _block);
|
void handleBlock(YulString _currentFunctionName, Block& _block);
|
||||||
bool recursive(FunctionDefinition const& _fun) const;
|
bool recursive(FunctionDefinition const& _fun) const;
|
||||||
|
|
||||||
|
Pass m_pass;
|
||||||
/// The AST to be modified. The root block itself will not be modified, because
|
/// The AST to be modified. The root block itself will not be modified, because
|
||||||
/// we store pointers to functions.
|
/// we store pointers to functions.
|
||||||
Block& m_ast;
|
Block& m_ast;
|
||||||
|
122
libyul/optimiser/NameSimplifier.cpp
Normal file
122
libyul/optimiser/NameSimplifier.cpp
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libyul/optimiser/NameSimplifier.h>
|
||||||
|
#include <libyul/optimiser/NameCollector.h>
|
||||||
|
#include <libyul/AsmData.h>
|
||||||
|
#include <libyul/Dialect.h>
|
||||||
|
#include <libyul/optimiser/OptimizerUtilities.h>
|
||||||
|
|
||||||
|
#include <libsolutil/CommonData.h>
|
||||||
|
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
using namespace solidity::yul;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
NameSimplifier::NameSimplifier(
|
||||||
|
OptimiserStepContext& _context,
|
||||||
|
Block const& _ast
|
||||||
|
):
|
||||||
|
m_context(_context),
|
||||||
|
m_usedNames(_context.reservedIdentifiers)
|
||||||
|
{
|
||||||
|
for (YulString name: m_usedNames)
|
||||||
|
m_translations[name] = name;
|
||||||
|
|
||||||
|
set<YulString> allNames = NameCollector(_ast).names();
|
||||||
|
m_usedNames += allNames;
|
||||||
|
for (YulString name: allNames)
|
||||||
|
findSimplification(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NameSimplifier::operator()(FunctionDefinition& _funDef)
|
||||||
|
{
|
||||||
|
translate(_funDef.name);
|
||||||
|
renameVariables(_funDef.parameters);
|
||||||
|
renameVariables(_funDef.returnVariables);
|
||||||
|
ASTModifier::operator()(_funDef);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NameSimplifier::operator()(VariableDeclaration& _varDecl)
|
||||||
|
{
|
||||||
|
renameVariables(_varDecl.variables);
|
||||||
|
ASTModifier::operator()(_varDecl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NameSimplifier::renameVariables(vector<TypedName>& _variables)
|
||||||
|
{
|
||||||
|
for (TypedName& typedName: _variables)
|
||||||
|
translate(typedName.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NameSimplifier::operator()(Identifier& _identifier)
|
||||||
|
{
|
||||||
|
translate(_identifier.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NameSimplifier::operator()(FunctionCall& _funCall)
|
||||||
|
{
|
||||||
|
// The visitor on its own does not visit the function name.
|
||||||
|
if (!m_context.dialect.builtin(_funCall.functionName.name))
|
||||||
|
(*this)(_funCall.functionName);
|
||||||
|
ASTModifier::operator()(_funCall);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NameSimplifier::findSimplification(YulString _name)
|
||||||
|
{
|
||||||
|
if (m_translations.count(_name))
|
||||||
|
return;
|
||||||
|
|
||||||
|
string name = _name.str();
|
||||||
|
|
||||||
|
static auto replacements = vector<pair<regex, string>>{
|
||||||
|
{regex("_\\$\\d+"), ""}, // removes AST IDs
|
||||||
|
{regex("(abi_..code.*)_to_.*"), "$1"}, // removes _to... for abi functions
|
||||||
|
{regex("(stringliteral_[0-9a-f][0-9a-f][0-9a-f][0-9a-f])[0-9a-f]*"), "$1"}, // shorten string literal
|
||||||
|
{regex("tuple_t_"), ""},
|
||||||
|
{regex("_memory_ptr"), ""},
|
||||||
|
{regex("_calldata_ptr"), "_calldata"},
|
||||||
|
{regex("_fromStack"), ""},
|
||||||
|
{regex("_storage_storage"), "_storage"},
|
||||||
|
{regex("_memory_memory"), "_memory"},
|
||||||
|
{regex("t_contract\\$_([^_]*)_"), "$1_"},
|
||||||
|
{regex("index_access_t_array"), "index_access"},
|
||||||
|
{regex("[0-9]*_$"), ""}
|
||||||
|
};
|
||||||
|
for (auto const& [pattern, substitute]: replacements)
|
||||||
|
{
|
||||||
|
string candidate = regex_replace(name, pattern, substitute);
|
||||||
|
if (
|
||||||
|
!isRestrictedIdentifier(m_context.dialect, YulString(candidate)) &&
|
||||||
|
!m_usedNames.count(YulString(candidate))
|
||||||
|
)
|
||||||
|
name = candidate;
|
||||||
|
}
|
||||||
|
if (name != _name.str())
|
||||||
|
{
|
||||||
|
m_usedNames.insert(YulString(name));
|
||||||
|
m_translations[_name] = YulString(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NameSimplifier::translate(YulString& _name)
|
||||||
|
{
|
||||||
|
auto it = m_translations.find(_name);
|
||||||
|
if (it != m_translations.end())
|
||||||
|
_name = it->second;
|
||||||
|
}
|
76
libyul/optimiser/NameSimplifier.h
Normal file
76
libyul/optimiser/NameSimplifier.h
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
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 <libyul/AsmDataForward.h>
|
||||||
|
#include <libyul/optimiser/ASTWalker.h>
|
||||||
|
#include <libyul/YulString.h>
|
||||||
|
#include <libyul/optimiser/OptimiserStep.h>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace solidity::yul
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Dialect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pass to "simplify" all identifier names.
|
||||||
|
*
|
||||||
|
* The purpose of this is to make generated code more readable, but also
|
||||||
|
* to remove AST identifiers that could lead to a different sorting order
|
||||||
|
* and thus influence e.g. the order of function inlining.
|
||||||
|
*
|
||||||
|
* Prerequisites: Disambiguator, FunctionHoister, FunctionGrouper
|
||||||
|
*/
|
||||||
|
class NameSimplifier: public ASTModifier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr char const* name{"NameSimplifier"};
|
||||||
|
static void run(OptimiserStepContext& _context, Block& _ast)
|
||||||
|
{
|
||||||
|
NameSimplifier{_context, _ast}(_ast);
|
||||||
|
}
|
||||||
|
|
||||||
|
using ASTModifier::operator();
|
||||||
|
void operator()(VariableDeclaration& _varDecl) override;
|
||||||
|
void operator()(Identifier& _identifier) override;
|
||||||
|
void operator()(FunctionCall& _funCall) override;
|
||||||
|
void operator()(FunctionDefinition& _funDef) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
NameSimplifier(
|
||||||
|
OptimiserStepContext& _context,
|
||||||
|
Block const& _ast
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Tries to rename a list of variables.
|
||||||
|
void renameVariables(std::vector<TypedName>& _variables);
|
||||||
|
|
||||||
|
void findSimplification(YulString _name);
|
||||||
|
void translate(YulString& _name);
|
||||||
|
|
||||||
|
OptimiserStepContext& m_context;
|
||||||
|
std::set<YulString> m_usedNames;
|
||||||
|
std::map<YulString, YulString> m_translations;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -171,12 +171,22 @@ bool Pattern::matches(
|
|||||||
return false;
|
return false;
|
||||||
assertThrow(m_arguments.size() == instrAndArgs->second->size(), OptimizerException, "");
|
assertThrow(m_arguments.size() == instrAndArgs->second->size(), OptimizerException, "");
|
||||||
for (size_t i = 0; i < m_arguments.size(); ++i)
|
for (size_t i = 0; i < m_arguments.size(); ++i)
|
||||||
if (!m_arguments[i].matches(instrAndArgs->second->at(i), _dialect, _ssaValues))
|
{
|
||||||
|
Expression const& arg = instrAndArgs->second->at(i);
|
||||||
|
// If this is a direct function call instead of a variable or literal,
|
||||||
|
// we reject the match because side-effects could prevent us from
|
||||||
|
// arbitrarily modifying the code.
|
||||||
|
if (
|
||||||
|
holds_alternative<FunctionCall>(arg) ||
|
||||||
|
!m_arguments[i].matches(arg, _dialect, _ssaValues)
|
||||||
|
)
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assertThrow(m_arguments.empty(), OptimizerException, "\"Any\" should not have arguments.");
|
assertThrow(m_arguments.empty(), OptimizerException, "\"Any\" should not have arguments.");
|
||||||
|
assertThrow(!holds_alternative<FunctionCall>(*expr), OptimizerException, "\"Any\" at top-level.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_matchGroup)
|
if (m_matchGroup)
|
||||||
@ -197,9 +207,14 @@ bool Pattern::matches(
|
|||||||
assertThrow(m_kind == PatternKind::Any, OptimizerException, "Match group repetition for non-any.");
|
assertThrow(m_kind == PatternKind::Any, OptimizerException, "Match group repetition for non-any.");
|
||||||
Expression const* firstMatch = (*m_matchGroups)[m_matchGroup];
|
Expression const* firstMatch = (*m_matchGroups)[m_matchGroup];
|
||||||
assertThrow(firstMatch, OptimizerException, "Match set but to null.");
|
assertThrow(firstMatch, OptimizerException, "Match set but to null.");
|
||||||
return
|
assertThrow(
|
||||||
SyntacticallyEqual{}(*firstMatch, _expr) &&
|
!holds_alternative<FunctionCall>(_expr) &&
|
||||||
SideEffectsCollector(_dialect, _expr).movable();
|
!holds_alternative<FunctionCall>(*firstMatch),
|
||||||
|
OptimizerException,
|
||||||
|
"Group matches have to be literals or variables."
|
||||||
|
);
|
||||||
|
|
||||||
|
return SyntacticallyEqual{}(*firstMatch, _expr);
|
||||||
}
|
}
|
||||||
else if (m_kind == PatternKind::Any)
|
else if (m_kind == PatternKind::Any)
|
||||||
(*m_matchGroups)[m_matchGroup] = &_expr;
|
(*m_matchGroups)[m_matchGroup] = &_expr;
|
||||||
|
@ -57,6 +57,7 @@
|
|||||||
#include <libyul/optimiser/LoadResolver.h>
|
#include <libyul/optimiser/LoadResolver.h>
|
||||||
#include <libyul/optimiser/LoopInvariantCodeMotion.h>
|
#include <libyul/optimiser/LoopInvariantCodeMotion.h>
|
||||||
#include <libyul/optimiser/Metrics.h>
|
#include <libyul/optimiser/Metrics.h>
|
||||||
|
#include <libyul/optimiser/NameSimplifier.h>
|
||||||
#include <libyul/backends/evm/ConstantOptimiser.h>
|
#include <libyul/backends/evm/ConstantOptimiser.h>
|
||||||
#include <libyul/AsmAnalysis.h>
|
#include <libyul/AsmAnalysis.h>
|
||||||
#include <libyul/AsmAnalysisInfo.h>
|
#include <libyul/AsmAnalysisInfo.h>
|
||||||
@ -181,6 +182,7 @@ map<string, unique_ptr<OptimiserStep>> const& OptimiserSuite::allSteps()
|
|||||||
LiteralRematerialiser,
|
LiteralRematerialiser,
|
||||||
LoadResolver,
|
LoadResolver,
|
||||||
LoopInvariantCodeMotion,
|
LoopInvariantCodeMotion,
|
||||||
|
NameSimplifier,
|
||||||
RedundantAssignEliminator,
|
RedundantAssignEliminator,
|
||||||
Rematerialiser,
|
Rematerialiser,
|
||||||
SSAReverser,
|
SSAReverser,
|
||||||
@ -218,6 +220,7 @@ map<string, char> const& OptimiserSuite::stepNameToAbbreviationMap()
|
|||||||
{LiteralRematerialiser::name, 'T'},
|
{LiteralRematerialiser::name, 'T'},
|
||||||
{LoadResolver::name, 'L'},
|
{LoadResolver::name, 'L'},
|
||||||
{LoopInvariantCodeMotion::name, 'M'},
|
{LoopInvariantCodeMotion::name, 'M'},
|
||||||
|
{NameSimplifier::name, 'N'},
|
||||||
{RedundantAssignEliminator::name, 'r'},
|
{RedundantAssignEliminator::name, 'r'},
|
||||||
{Rematerialiser::name, 'm'},
|
{Rematerialiser::name, 'm'},
|
||||||
{SSAReverser::name, 'V'},
|
{SSAReverser::name, 'V'},
|
||||||
|
@ -35,5 +35,5 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
docker run -v $(pwd):/root/project -w /root/project \
|
docker run -v $(pwd):/root/project -w /root/project \
|
||||||
solbuildpackpusher/solidity-buildpack-deps@sha256:d557d015918c3cf68b0d22839bab41013f0757b651a7fef21595f89721dbebcc \
|
solbuildpackpusher/solidity-buildpack-deps@sha256:23dad3b34deae8107c8551804ef299f6a89c23ed506e8118fac151e2bdc9018c\
|
||||||
./scripts/travis-emscripten/build_emscripten.sh $BUILD_DIR
|
./scripts/travis-emscripten/build_emscripten.sh $BUILD_DIR
|
||||||
|
@ -29,12 +29,12 @@
|
|||||||
# make version=1.39.15 build
|
# make version=1.39.15 build
|
||||||
#
|
#
|
||||||
FROM emscripten/emsdk:1.39.15 AS base
|
FROM emscripten/emsdk:1.39.15 AS base
|
||||||
LABEL version="1"
|
LABEL version="2"
|
||||||
|
|
||||||
ADD emscripten.jam /usr/src
|
ADD emscripten.jam /usr/src
|
||||||
RUN set -ex; \
|
RUN set -ex; \
|
||||||
cd /usr/src; \
|
cd /usr/src; \
|
||||||
git clone https://github.com/Z3Prover/z3.git -b z3-4.8.8 --depth 1 ; \
|
git clone https://github.com/Z3Prover/z3.git -b z3-4.8.9 --depth 1 ; \
|
||||||
cd z3; \
|
cd z3; \
|
||||||
mkdir build; \
|
mkdir build; \
|
||||||
cd build; \
|
cd build; \
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
# (c) 2016-2019 solidity contributors.
|
# (c) 2016-2019 solidity contributors.
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
FROM gcr.io/oss-fuzz-base/base-clang as base
|
FROM gcr.io/oss-fuzz-base/base-clang as base
|
||||||
LABEL version="3"
|
LABEL version="4"
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ RUN git clone -b boost-1.69.0 https://github.com/boostorg/boost.git \
|
|||||||
rm -rf /usr/src/boost
|
rm -rf /usr/src/boost
|
||||||
|
|
||||||
# Z3
|
# Z3
|
||||||
RUN git clone --depth 1 -b z3-4.8.7 https://github.com/Z3Prover/z3.git \
|
RUN git clone --depth 1 -b z3-4.8.9 https://github.com/Z3Prover/z3.git \
|
||||||
/usr/src/z3; \
|
/usr/src/z3; \
|
||||||
cd /usr/src/z3; \
|
cd /usr/src/z3; \
|
||||||
mkdir build; \
|
mkdir build; \
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
# (c) 2016-2019 solidity contributors.
|
# (c) 2016-2019 solidity contributors.
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
FROM buildpack-deps:bionic AS base
|
FROM buildpack-deps:bionic AS base
|
||||||
LABEL version="2"
|
LABEL version="3"
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
# (c) 2016-2019 solidity contributors.
|
# (c) 2016-2019 solidity contributors.
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
FROM buildpack-deps:focal AS base
|
FROM buildpack-deps:focal AS base
|
||||||
LABEL version="2"
|
LABEL version="3"
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
# (c) 2016-2019 solidity contributors.
|
# (c) 2016-2019 solidity contributors.
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
FROM buildpack-deps:focal AS base
|
FROM buildpack-deps:focal AS base
|
||||||
LABEL version="2"
|
LABEL version="3"
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ packagename=solc
|
|||||||
|
|
||||||
static_build_distribution=focal
|
static_build_distribution=focal
|
||||||
|
|
||||||
DISTRIBUTIONS="bionic eoan focal"
|
DISTRIBUTIONS="bionic focal groovy"
|
||||||
|
|
||||||
if is_release
|
if is_release
|
||||||
then
|
then
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <iostream>
|
||||||
#include <test/Common.h>
|
#include <test/Common.h>
|
||||||
|
|
||||||
#include <libsolutil/Assertions.h>
|
#include <libsolutil/Assertions.h>
|
||||||
@ -57,9 +58,9 @@ boost::filesystem::path testPath()
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string EVMOneEnvOrDefaultPath()
|
std::string envOrDefaultPath(std::string const& env_name, std::string const& lib_name)
|
||||||
{
|
{
|
||||||
if (auto path = getenv("ETH_EVMONE"))
|
if (auto path = getenv(env_name.c_str()))
|
||||||
return path;
|
return path;
|
||||||
|
|
||||||
auto const searchPath =
|
auto const searchPath =
|
||||||
@ -76,7 +77,7 @@ std::string EVMOneEnvOrDefaultPath()
|
|||||||
};
|
};
|
||||||
for (auto const& basePath: searchPath)
|
for (auto const& basePath: searchPath)
|
||||||
{
|
{
|
||||||
fs::path p = basePath / evmoneFilename;
|
fs::path p = basePath / lib_name;
|
||||||
if (fs::exists(p))
|
if (fs::exists(p))
|
||||||
return p.string();
|
return p.string();
|
||||||
}
|
}
|
||||||
@ -92,7 +93,8 @@ CommonOptions::CommonOptions(std::string _caption):
|
|||||||
options.add_options()
|
options.add_options()
|
||||||
("evm-version", po::value(&evmVersionString), "which evm version to use")
|
("evm-version", po::value(&evmVersionString), "which evm version to use")
|
||||||
("testpath", po::value<fs::path>(&this->testPath)->default_value(solidity::test::testPath()), "path to test files")
|
("testpath", po::value<fs::path>(&this->testPath)->default_value(solidity::test::testPath()), "path to test files")
|
||||||
("evmonepath", po::value<fs::path>(&evmonePath)->default_value(EVMOneEnvOrDefaultPath()), "path to evmone library")
|
("vm", po::value<std::vector<fs::path>>(&vmPaths), "path to evmc library, can be supplied multiple times.")
|
||||||
|
("ewasm", po::bool_switch(&ewasm), "tries to automatically find an ewasm vm and enable ewasm test-execution.")
|
||||||
("no-smt", po::bool_switch(&disableSMT), "disable SMT checker")
|
("no-smt", po::bool_switch(&disableSMT), "disable SMT checker")
|
||||||
("optimize", po::bool_switch(&optimize), "enables optimization")
|
("optimize", po::bool_switch(&optimize), "enables optimization")
|
||||||
("enforce-via-yul", po::bool_switch(&enforceViaYul), "Enforce compiling all tests via yul to see if additional tests can be activated.")
|
("enforce-via-yul", po::bool_switch(&enforceViaYul), "Enforce compiling all tests via yul to see if additional tests can be activated.")
|
||||||
@ -141,6 +143,33 @@ bool CommonOptions::parse(int argc, char const* const* argv)
|
|||||||
throw std::runtime_error(errorMessage.str());
|
throw std::runtime_error(errorMessage.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (vmPaths.empty())
|
||||||
|
{
|
||||||
|
std::string evmone = envOrDefaultPath("ETH_EVMONE", evmoneFilename);
|
||||||
|
if (!evmone.empty())
|
||||||
|
vmPaths.emplace_back(evmone);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "Unable to find " << solidity::test::evmoneFilename
|
||||||
|
<< ". Please provide the path using --vm <path>." << std::endl;
|
||||||
|
std::cout << "You can download it at" << std::endl;
|
||||||
|
std::cout << solidity::test::evmoneDownloadLink << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ewasm) {
|
||||||
|
std::string hera = envOrDefaultPath("ETH_HERA", heraFilename);
|
||||||
|
if (!hera.empty())
|
||||||
|
vmPaths.emplace_back(hera);
|
||||||
|
else {
|
||||||
|
std::cout << "Unable to find " << solidity::test::heraFilename
|
||||||
|
<< ". Please provide the path using --vm <path>." << std::endl;
|
||||||
|
std::cout << "You can download it at" << std::endl;
|
||||||
|
std::cout << solidity::test::heraDownloadLink << std::endl;
|
||||||
|
std::cout << "Ewasm tests disabled." << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
#include <libsolutil/Exceptions.h>
|
#include <libsolutil/Exceptions.h>
|
||||||
#include <liblangutil/EVMVersion.h>
|
#include <liblangutil/EVMVersion.h>
|
||||||
|
|
||||||
|
#include <test/evmc/evmc.h>
|
||||||
|
|
||||||
#include <boost/filesystem/path.hpp>
|
#include <boost/filesystem/path.hpp>
|
||||||
#include <boost/noncopyable.hpp>
|
#include <boost/noncopyable.hpp>
|
||||||
#include <boost/program_options.hpp>
|
#include <boost/program_options.hpp>
|
||||||
@ -31,21 +33,27 @@ namespace solidity::test
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
static constexpr auto evmoneFilename = "evmone.dll";
|
static constexpr auto evmoneFilename = "evmone.dll";
|
||||||
static constexpr auto evmoneDownloadLink = "https://github.com/ethereum/evmone/releases/download/v0.4.1/evmone-0.4.1-windows-amd64.zip";
|
static constexpr auto evmoneDownloadLink = "https://github.com/ethereum/evmone/releases/download/v0.4.1/evmone-0.4.1-windows-amd64.zip";
|
||||||
|
static constexpr auto heraFilename = "hera.dll";
|
||||||
|
static constexpr auto heraDownloadLink = "https://github.com/ewasm/hera/archive/v0.3.0.tar.gz";
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
static constexpr auto evmoneFilename = "libevmone.dylib";
|
static constexpr auto evmoneFilename = "libevmone.dylib";
|
||||||
static constexpr auto evmoneDownloadLink = "https://github.com/ethereum/evmone/releases/download/v0.4.1/evmone-0.4.1-darwin-x86_64.tar.gz";
|
static constexpr auto evmoneDownloadLink = "https://github.com/ethereum/evmone/releases/download/v0.4.1/evmone-0.4.1-darwin-x86_64.tar.gz";
|
||||||
|
static constexpr auto heraFilename = "libhera.dylib";
|
||||||
|
static constexpr auto heraDownloadLink = "https://github.com/ewasm/hera/releases/download/v0.3.0/hera-0.3.0-darwin-x86_64.tar.gz";
|
||||||
#else
|
#else
|
||||||
static constexpr auto evmoneFilename = "libevmone.so";
|
static constexpr auto evmoneFilename = "libevmone.so";
|
||||||
static constexpr auto evmoneDownloadLink = "https://github.com/ethereum/evmone/releases/download/v0.4.1/evmone-0.4.1-linux-x86_64.tar.gz";
|
static constexpr auto evmoneDownloadLink = "https://github.com/ethereum/evmone/releases/download/v0.4.1/evmone-0.4.1-linux-x86_64.tar.gz";
|
||||||
|
static constexpr auto heraFilename = "libhera.so";
|
||||||
|
static constexpr auto heraDownloadLink = "https://github.com/ewasm/hera/releases/download/v0.3.0/hera-0.3.0-linux-x86_64.tar.gz";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
struct ConfigException : public util::Exception {};
|
struct ConfigException : public util::Exception {};
|
||||||
|
|
||||||
struct CommonOptions: boost::noncopyable
|
struct CommonOptions: boost::noncopyable
|
||||||
{
|
{
|
||||||
boost::filesystem::path evmonePath;
|
std::vector<boost::filesystem::path> vmPaths;
|
||||||
boost::filesystem::path testPath;
|
boost::filesystem::path testPath;
|
||||||
|
bool ewasm = false;
|
||||||
bool optimize = false;
|
bool optimize = false;
|
||||||
bool enforceViaYul = false;
|
bool enforceViaYul = false;
|
||||||
bool disableSMT = false;
|
bool disableSMT = false;
|
||||||
@ -64,8 +72,8 @@ struct CommonOptions: boost::noncopyable
|
|||||||
|
|
||||||
CommonOptions(std::string caption = "");
|
CommonOptions(std::string caption = "");
|
||||||
virtual ~CommonOptions() {};
|
virtual ~CommonOptions() {};
|
||||||
protected:
|
|
||||||
|
|
||||||
|
protected:
|
||||||
boost::program_options::options_description options;
|
boost::program_options::options_description options;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -39,17 +39,18 @@ using namespace evmc::literals;
|
|||||||
|
|
||||||
evmc::VM& EVMHost::getVM(string const& _path)
|
evmc::VM& EVMHost::getVM(string const& _path)
|
||||||
{
|
{
|
||||||
static evmc::VM theVM;
|
static evmc::VM NullVM{nullptr};
|
||||||
if (!theVM && !_path.empty())
|
static map<string, unique_ptr<evmc::VM>> vms;
|
||||||
|
if (vms.count(_path) == 0)
|
||||||
{
|
{
|
||||||
evmc_loader_error_code errorCode = {};
|
evmc_loader_error_code errorCode = {};
|
||||||
auto vm = evmc::VM{evmc_load_and_configure(_path.c_str(), &errorCode)};
|
auto vm = evmc::VM{evmc_load_and_configure(_path.c_str(), &errorCode)};
|
||||||
if (vm && errorCode == EVMC_LOADER_SUCCESS)
|
if (vm && errorCode == EVMC_LOADER_SUCCESS)
|
||||||
{
|
{
|
||||||
if (vm.get_capabilities() & EVMC_CAPABILITY_EVM1)
|
if (vm.get_capabilities() & (EVMC_CAPABILITY_EVM1 | EVMC_CAPABILITY_EWASM))
|
||||||
theVM = std::move(vm);
|
vms[_path] = make_unique<evmc::VM>(evmc::VM(move(vm)));
|
||||||
else
|
else
|
||||||
cerr << "VM loaded does not support EVM1" << endl;
|
cerr << "VM loaded neither supports EVM1 nor EWASM" << endl;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -59,7 +60,38 @@ evmc::VM& EVMHost::getVM(string const& _path)
|
|||||||
cerr << endl;
|
cerr << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return theVM;
|
|
||||||
|
if (vms.count(_path) > 0)
|
||||||
|
return *vms[_path];
|
||||||
|
|
||||||
|
return NullVM;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EVMHost::checkVmPaths(vector<boost::filesystem::path> const& _vmPaths)
|
||||||
|
{
|
||||||
|
bool evmVmFound = false;
|
||||||
|
bool ewasmVmFound = false;
|
||||||
|
for (auto const& path: _vmPaths)
|
||||||
|
{
|
||||||
|
evmc::VM& vm = EVMHost::getVM(path.string());
|
||||||
|
if (!vm)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (vm.has_capability(EVMC_CAPABILITY_EVM1))
|
||||||
|
{
|
||||||
|
if (evmVmFound)
|
||||||
|
throw runtime_error("Multiple evm1 evmc vms defined. Please only define one evm1 evmc vm.");
|
||||||
|
evmVmFound = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vm.has_capability(EVMC_CAPABILITY_EWASM))
|
||||||
|
{
|
||||||
|
if (ewasmVmFound)
|
||||||
|
throw runtime_error("Multiple ewasm evmc vms where defined. Please only define one ewasm evmc vm.");
|
||||||
|
ewasmVmFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return evmVmFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM& _vm):
|
EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM& _vm):
|
||||||
|
@ -30,6 +30,8 @@
|
|||||||
|
|
||||||
#include <libsolutil/FixedHash.h>
|
#include <libsolutil/FixedHash.h>
|
||||||
|
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
namespace solidity::test
|
namespace solidity::test
|
||||||
{
|
{
|
||||||
using Address = util::h160;
|
using Address = util::h160;
|
||||||
@ -40,12 +42,17 @@ public:
|
|||||||
using MockedHost::get_code_size;
|
using MockedHost::get_code_size;
|
||||||
using MockedHost::get_balance;
|
using MockedHost::get_balance;
|
||||||
|
|
||||||
/// Tries to dynamically load libevmone. @returns nullptr on failure.
|
/// Tries to dynamically load an evmc vm supporting evm1 or ewasm and caches the loaded VM.
|
||||||
/// The path has to be provided for the first successful run and will be ignored
|
/// @returns vmc::VM(nullptr) on failure.
|
||||||
/// afterwards.
|
|
||||||
static evmc::VM& getVM(std::string const& _path = {});
|
static evmc::VM& getVM(std::string const& _path = {});
|
||||||
|
|
||||||
explicit EVMHost(langutil::EVMVersion _evmVersion, evmc::VM& _vm = getVM());
|
/// Tries to load all defined evmc vm shared libraries.
|
||||||
|
/// @param _vmPaths paths to multiple evmc shared libraries.
|
||||||
|
/// @throw Exception if multiple evm1 or multiple ewasm evmc vms where loaded.
|
||||||
|
/// @returns true, if an evmc vm was supporting evm1 loaded properly.
|
||||||
|
static bool checkVmPaths(std::vector<boost::filesystem::path> const& _vmPaths);
|
||||||
|
|
||||||
|
explicit EVMHost(langutil::EVMVersion _evmVersion, evmc::VM& _vm);
|
||||||
|
|
||||||
void reset() { accounts.clear(); m_currentAddress = {}; }
|
void reset() { accounts.clear(); m_currentAddress = {}; }
|
||||||
void newBlock()
|
void newBlock()
|
||||||
@ -71,6 +78,12 @@ public:
|
|||||||
static util::h256 convertFromEVMC(evmc::bytes32 const& _data);
|
static util::h256 convertFromEVMC(evmc::bytes32 const& _data);
|
||||||
static evmc::bytes32 convertToEVMC(util::h256 const& _data);
|
static evmc::bytes32 convertToEVMC(util::h256 const& _data);
|
||||||
|
|
||||||
|
/// @returns true, if the evmc VM has the given capability.
|
||||||
|
bool hasCapability(evmc_capabilities capability) const noexcept
|
||||||
|
{
|
||||||
|
return m_vm.has_capability(capability);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
evmc::address m_currentAddress = {};
|
evmc::address m_currentAddress = {};
|
||||||
|
|
||||||
|
@ -29,6 +29,8 @@
|
|||||||
|
|
||||||
#include <libsolutil/CommonIO.h>
|
#include <libsolutil/CommonIO.h>
|
||||||
|
|
||||||
|
#include <liblangutil/Exceptions.h>
|
||||||
|
|
||||||
#include <boost/test/framework.hpp>
|
#include <boost/test/framework.hpp>
|
||||||
#include <boost/algorithm/string/replace.hpp>
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
|
|
||||||
@ -40,27 +42,47 @@ using namespace solidity::util;
|
|||||||
using namespace solidity::test;
|
using namespace solidity::test;
|
||||||
|
|
||||||
ExecutionFramework::ExecutionFramework():
|
ExecutionFramework::ExecutionFramework():
|
||||||
ExecutionFramework(solidity::test::CommonOptions::get().evmVersion())
|
ExecutionFramework(solidity::test::CommonOptions::get().evmVersion(), solidity::test::CommonOptions::get().vmPaths)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecutionFramework::ExecutionFramework(langutil::EVMVersion _evmVersion):
|
ExecutionFramework::ExecutionFramework(langutil::EVMVersion _evmVersion, vector<boost::filesystem::path> const& _vmPaths):
|
||||||
m_evmVersion(_evmVersion),
|
m_evmVersion(_evmVersion),
|
||||||
m_optimiserSettings(solidity::frontend::OptimiserSettings::minimal()),
|
m_optimiserSettings(solidity::frontend::OptimiserSettings::minimal()),
|
||||||
m_showMessages(solidity::test::CommonOptions::get().showMessages),
|
m_showMessages(solidity::test::CommonOptions::get().showMessages),
|
||||||
m_evmHost(make_shared<EVMHost>(m_evmVersion))
|
m_vmPaths(_vmPaths)
|
||||||
{
|
{
|
||||||
if (solidity::test::CommonOptions::get().optimize)
|
if (solidity::test::CommonOptions::get().optimize)
|
||||||
m_optimiserSettings = solidity::frontend::OptimiserSettings::standard();
|
m_optimiserSettings = solidity::frontend::OptimiserSettings::standard();
|
||||||
|
|
||||||
|
for (auto const& path: m_vmPaths)
|
||||||
|
if (EVMHost::getVM(path.string()).has_capability(EVMC_CAPABILITY_EWASM))
|
||||||
|
m_supportsEwasm = true;
|
||||||
|
|
||||||
|
selectVM(evmc_capabilities::EVMC_CAPABILITY_EVM1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExecutionFramework::selectVM(evmc_capabilities _cap)
|
||||||
|
{
|
||||||
|
m_evmcHost.reset();
|
||||||
|
for (auto const& path: m_vmPaths)
|
||||||
|
{
|
||||||
|
evmc::VM& vm = EVMHost::getVM(path.string());
|
||||||
|
if (vm.has_capability(_cap))
|
||||||
|
{
|
||||||
|
m_evmcHost = make_unique<EVMHost>(m_evmVersion, vm);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
solAssert(m_evmcHost != nullptr, "");
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExecutionFramework::reset()
|
void ExecutionFramework::reset()
|
||||||
{
|
{
|
||||||
m_evmHost->reset();
|
m_evmcHost->reset();
|
||||||
for (size_t i = 0; i < 10; i++)
|
for (size_t i = 0; i < 10; i++)
|
||||||
m_evmHost->accounts[EVMHost::convertToEVMC(account(i))].balance =
|
m_evmcHost->accounts[EVMHost::convertToEVMC(account(i))].balance =
|
||||||
EVMHost::convertToEVMC(u256(1) << 100);
|
EVMHost::convertToEVMC(u256(1) << 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +114,7 @@ std::pair<bool, string> ExecutionFramework::compareAndCreateMessage(
|
|||||||
|
|
||||||
u256 ExecutionFramework::gasLimit() const
|
u256 ExecutionFramework::gasLimit() const
|
||||||
{
|
{
|
||||||
return {m_evmHost->tx_context.block_gas_limit};
|
return {m_evmcHost->tx_context.block_gas_limit};
|
||||||
}
|
}
|
||||||
|
|
||||||
u256 ExecutionFramework::gasPrice() const
|
u256 ExecutionFramework::gasPrice() const
|
||||||
@ -100,24 +122,24 @@ u256 ExecutionFramework::gasPrice() const
|
|||||||
// here and below we use "return u256{....}" instead of just "return {....}"
|
// here and below we use "return u256{....}" instead of just "return {....}"
|
||||||
// to please MSVC and avoid unexpected
|
// to please MSVC and avoid unexpected
|
||||||
// warning C4927 : illegal conversion; more than one user - defined conversion has been implicitly applied
|
// warning C4927 : illegal conversion; more than one user - defined conversion has been implicitly applied
|
||||||
return u256{EVMHost::convertFromEVMC(m_evmHost->tx_context.tx_gas_price)};
|
return u256{EVMHost::convertFromEVMC(m_evmcHost->tx_context.tx_gas_price)};
|
||||||
}
|
}
|
||||||
|
|
||||||
u256 ExecutionFramework::blockHash(u256 const& _number) const
|
u256 ExecutionFramework::blockHash(u256 const& _number) const
|
||||||
{
|
{
|
||||||
return u256{EVMHost::convertFromEVMC(
|
return u256{EVMHost::convertFromEVMC(
|
||||||
m_evmHost->get_block_hash(static_cast<int64_t>(_number & numeric_limits<uint64_t>::max()))
|
m_evmcHost->get_block_hash(static_cast<int64_t>(_number & numeric_limits<uint64_t>::max()))
|
||||||
)};
|
)};
|
||||||
}
|
}
|
||||||
|
|
||||||
u256 ExecutionFramework::blockNumber() const
|
u256 ExecutionFramework::blockNumber() const
|
||||||
{
|
{
|
||||||
return m_evmHost->tx_context.block_number;
|
return m_evmcHost->tx_context.block_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExecutionFramework::sendMessage(bytes const& _data, bool _isCreation, u256 const& _value)
|
void ExecutionFramework::sendMessage(bytes const& _data, bool _isCreation, u256 const& _value)
|
||||||
{
|
{
|
||||||
m_evmHost->newBlock();
|
m_evmcHost->newBlock();
|
||||||
|
|
||||||
if (m_showMessages)
|
if (m_showMessages)
|
||||||
{
|
{
|
||||||
@ -147,7 +169,7 @@ void ExecutionFramework::sendMessage(bytes const& _data, bool _isCreation, u256
|
|||||||
}
|
}
|
||||||
message.gas = m_gas.convert_to<int64_t>();
|
message.gas = m_gas.convert_to<int64_t>();
|
||||||
|
|
||||||
evmc::result result = m_evmHost->call(message);
|
evmc::result result = m_evmcHost->call(message);
|
||||||
|
|
||||||
m_output = bytes(result.output_data, result.output_data + result.output_size);
|
m_output = bytes(result.output_data, result.output_data + result.output_size);
|
||||||
if (_isCreation)
|
if (_isCreation)
|
||||||
@ -166,7 +188,7 @@ void ExecutionFramework::sendMessage(bytes const& _data, bool _isCreation, u256
|
|||||||
|
|
||||||
void ExecutionFramework::sendEther(Address const& _addr, u256 const& _amount)
|
void ExecutionFramework::sendEther(Address const& _addr, u256 const& _amount)
|
||||||
{
|
{
|
||||||
m_evmHost->newBlock();
|
m_evmcHost->newBlock();
|
||||||
|
|
||||||
if (m_showMessages)
|
if (m_showMessages)
|
||||||
{
|
{
|
||||||
@ -181,12 +203,12 @@ void ExecutionFramework::sendEther(Address const& _addr, u256 const& _amount)
|
|||||||
message.destination = EVMHost::convertToEVMC(_addr);
|
message.destination = EVMHost::convertToEVMC(_addr);
|
||||||
message.gas = m_gas.convert_to<int64_t>();
|
message.gas = m_gas.convert_to<int64_t>();
|
||||||
|
|
||||||
m_evmHost->call(message);
|
m_evmcHost->call(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ExecutionFramework::currentTimestamp()
|
size_t ExecutionFramework::currentTimestamp()
|
||||||
{
|
{
|
||||||
return static_cast<size_t>(m_evmHost->tx_context.block_timestamp);
|
return static_cast<size_t>(m_evmcHost->tx_context.block_timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ExecutionFramework::blockTimestamp(u256 _block)
|
size_t ExecutionFramework::blockTimestamp(u256 _block)
|
||||||
@ -204,32 +226,32 @@ Address ExecutionFramework::account(size_t _idx)
|
|||||||
|
|
||||||
bool ExecutionFramework::addressHasCode(Address const& _addr)
|
bool ExecutionFramework::addressHasCode(Address const& _addr)
|
||||||
{
|
{
|
||||||
return m_evmHost->get_code_size(EVMHost::convertToEVMC(_addr)) != 0;
|
return m_evmcHost->get_code_size(EVMHost::convertToEVMC(_addr)) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ExecutionFramework::numLogs() const
|
size_t ExecutionFramework::numLogs() const
|
||||||
{
|
{
|
||||||
return m_evmHost->recorded_logs.size();
|
return m_evmcHost->recorded_logs.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ExecutionFramework::numLogTopics(size_t _logIdx) const
|
size_t ExecutionFramework::numLogTopics(size_t _logIdx) const
|
||||||
{
|
{
|
||||||
return m_evmHost->recorded_logs.at(_logIdx).topics.size();
|
return m_evmcHost->recorded_logs.at(_logIdx).topics.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
h256 ExecutionFramework::logTopic(size_t _logIdx, size_t _topicIdx) const
|
h256 ExecutionFramework::logTopic(size_t _logIdx, size_t _topicIdx) const
|
||||||
{
|
{
|
||||||
return EVMHost::convertFromEVMC(m_evmHost->recorded_logs.at(_logIdx).topics.at(_topicIdx));
|
return EVMHost::convertFromEVMC(m_evmcHost->recorded_logs.at(_logIdx).topics.at(_topicIdx));
|
||||||
}
|
}
|
||||||
|
|
||||||
Address ExecutionFramework::logAddress(size_t _logIdx) const
|
Address ExecutionFramework::logAddress(size_t _logIdx) const
|
||||||
{
|
{
|
||||||
return EVMHost::convertFromEVMC(m_evmHost->recorded_logs.at(_logIdx).creator);
|
return EVMHost::convertFromEVMC(m_evmcHost->recorded_logs.at(_logIdx).creator);
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes ExecutionFramework::logData(size_t _logIdx) const
|
bytes ExecutionFramework::logData(size_t _logIdx) const
|
||||||
{
|
{
|
||||||
const auto& data = m_evmHost->recorded_logs.at(_logIdx).data;
|
const auto& data = m_evmcHost->recorded_logs.at(_logIdx).data;
|
||||||
// TODO: Return a copy of log data, because this is expected from REQUIRE_LOG_DATA(),
|
// TODO: Return a copy of log data, because this is expected from REQUIRE_LOG_DATA(),
|
||||||
// but reference type like string_view would be preferable.
|
// but reference type like string_view would be preferable.
|
||||||
return {data.begin(), data.end()};
|
return {data.begin(), data.end()};
|
||||||
@ -237,13 +259,13 @@ bytes ExecutionFramework::logData(size_t _logIdx) const
|
|||||||
|
|
||||||
u256 ExecutionFramework::balanceAt(Address const& _addr)
|
u256 ExecutionFramework::balanceAt(Address const& _addr)
|
||||||
{
|
{
|
||||||
return u256(EVMHost::convertFromEVMC(m_evmHost->get_balance(EVMHost::convertToEVMC(_addr))));
|
return u256(EVMHost::convertFromEVMC(m_evmcHost->get_balance(EVMHost::convertToEVMC(_addr))));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExecutionFramework::storageEmpty(Address const& _addr)
|
bool ExecutionFramework::storageEmpty(Address const& _addr)
|
||||||
{
|
{
|
||||||
const auto it = m_evmHost->accounts.find(EVMHost::convertToEVMC(_addr));
|
const auto it = m_evmcHost->accounts.find(EVMHost::convertToEVMC(_addr));
|
||||||
if (it != m_evmHost->accounts.end())
|
if (it != m_evmcHost->accounts.end())
|
||||||
{
|
{
|
||||||
for (auto const& entry: it->second.storage)
|
for (auto const& entry: it->second.storage)
|
||||||
if (!(entry.second.value == evmc::bytes32{}))
|
if (!(entry.second.value == evmc::bytes32{}))
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <test/Common.h>
|
#include <test/Common.h>
|
||||||
|
#include <test/EVMHost.h>
|
||||||
|
|
||||||
#include <libsolidity/interface/OptimiserSettings.h>
|
#include <libsolidity/interface/OptimiserSettings.h>
|
||||||
#include <libsolidity/interface/DebugSettings.h>
|
#include <libsolidity/interface/DebugSettings.h>
|
||||||
@ -39,8 +40,6 @@
|
|||||||
|
|
||||||
namespace solidity::test
|
namespace solidity::test
|
||||||
{
|
{
|
||||||
class EVMHost;
|
|
||||||
|
|
||||||
using rational = boost::rational<bigint>;
|
using rational = boost::rational<bigint>;
|
||||||
/// An Ethereum address: 20 bytes.
|
/// An Ethereum address: 20 bytes.
|
||||||
/// @NOTE This is not endian-specific; it's just a bunch of bytes.
|
/// @NOTE This is not endian-specific; it's just a bunch of bytes.
|
||||||
@ -55,7 +54,7 @@ class ExecutionFramework
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
ExecutionFramework();
|
ExecutionFramework();
|
||||||
explicit ExecutionFramework(langutil::EVMVersion _evmVersion);
|
ExecutionFramework(langutil::EVMVersion _evmVersion, std::vector<boost::filesystem::path> const& _vmPaths);
|
||||||
virtual ~ExecutionFramework() = default;
|
virtual ~ExecutionFramework() = default;
|
||||||
|
|
||||||
virtual bytes const& compileAndRunWithoutCheck(
|
virtual bytes const& compileAndRunWithoutCheck(
|
||||||
@ -255,6 +254,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void selectVM(evmc_capabilities _cap = evmc_capabilities::EVMC_CAPABILITY_EVM1);
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0);
|
void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0);
|
||||||
@ -279,7 +279,10 @@ protected:
|
|||||||
solidity::frontend::RevertStrings m_revertStrings = solidity::frontend::RevertStrings::Default;
|
solidity::frontend::RevertStrings m_revertStrings = solidity::frontend::RevertStrings::Default;
|
||||||
solidity::frontend::OptimiserSettings m_optimiserSettings = solidity::frontend::OptimiserSettings::minimal();
|
solidity::frontend::OptimiserSettings m_optimiserSettings = solidity::frontend::OptimiserSettings::minimal();
|
||||||
bool m_showMessages = false;
|
bool m_showMessages = false;
|
||||||
std::shared_ptr<EVMHost> m_evmHost;
|
bool m_supportsEwasm = false;
|
||||||
|
std::unique_ptr<EVMHost> m_evmcHost;
|
||||||
|
|
||||||
|
std::vector<boost::filesystem::path> m_vmPaths;
|
||||||
|
|
||||||
bool m_transactionSuccessful = true;
|
bool m_transactionSuccessful = true;
|
||||||
Address m_sender = account(0);
|
Address m_sender = account(0);
|
||||||
|
@ -39,6 +39,7 @@ public:
|
|||||||
{
|
{
|
||||||
std::string filename;
|
std::string filename;
|
||||||
langutil::EVMVersion evmVersion;
|
langutil::EVMVersion evmVersion;
|
||||||
|
std::vector<boost::filesystem::path> vmPaths;
|
||||||
bool enforceCompileViaYul;
|
bool enforceCompileViaYul;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -39,7 +39,6 @@
|
|||||||
#include <test/InteractiveTests.h>
|
#include <test/InteractiveTests.h>
|
||||||
#include <test/Common.h>
|
#include <test/Common.h>
|
||||||
#include <test/EVMHost.h>
|
#include <test/EVMHost.h>
|
||||||
#include <test/Common.h>
|
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
@ -72,7 +71,7 @@ int registerTests(
|
|||||||
{
|
{
|
||||||
int numTestsAdded = 0;
|
int numTestsAdded = 0;
|
||||||
fs::path fullpath = _basepath / _path;
|
fs::path fullpath = _basepath / _path;
|
||||||
TestCase::Config config{fullpath.string(), solidity::test::CommonOptions::get().evmVersion(), _enforceViaYul};
|
TestCase::Config config{fullpath.string(), solidity::test::CommonOptions::get().evmVersion(), solidity::test::CommonOptions::get().vmPaths, _enforceViaYul};
|
||||||
if (fs::is_directory(fullpath))
|
if (fs::is_directory(fullpath))
|
||||||
{
|
{
|
||||||
test_suite* sub_suite = BOOST_TEST_SUITE(_path.filename().string());
|
test_suite* sub_suite = BOOST_TEST_SUITE(_path.filename().string());
|
||||||
@ -156,14 +155,19 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] )
|
|||||||
|
|
||||||
initializeOptions();
|
initializeOptions();
|
||||||
|
|
||||||
bool disableSemantics = !solidity::test::EVMHost::getVM(solidity::test::CommonOptions::get().evmonePath.string());
|
bool disableSemantics = true;
|
||||||
if (disableSemantics)
|
try
|
||||||
{
|
{
|
||||||
cout << "Unable to find " << solidity::test::evmoneFilename << ". Please provide the path using -- --evmonepath <path>." << endl;
|
disableSemantics = !solidity::test::EVMHost::checkVmPaths(solidity::test::CommonOptions::get().vmPaths);
|
||||||
cout << "You can download it at" << endl;
|
|
||||||
cout << solidity::test::evmoneDownloadLink << endl;
|
|
||||||
cout << endl << "--- SKIPPING ALL SEMANTICS TESTS ---" << endl << endl;
|
|
||||||
}
|
}
|
||||||
|
catch (std::runtime_error const& _exception)
|
||||||
|
{
|
||||||
|
cerr << "Error: " << _exception.what() << endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (disableSemantics)
|
||||||
|
cout << endl << "--- SKIPPING ALL SEMANTICS TESTS ---" << endl << endl;
|
||||||
|
|
||||||
// Include the interactive tests in the automatic tests as well
|
// Include the interactive tests in the automatic tests as well
|
||||||
for (auto const& ts: g_interactiveTestsuites)
|
for (auto const& ts: g_interactiveTestsuites)
|
||||||
{
|
{
|
||||||
|
1
test/cmdlineTests/name_simplifier/args
Normal file
1
test/cmdlineTests/name_simplifier/args
Normal file
@ -0,0 +1 @@
|
|||||||
|
--optimize --ir-optimized --metadata-hash none
|
23
test/cmdlineTests/name_simplifier/input.sol
Normal file
23
test/cmdlineTests/name_simplifier/input.sol
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
pragma solidity >=0.0;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
// The point of this test is to check that the
|
||||||
|
// AST IDs are removed from the optimized IR
|
||||||
|
// so that they do not have a big effect on the
|
||||||
|
// optimizer if it has a bug that makes it
|
||||||
|
// depen on the actual identifiers.
|
||||||
|
|
||||||
|
struct S { uint x; }
|
||||||
|
struct T { uint[2] y; }
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
S[2] values;
|
||||||
|
T t;
|
||||||
|
|
||||||
|
function sumArray(S[] memory _s) public returns (uint, string memory) {
|
||||||
|
values[0].x = _s[0].x;
|
||||||
|
t.y[0] = _s[1].x;
|
||||||
|
return (t.y[0], "longstringlongstringlongstringlongstringlongstringlongstringlongstringlongstringlongstringlongstring");
|
||||||
|
}
|
||||||
|
}
|
129
test/cmdlineTests/name_simplifier/output
Normal file
129
test/cmdlineTests/name_simplifier/output
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
Optimized IR:
|
||||||
|
/*******************************************************
|
||||||
|
* WARNING *
|
||||||
|
* Solidity to Yul compilation is still EXPERIMENTAL *
|
||||||
|
* It can result in LOSS OF FUNDS or worse *
|
||||||
|
* !USE AT YOUR OWN RISK! *
|
||||||
|
*******************************************************/
|
||||||
|
|
||||||
|
object "C_56" {
|
||||||
|
code {
|
||||||
|
{
|
||||||
|
mstore(64, 128)
|
||||||
|
if callvalue() { revert(0, 0) }
|
||||||
|
let _1 := datasize("C_56_deployed")
|
||||||
|
codecopy(0, dataoffset("C_56_deployed"), _1)
|
||||||
|
return(0, _1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
object "C_56_deployed" {
|
||||||
|
code {
|
||||||
|
{
|
||||||
|
mstore(64, 128)
|
||||||
|
if iszero(lt(calldatasize(), 4))
|
||||||
|
{
|
||||||
|
let _1 := 0
|
||||||
|
if eq(0xf8eddcc6, shr(224, calldataload(_1)))
|
||||||
|
{
|
||||||
|
if callvalue() { revert(_1, _1) }
|
||||||
|
let _2 := 32
|
||||||
|
if slt(add(calldatasize(), not(3)), _2) { revert(_1, _1) }
|
||||||
|
let offset := calldataload(4)
|
||||||
|
let _3 := 0xffffffffffffffff
|
||||||
|
if gt(offset, _3) { revert(_1, _1) }
|
||||||
|
if iszero(slt(add(offset, 35), calldatasize())) { revert(_1, _1) }
|
||||||
|
let length := calldataload(add(4, offset))
|
||||||
|
if gt(length, _3) { revert(_1, _1) }
|
||||||
|
let _4 := mul(length, _2)
|
||||||
|
let dst := allocateMemory(add(_4, _2))
|
||||||
|
let dst_1 := dst
|
||||||
|
mstore(dst, length)
|
||||||
|
dst := add(dst, _2)
|
||||||
|
let src := add(offset, 36)
|
||||||
|
if gt(add(add(offset, _4), 36), calldatasize()) { revert(_1, _1) }
|
||||||
|
let i := _1
|
||||||
|
for { } lt(i, length) { i := add(i, 1) }
|
||||||
|
{
|
||||||
|
mstore(dst, abi_decode_t_struct$_S(src, calldatasize()))
|
||||||
|
dst := add(dst, _2)
|
||||||
|
src := add(src, _2)
|
||||||
|
}
|
||||||
|
let ret, ret_1 := fun_sumArray_55(dst_1)
|
||||||
|
let memPos := allocateMemory(_1)
|
||||||
|
return(memPos, sub(abi_encode_uint256_t_string(memPos, ret, ret_1), memPos))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
revert(0, 0)
|
||||||
|
}
|
||||||
|
function abi_decode_t_struct$_S(headStart, end) -> value
|
||||||
|
{
|
||||||
|
if slt(sub(end, headStart), 0x20) { revert(value, value) }
|
||||||
|
value := allocateMemory(0x20)
|
||||||
|
mstore(value, calldataload(headStart))
|
||||||
|
}
|
||||||
|
function abi_encode_uint256_t_string(headStart, value0, value1) -> tail
|
||||||
|
{
|
||||||
|
mstore(headStart, value0)
|
||||||
|
let _1 := 32
|
||||||
|
mstore(add(headStart, _1), 64)
|
||||||
|
let length := mload(value1)
|
||||||
|
mstore(add(headStart, 64), length)
|
||||||
|
let i := tail
|
||||||
|
for { } lt(i, length) { i := add(i, _1) }
|
||||||
|
{
|
||||||
|
mstore(add(add(headStart, i), 96), mload(add(add(value1, i), _1)))
|
||||||
|
}
|
||||||
|
if gt(i, length)
|
||||||
|
{
|
||||||
|
mstore(add(add(headStart, length), 96), tail)
|
||||||
|
}
|
||||||
|
tail := add(add(headStart, and(add(length, 31), not(31))), 96)
|
||||||
|
}
|
||||||
|
function allocateMemory(size) -> memPtr
|
||||||
|
{
|
||||||
|
memPtr := mload(64)
|
||||||
|
let newFreePtr := add(memPtr, size)
|
||||||
|
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { revert(0, 0) }
|
||||||
|
mstore(64, newFreePtr)
|
||||||
|
}
|
||||||
|
function convert_t_stringliteral_6490_to_t_string() -> converted
|
||||||
|
{
|
||||||
|
converted := allocateMemory(160)
|
||||||
|
mstore(converted, 100)
|
||||||
|
mstore(add(converted, 32), "longstringlongstringlongstringlo")
|
||||||
|
mstore(add(converted, 64), "ngstringlongstringlongstringlong")
|
||||||
|
mstore(add(converted, 96), "stringlongstringlongstringlongst")
|
||||||
|
mstore(add(converted, 128), "ring")
|
||||||
|
}
|
||||||
|
function extract_from_storage_value_dynamict_uint256(slot_value, offset) -> value
|
||||||
|
{
|
||||||
|
value := shr(mul(offset, 8), slot_value)
|
||||||
|
}
|
||||||
|
function fun_sumArray_55(vloc__s_19_mpos) -> vloc, vloc__24_mpos
|
||||||
|
{
|
||||||
|
let _1 := mload(vloc__s_19_mpos)
|
||||||
|
if iszero(lt(vloc, _1)) { invalid() }
|
||||||
|
let _2 := mload(mload(add(add(vloc__s_19_mpos, mul(vloc, 32)), 32)))
|
||||||
|
let _3, _4 := storage_array_index_access$_t_struct$_S_storage(vloc, vloc)
|
||||||
|
sstore(_3, _2)
|
||||||
|
if iszero(lt(0x01, _1)) { invalid() }
|
||||||
|
let _5 := mload(mload(add(vloc__s_19_mpos, 64)))
|
||||||
|
if iszero(lt(vloc, 0x02)) { invalid() }
|
||||||
|
let slot := add(0x02, vloc)
|
||||||
|
let _6 := sload(slot)
|
||||||
|
let shiftBits := mul(vloc, 8)
|
||||||
|
let mask := shl(shiftBits, not(0))
|
||||||
|
sstore(slot, or(and(_6, not(mask)), and(shl(shiftBits, _5), mask)))
|
||||||
|
let _7, _8 := storage_array_index_access$_t_struct$_S_storage(0x02, vloc)
|
||||||
|
vloc := extract_from_storage_value_dynamict_uint256(sload(_7), _8)
|
||||||
|
vloc__24_mpos := convert_t_stringliteral_6490_to_t_string()
|
||||||
|
}
|
||||||
|
function storage_array_index_access$_t_struct$_S_storage(array, index) -> slot, offset
|
||||||
|
{
|
||||||
|
if iszero(lt(index, 0x02)) { invalid() }
|
||||||
|
slot := add(array, index)
|
||||||
|
offset := offset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -33,19 +33,22 @@ object "Arraysum_33" {
|
|||||||
for { }
|
for { }
|
||||||
lt(vloc_i, _2)
|
lt(vloc_i, _2)
|
||||||
{
|
{
|
||||||
vloc_i := increment_t_uint256(vloc_i)
|
if gt(vloc_i, not(1)) { revert(_1, _1) }
|
||||||
|
vloc_i := add(vloc_i, 1)
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let _3, _4 := storage_array_index_access_t_array$_t_uint256_$dyn_storage(_1, vloc_i)
|
mstore(_1, _1)
|
||||||
vloc_sum := checked_add_t_uint256(vloc_sum, extract_from_storage_value_dynamict_uint256(sload(_3), _4))
|
let _3 := sload(add(keccak256(_1, 0x20), vloc_i))
|
||||||
|
if gt(vloc_sum, not(_3)) { revert(_1, _1) }
|
||||||
|
vloc_sum := add(vloc_sum, _3)
|
||||||
}
|
}
|
||||||
let memPos := allocateMemory(_1)
|
let memPos := allocateMemory(_1)
|
||||||
return(memPos, sub(abi_encode_tuple_t_uint256__to_t_uint256__fromStack(memPos, _1), memPos))
|
return(memPos, sub(abi_encode_uint(memPos, _1), memPos))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
revert(0, 0)
|
revert(0, 0)
|
||||||
}
|
}
|
||||||
function abi_encode_tuple_t_uint256__to_t_uint256__fromStack(headStart, value0) -> tail
|
function abi_encode_uint(headStart, value0) -> tail
|
||||||
{
|
{
|
||||||
tail := add(headStart, 32)
|
tail := add(headStart, 32)
|
||||||
mstore(headStart, value0)
|
mstore(headStart, value0)
|
||||||
@ -57,27 +60,6 @@ object "Arraysum_33" {
|
|||||||
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { revert(0, 0) }
|
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { revert(0, 0) }
|
||||||
mstore(64, newFreePtr)
|
mstore(64, newFreePtr)
|
||||||
}
|
}
|
||||||
function checked_add_t_uint256(x, y) -> sum
|
|
||||||
{
|
|
||||||
if gt(x, not(y)) { revert(sum, sum) }
|
|
||||||
sum := add(x, y)
|
|
||||||
}
|
|
||||||
function extract_from_storage_value_dynamict_uint256(slot_value, offset) -> value
|
|
||||||
{
|
|
||||||
value := shr(mul(offset, 8), slot_value)
|
|
||||||
}
|
|
||||||
function increment_t_uint256(value) -> ret
|
|
||||||
{
|
|
||||||
if gt(value, not(1)) { revert(ret, ret) }
|
|
||||||
ret := add(value, 1)
|
|
||||||
}
|
|
||||||
function storage_array_index_access_t_array$_t_uint256_$dyn_storage(array, index) -> slot, offset
|
|
||||||
{
|
|
||||||
if iszero(lt(index, sload(array))) { invalid() }
|
|
||||||
mstore(slot, array)
|
|
||||||
slot := add(keccak256(slot, 0x20), index)
|
|
||||||
offset := offset
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,6 @@
|
|||||||
(import \"ethereum\" \"finish\" (func $eth.finish (param i32 i32)))
|
(import \"ethereum\" \"finish\" (func $eth.finish (param i32 i32)))
|
||||||
(memory $memory (export \"memory\") 1)
|
(memory $memory (export \"memory\") 1)
|
||||||
(export \"main\" (func $main))
|
(export \"main\" (func $main))
|
||||||
(global $global_ (mut i64) (i64.const 0))
|
|
||||||
(global $global__1 (mut i64) (i64.const 0))
|
|
||||||
(global $global__2 (mut i64) (i64.const 0))
|
|
||||||
|
|
||||||
(func $main
|
(func $main
|
||||||
(local $_1 i64)
|
(local $_1 i64)
|
||||||
@ -18,7 +15,6 @@
|
|||||||
(local $z1 i64)
|
(local $z1 i64)
|
||||||
(local $z2 i64)
|
(local $z2 i64)
|
||||||
(local $z3 i64)
|
(local $z3 i64)
|
||||||
(local $z4 i64)
|
|
||||||
(local $_3 i64)
|
(local $_3 i64)
|
||||||
(block $label_
|
(block $label_
|
||||||
(local.set $_1 (i64.const 0))
|
(local.set $_1 (i64.const 0))
|
||||||
@ -32,18 +28,14 @@
|
|||||||
(i64.store (i32.add (local.get $r) (i32.const 16)) (local.get $_2))
|
(i64.store (i32.add (local.get $r) (i32.const 16)) (local.get $_2))
|
||||||
(i64.store (i32.add (local.get $r) (i32.const 24)) (call $endian_swap (i64.const 128)))
|
(i64.store (i32.add (local.get $r) (i32.const 24)) (call $endian_swap (i64.const 128)))
|
||||||
(call $eth.getCallValue (i32.const 0))
|
(call $eth.getCallValue (i32.const 0))
|
||||||
(block
|
(local.set $z1 (call $endian_swap (i64.load (i32.const 0))))
|
||||||
(local.set $z1 (call $mload_internal (i32.const 0)))
|
(local.set $z2 (call $endian_swap (i64.load (i32.add (i32.const 0) (i32.const 8)))))
|
||||||
(local.set $z2 (global.get $global_))
|
(local.set $z3 (call $endian_swap (i64.load (i32.add (i32.const 0) (i32.const 16)))))
|
||||||
(local.set $z3 (global.get $global__1))
|
(if (i32.eqz (i64.eqz (i64.or (i64.or (local.get $z1) (local.get $z2)) (i64.or (local.get $z3) (call $endian_swap (i64.load (i32.add (i32.const 0) (i32.const 24)))))))) (then
|
||||||
(local.set $z4 (global.get $global__2))
|
(call $revert (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))))
|
||||||
|
|
||||||
)
|
|
||||||
(if (i32.eqz (i64.eqz (i64.or (i64.or (local.get $z1) (local.get $z2)) (i64.or (local.get $z3) (local.get $z4))))) (then
|
|
||||||
(call $eth.revert (call $to_internal_i32ptr (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1)) (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1)))))
|
|
||||||
(local.set $_3 (datasize \"C_2_deployed\"))
|
(local.set $_3 (datasize \"C_2_deployed\"))
|
||||||
(call $eth.codeCopy (call $to_internal_i32ptr (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1)) (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (dataoffset \"C_2_deployed\")) (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_3)))
|
(call $codecopy (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (dataoffset \"C_2_deployed\") (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_3))
|
||||||
(call $eth.finish (call $to_internal_i32ptr (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1)) (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_3)))
|
(call $return (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_3))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -54,7 +46,7 @@
|
|||||||
(param $x4 i64)
|
(param $x4 i64)
|
||||||
(result i32)
|
(result i32)
|
||||||
(local $v i32)
|
(local $v i32)
|
||||||
(block $label__3
|
(block $label__1
|
||||||
(if (i64.ne (i64.const 0) (i64.or (i64.or (local.get $x1) (local.get $x2)) (local.get $x3))) (then
|
(if (i64.ne (i64.const 0) (i64.or (i64.or (local.get $x1) (local.get $x2)) (local.get $x3))) (then
|
||||||
(unreachable)))
|
(unreachable)))
|
||||||
(if (i64.ne (i64.const 0) (i64.shr_u (local.get $x4) (i64.const 32))) (then
|
(if (i64.ne (i64.const 0) (i64.shr_u (local.get $x4) (i64.const 32))) (then
|
||||||
@ -73,7 +65,7 @@
|
|||||||
(result i32)
|
(result i32)
|
||||||
(local $r i32)
|
(local $r i32)
|
||||||
(local $p i32)
|
(local $p i32)
|
||||||
(block $label__4
|
(block $label__2
|
||||||
(local.set $p (call $u256_to_i32 (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4)))
|
(local.set $p (call $u256_to_i32 (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4)))
|
||||||
(local.set $r (i32.add (local.get $p) (i32.const 64)))
|
(local.set $r (i32.add (local.get $p) (i32.const 64)))
|
||||||
(if (i32.lt_u (local.get $r) (local.get $p)) (then
|
(if (i32.lt_u (local.get $r) (local.get $p)) (then
|
||||||
@ -83,11 +75,29 @@
|
|||||||
(local.get $r)
|
(local.get $r)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
(func $codecopy
|
||||||
|
(param $x1 i64)
|
||||||
|
(param $x2 i64)
|
||||||
|
(param $x3 i64)
|
||||||
|
(param $x4 i64)
|
||||||
|
(param $y1 i64)
|
||||||
|
(param $y2 i64)
|
||||||
|
(param $y3 i64)
|
||||||
|
(param $y4 i64)
|
||||||
|
(param $z1 i64)
|
||||||
|
(param $z2 i64)
|
||||||
|
(param $z3 i64)
|
||||||
|
(param $z4 i64)
|
||||||
|
(block $label__3
|
||||||
|
(call $eth.codeCopy (call $to_internal_i32ptr (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4)) (call $u256_to_i32 (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4)) (call $u256_to_i32 (local.get $z1) (local.get $z2) (local.get $z3) (local.get $z4)))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
(func $endian_swap_16
|
(func $endian_swap_16
|
||||||
(param $x i64)
|
(param $x i64)
|
||||||
(result i64)
|
(result i64)
|
||||||
(local $y i64)
|
(local $y i64)
|
||||||
(block $label__5
|
(block $label__4
|
||||||
(local.set $y (i64.or (i64.and (i64.shl (local.get $x) (i64.const 8)) (i64.const 65280)) (i64.and (i64.shr_u (local.get $x) (i64.const 8)) (i64.const 255))))
|
(local.set $y (i64.or (i64.and (i64.shl (local.get $x) (i64.const 8)) (i64.const 65280)) (i64.and (i64.shr_u (local.get $x) (i64.const 8)) (i64.const 255))))
|
||||||
|
|
||||||
)
|
)
|
||||||
@ -99,7 +109,7 @@
|
|||||||
(result i64)
|
(result i64)
|
||||||
(local $y i64)
|
(local $y i64)
|
||||||
(local $hi i64)
|
(local $hi i64)
|
||||||
(block $label__6
|
(block $label__5
|
||||||
(local.set $hi (i64.shl (call $endian_swap_16 (local.get $x)) (i64.const 16)))
|
(local.set $hi (i64.shl (call $endian_swap_16 (local.get $x)) (i64.const 16)))
|
||||||
(local.set $y (i64.or (local.get $hi) (call $endian_swap_16 (i64.shr_u (local.get $x) (i64.const 16)))))
|
(local.set $y (i64.or (local.get $hi) (call $endian_swap_16 (i64.shr_u (local.get $x) (i64.const 16)))))
|
||||||
|
|
||||||
@ -112,7 +122,7 @@
|
|||||||
(result i64)
|
(result i64)
|
||||||
(local $y i64)
|
(local $y i64)
|
||||||
(local $hi i64)
|
(local $hi i64)
|
||||||
(block $label__7
|
(block $label__6
|
||||||
(local.set $hi (i64.shl (call $endian_swap_32 (local.get $x)) (i64.const 32)))
|
(local.set $hi (i64.shl (call $endian_swap_32 (local.get $x)) (i64.const 32)))
|
||||||
(local.set $y (i64.or (local.get $hi) (call $endian_swap_32 (i64.shr_u (local.get $x) (i64.const 32)))))
|
(local.set $y (i64.or (local.get $hi) (call $endian_swap_32 (i64.shr_u (local.get $x) (i64.const 32)))))
|
||||||
|
|
||||||
@ -120,24 +130,32 @@
|
|||||||
(local.get $y)
|
(local.get $y)
|
||||||
)
|
)
|
||||||
|
|
||||||
(func $mload_internal
|
(func $return
|
||||||
(param $pos i32)
|
(param $x1 i64)
|
||||||
(result i64)
|
(param $x2 i64)
|
||||||
(local $z1 i64)
|
(param $x3 i64)
|
||||||
(local $z2 i64)
|
(param $x4 i64)
|
||||||
(local $z3 i64)
|
(param $y1 i64)
|
||||||
(local $z4 i64)
|
(param $y2 i64)
|
||||||
(block $label__8
|
(param $y3 i64)
|
||||||
(local.set $z1 (call $endian_swap (i64.load (local.get $pos))))
|
(param $y4 i64)
|
||||||
(local.set $z2 (call $endian_swap (i64.load (i32.add (local.get $pos) (i32.const 8)))))
|
(block $label__7
|
||||||
(local.set $z3 (call $endian_swap (i64.load (i32.add (local.get $pos) (i32.const 16)))))
|
(call $eth.finish (call $to_internal_i32ptr (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4)) (call $u256_to_i32 (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4)))
|
||||||
(local.set $z4 (call $endian_swap (i64.load (i32.add (local.get $pos) (i32.const 24)))))
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(func $revert
|
||||||
|
(param $x1 i64)
|
||||||
|
(param $x2 i64)
|
||||||
|
(param $x3 i64)
|
||||||
|
(param $x4 i64)
|
||||||
|
(param $y1 i64)
|
||||||
|
(param $y2 i64)
|
||||||
|
(param $y3 i64)
|
||||||
|
(param $y4 i64)
|
||||||
|
(block $label__8
|
||||||
|
(call $eth.revert (call $to_internal_i32ptr (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4)) (call $u256_to_i32 (local.get $y1) (local.get $y2) (local.get $y3) (local.get $y4)))
|
||||||
)
|
)
|
||||||
(global.set $global_ (local.get $z2))
|
|
||||||
(global.set $global__1 (local.get $z3))
|
|
||||||
(global.set $global__2 (local.get $z4))
|
|
||||||
(local.get $z1)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
)
|
)
|
||||||
|
@ -4,12 +4,6 @@
|
|||||||
Pretty printed source:
|
Pretty printed source:
|
||||||
object "object" {
|
object "object" {
|
||||||
code {
|
code {
|
||||||
{
|
|
||||||
let a3, b3, c3, d3, e3, f3, g3, h3, i3, j3, k3, l3, m3, o3, p3 := fun()
|
|
||||||
let a3_1, b3_1, c3_1, d3_1, e3_1, f3_1, g3_1, h3_1, i3_1, j3_1, k3_1, l3_1, m3_1, o3_1, p3_1 := fun()
|
|
||||||
sstore(a3, a3_1)
|
|
||||||
}
|
|
||||||
function fun() -> a3, b3, c3, d3, e3, f3, g3, h3, i3, j3, k3, l3, m3, o3, p3
|
|
||||||
{
|
{
|
||||||
let _1 := 1
|
let _1 := 1
|
||||||
sstore(_1, _1)
|
sstore(_1, _1)
|
||||||
@ -25,93 +19,29 @@ object "object" {
|
|||||||
sstore(11, _1)
|
sstore(11, _1)
|
||||||
sstore(12, _1)
|
sstore(12, _1)
|
||||||
sstore(13, _1)
|
sstore(13, _1)
|
||||||
a3 := _1
|
sstore(_1, _1)
|
||||||
b3 := _1
|
sstore(2, _1)
|
||||||
c3 := _1
|
sstore(3, _1)
|
||||||
d3 := _1
|
sstore(4, _1)
|
||||||
e3 := _1
|
sstore(5, _1)
|
||||||
f3 := _1
|
sstore(6, _1)
|
||||||
g3 := _1
|
sstore(7, _1)
|
||||||
h3 := _1
|
sstore(8, _1)
|
||||||
i3 := _1
|
sstore(9, _1)
|
||||||
j3 := _1
|
sstore(10, _1)
|
||||||
k3 := _1
|
sstore(11, _1)
|
||||||
l3 := _1
|
sstore(12, _1)
|
||||||
m3 := _1
|
sstore(13, _1)
|
||||||
o3 := _1
|
sstore(_1, _1)
|
||||||
p3 := _1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Binary representation:
|
Binary representation:
|
||||||
60056030565b505050505050505050505050505060196030565b5050505050505050505050505050808255505060c3565b6000600060006000600060006000600060006000600060006000600060006001808155806002558060035580600455806005558060065580600755806008558060095580600a5580600b5580600c5580600d55809f50809e50809d50809c50809b50809a50809950809850809750809650809550809450809350809250809150505b909192939495969798999a9b9c9d9e565b
|
6001808155806002558060035580600455806005558060065580600755806008558060095580600a5580600b5580600c5580600d55808155806002558060035580600455806005558060065580600755806008558060095580600a5580600b5580600c5580600d5580815550
|
||||||
|
|
||||||
Text representation:
|
Text representation:
|
||||||
/* "yul_stack_opt/input.sol":3:573 */
|
|
||||||
tag_1
|
|
||||||
tag_2
|
|
||||||
jump // in
|
|
||||||
tag_1:
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
tag_3
|
|
||||||
tag_2
|
|
||||||
jump // in
|
|
||||||
tag_3:
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
/* "yul_stack_opt/input.sol":740:742 */
|
|
||||||
dup1
|
|
||||||
/* "yul_stack_opt/input.sol":736:738 */
|
|
||||||
dup3
|
|
||||||
/* "yul_stack_opt/input.sol":729:743 */
|
|
||||||
sstore
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
/* "yul_stack_opt/input.sol":3:573 */
|
|
||||||
jump(tag_4)
|
|
||||||
tag_2:
|
|
||||||
0x00
|
|
||||||
0x00
|
|
||||||
0x00
|
|
||||||
0x00
|
|
||||||
0x00
|
|
||||||
0x00
|
|
||||||
0x00
|
|
||||||
0x00
|
|
||||||
0x00
|
|
||||||
0x00
|
|
||||||
0x00
|
|
||||||
0x00
|
|
||||||
0x00
|
|
||||||
0x00
|
|
||||||
0x00
|
|
||||||
/* "yul_stack_opt/input.sol":98:99 */
|
/* "yul_stack_opt/input.sol":98:99 */
|
||||||
0x01
|
0x01
|
||||||
dup1
|
dup1
|
||||||
@ -192,96 +122,84 @@ tag_2:
|
|||||||
sstore
|
sstore
|
||||||
/* "yul_stack_opt/input.sol":98:99 */
|
/* "yul_stack_opt/input.sol":98:99 */
|
||||||
dup1
|
dup1
|
||||||
/* "yul_stack_opt/input.sol":423:430 */
|
dup2
|
||||||
swap16
|
/* "yul_stack_opt/input.sol":129:141 */
|
||||||
pop
|
sstore
|
||||||
/* "yul_stack_opt/input.sol":98:99 */
|
/* "yul_stack_opt/input.sol":98:99 */
|
||||||
dup1
|
dup1
|
||||||
/* "yul_stack_opt/input.sol":433:440 */
|
/* "yul_stack_opt/input.sol":151:160 */
|
||||||
swap15
|
0x02
|
||||||
pop
|
/* "yul_stack_opt/input.sol":144:164 */
|
||||||
|
sstore
|
||||||
/* "yul_stack_opt/input.sol":98:99 */
|
/* "yul_stack_opt/input.sol":98:99 */
|
||||||
dup1
|
dup1
|
||||||
/* "yul_stack_opt/input.sol":443:450 */
|
/* "yul_stack_opt/input.sol":174:183 */
|
||||||
swap14
|
0x03
|
||||||
pop
|
/* "yul_stack_opt/input.sol":167:187 */
|
||||||
|
sstore
|
||||||
/* "yul_stack_opt/input.sol":98:99 */
|
/* "yul_stack_opt/input.sol":98:99 */
|
||||||
dup1
|
dup1
|
||||||
/* "yul_stack_opt/input.sol":453:460 */
|
/* "yul_stack_opt/input.sol":197:206 */
|
||||||
swap13
|
0x04
|
||||||
pop
|
/* "yul_stack_opt/input.sol":190:210 */
|
||||||
|
sstore
|
||||||
/* "yul_stack_opt/input.sol":98:99 */
|
/* "yul_stack_opt/input.sol":98:99 */
|
||||||
dup1
|
dup1
|
||||||
/* "yul_stack_opt/input.sol":463:470 */
|
/* "yul_stack_opt/input.sol":220:229 */
|
||||||
swap12
|
0x05
|
||||||
pop
|
/* "yul_stack_opt/input.sol":213:233 */
|
||||||
|
sstore
|
||||||
/* "yul_stack_opt/input.sol":98:99 */
|
/* "yul_stack_opt/input.sol":98:99 */
|
||||||
dup1
|
dup1
|
||||||
/* "yul_stack_opt/input.sol":473:480 */
|
/* "yul_stack_opt/input.sol":243:252 */
|
||||||
swap11
|
0x06
|
||||||
pop
|
/* "yul_stack_opt/input.sol":236:256 */
|
||||||
|
sstore
|
||||||
/* "yul_stack_opt/input.sol":98:99 */
|
/* "yul_stack_opt/input.sol":98:99 */
|
||||||
dup1
|
dup1
|
||||||
/* "yul_stack_opt/input.sol":483:490 */
|
/* "yul_stack_opt/input.sol":266:275 */
|
||||||
swap10
|
0x07
|
||||||
pop
|
/* "yul_stack_opt/input.sol":259:279 */
|
||||||
|
sstore
|
||||||
/* "yul_stack_opt/input.sol":98:99 */
|
/* "yul_stack_opt/input.sol":98:99 */
|
||||||
dup1
|
dup1
|
||||||
/* "yul_stack_opt/input.sol":493:500 */
|
/* "yul_stack_opt/input.sol":289:298 */
|
||||||
swap9
|
0x08
|
||||||
pop
|
/* "yul_stack_opt/input.sol":282:302 */
|
||||||
|
sstore
|
||||||
/* "yul_stack_opt/input.sol":98:99 */
|
/* "yul_stack_opt/input.sol":98:99 */
|
||||||
dup1
|
dup1
|
||||||
/* "yul_stack_opt/input.sol":503:510 */
|
/* "yul_stack_opt/input.sol":312:321 */
|
||||||
swap8
|
0x09
|
||||||
pop
|
/* "yul_stack_opt/input.sol":305:325 */
|
||||||
|
sstore
|
||||||
/* "yul_stack_opt/input.sol":98:99 */
|
/* "yul_stack_opt/input.sol":98:99 */
|
||||||
dup1
|
dup1
|
||||||
/* "yul_stack_opt/input.sol":513:520 */
|
/* "yul_stack_opt/input.sol":335:344 */
|
||||||
swap7
|
0x0a
|
||||||
pop
|
/* "yul_stack_opt/input.sol":328:348 */
|
||||||
|
sstore
|
||||||
/* "yul_stack_opt/input.sol":98:99 */
|
/* "yul_stack_opt/input.sol":98:99 */
|
||||||
dup1
|
dup1
|
||||||
/* "yul_stack_opt/input.sol":523:530 */
|
/* "yul_stack_opt/input.sol":358:368 */
|
||||||
swap6
|
0x0b
|
||||||
pop
|
/* "yul_stack_opt/input.sol":351:372 */
|
||||||
|
sstore
|
||||||
/* "yul_stack_opt/input.sol":98:99 */
|
/* "yul_stack_opt/input.sol":98:99 */
|
||||||
dup1
|
dup1
|
||||||
/* "yul_stack_opt/input.sol":533:540 */
|
/* "yul_stack_opt/input.sol":382:392 */
|
||||||
swap5
|
0x0c
|
||||||
pop
|
/* "yul_stack_opt/input.sol":375:396 */
|
||||||
|
sstore
|
||||||
/* "yul_stack_opt/input.sol":98:99 */
|
/* "yul_stack_opt/input.sol":98:99 */
|
||||||
dup1
|
dup1
|
||||||
/* "yul_stack_opt/input.sol":543:550 */
|
/* "yul_stack_opt/input.sol":406:416 */
|
||||||
swap4
|
0x0d
|
||||||
pop
|
/* "yul_stack_opt/input.sol":399:420 */
|
||||||
|
sstore
|
||||||
/* "yul_stack_opt/input.sol":98:99 */
|
/* "yul_stack_opt/input.sol":98:99 */
|
||||||
dup1
|
dup1
|
||||||
/* "yul_stack_opt/input.sol":553:560 */
|
dup2
|
||||||
swap3
|
/* "yul_stack_opt/input.sol":729:743 */
|
||||||
|
sstore
|
||||||
pop
|
pop
|
||||||
/* "yul_stack_opt/input.sol":98:99 */
|
|
||||||
dup1
|
|
||||||
/* "yul_stack_opt/input.sol":563:570 */
|
|
||||||
swap2
|
|
||||||
pop
|
|
||||||
pop
|
|
||||||
/* "yul_stack_opt/input.sol":85:573 */
|
|
||||||
tag_5:
|
|
||||||
swap1
|
|
||||||
swap2
|
|
||||||
swap3
|
|
||||||
swap4
|
|
||||||
swap5
|
|
||||||
swap6
|
|
||||||
swap7
|
|
||||||
swap8
|
|
||||||
swap9
|
|
||||||
swap10
|
|
||||||
swap11
|
|
||||||
swap12
|
|
||||||
swap13
|
|
||||||
swap14
|
|
||||||
swap15
|
|
||||||
jump // out
|
|
||||||
tag_4:
|
|
||||||
|
@ -417,7 +417,7 @@ BOOST_AUTO_TEST_CASE(auction_simple)
|
|||||||
BOOST_CHECK_EQUAL(registrar.owner(name), 0);
|
BOOST_CHECK_EQUAL(registrar.owner(name), 0);
|
||||||
// "wait" until auction end
|
// "wait" until auction end
|
||||||
|
|
||||||
m_evmHost->tx_context.block_timestamp += m_biddingTime + 10;
|
m_evmcHost->tx_context.block_timestamp += m_biddingTime + 10;
|
||||||
// trigger auction again
|
// trigger auction again
|
||||||
registrar.reserve(name);
|
registrar.reserve(name);
|
||||||
BOOST_CHECK_EQUAL(registrar.owner(name), m_sender);
|
BOOST_CHECK_EQUAL(registrar.owner(name), m_sender);
|
||||||
@ -429,7 +429,7 @@ BOOST_AUTO_TEST_CASE(auction_bidding)
|
|||||||
string name = "x";
|
string name = "x";
|
||||||
|
|
||||||
unsigned startTime = 0x776347e2;
|
unsigned startTime = 0x776347e2;
|
||||||
m_evmHost->tx_context.block_timestamp = startTime;
|
m_evmcHost->tx_context.block_timestamp = startTime;
|
||||||
|
|
||||||
RegistrarInterface registrar(*this);
|
RegistrarInterface registrar(*this);
|
||||||
// initiate auction
|
// initiate auction
|
||||||
@ -437,19 +437,19 @@ BOOST_AUTO_TEST_CASE(auction_bidding)
|
|||||||
registrar.reserve(name);
|
registrar.reserve(name);
|
||||||
BOOST_CHECK_EQUAL(registrar.owner(name), 0);
|
BOOST_CHECK_EQUAL(registrar.owner(name), 0);
|
||||||
// overbid self
|
// overbid self
|
||||||
m_evmHost->tx_context.block_timestamp = startTime + m_biddingTime - 10;
|
m_evmcHost->tx_context.block_timestamp = startTime + m_biddingTime - 10;
|
||||||
registrar.setNextValue(12);
|
registrar.setNextValue(12);
|
||||||
registrar.reserve(name);
|
registrar.reserve(name);
|
||||||
// another bid by someone else
|
// another bid by someone else
|
||||||
sendEther(account(1), 10 * ether);
|
sendEther(account(1), 10 * ether);
|
||||||
m_sender = account(1);
|
m_sender = account(1);
|
||||||
m_evmHost->tx_context.block_timestamp = startTime + 2 * m_biddingTime - 50;
|
m_evmcHost->tx_context.block_timestamp = startTime + 2 * m_biddingTime - 50;
|
||||||
registrar.setNextValue(13);
|
registrar.setNextValue(13);
|
||||||
registrar.reserve(name);
|
registrar.reserve(name);
|
||||||
BOOST_CHECK_EQUAL(registrar.owner(name), 0);
|
BOOST_CHECK_EQUAL(registrar.owner(name), 0);
|
||||||
// end auction by first bidder (which is not highest) trying to overbid again (too late)
|
// end auction by first bidder (which is not highest) trying to overbid again (too late)
|
||||||
m_sender = account(0);
|
m_sender = account(0);
|
||||||
m_evmHost->tx_context.block_timestamp = startTime + 4 * m_biddingTime;
|
m_evmcHost->tx_context.block_timestamp = startTime + 4 * m_biddingTime;
|
||||||
registrar.setNextValue(20);
|
registrar.setNextValue(20);
|
||||||
registrar.reserve(name);
|
registrar.reserve(name);
|
||||||
BOOST_CHECK_EQUAL(registrar.owner(name), account(1));
|
BOOST_CHECK_EQUAL(registrar.owner(name), account(1));
|
||||||
|
@ -48,6 +48,7 @@ function solcjs_test
|
|||||||
|
|
||||||
printLog "Copying SMTChecker tests..."
|
printLog "Copying SMTChecker tests..."
|
||||||
cp -Rf "$TEST_DIR"/test/libsolidity/smtCheckerTests test/
|
cp -Rf "$TEST_DIR"/test/libsolidity/smtCheckerTests test/
|
||||||
|
rm -rf test/smtCheckerTests/imports
|
||||||
|
|
||||||
# Update version (needed for some tests)
|
# Update version (needed for some tests)
|
||||||
echo "Updating package.json to version $VERSION"
|
echo "Updating package.json to version $VERSION"
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include <libsolidity/parsing/Parser.h>
|
#include <libsolidity/parsing/Parser.h>
|
||||||
#include <libsolidity/analysis/DeclarationTypeChecker.h>
|
#include <libsolidity/analysis/DeclarationTypeChecker.h>
|
||||||
#include <libsolidity/analysis/NameAndTypeResolver.h>
|
#include <libsolidity/analysis/NameAndTypeResolver.h>
|
||||||
|
#include <libsolidity/analysis/Scoper.h>
|
||||||
#include <libsolidity/codegen/Compiler.h>
|
#include <libsolidity/codegen/Compiler.h>
|
||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
#include <libsolidity/analysis/TypeChecker.h>
|
#include <libsolidity/analysis/TypeChecker.h>
|
||||||
@ -59,6 +60,7 @@ evmasm::AssemblyItems compileContract(std::shared_ptr<CharStream> _sourceCode)
|
|||||||
BOOST_REQUIRE_NO_THROW(sourceUnit = parser.parse(make_shared<Scanner>(_sourceCode)));
|
BOOST_REQUIRE_NO_THROW(sourceUnit = parser.parse(make_shared<Scanner>(_sourceCode)));
|
||||||
BOOST_CHECK(!!sourceUnit);
|
BOOST_CHECK(!!sourceUnit);
|
||||||
|
|
||||||
|
Scoper::assignScopes(*sourceUnit);
|
||||||
GlobalContext globalContext;
|
GlobalContext globalContext;
|
||||||
NameAndTypeResolver resolver(globalContext, solidity::test::CommonOptions::get().evmVersion(), errorReporter);
|
NameAndTypeResolver resolver(globalContext, solidity::test::CommonOptions::get().evmVersion(), errorReporter);
|
||||||
DeclarationTypeChecker declarationTypeChecker(errorReporter, solidity::test::CommonOptions::get().evmVersion());
|
DeclarationTypeChecker declarationTypeChecker(errorReporter, solidity::test::CommonOptions::get().evmVersion());
|
||||||
|
@ -39,8 +39,8 @@ using namespace boost::unit_test;
|
|||||||
namespace fs = boost::filesystem;
|
namespace fs = boost::filesystem;
|
||||||
|
|
||||||
|
|
||||||
SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVersion, bool enforceViaYul):
|
SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVersion, vector<boost::filesystem::path> const& _vmPaths, bool enforceViaYul):
|
||||||
SolidityExecutionFramework(_evmVersion),
|
SolidityExecutionFramework(_evmVersion, _vmPaths),
|
||||||
EVMVersionRestrictedTestCase(_filename),
|
EVMVersionRestrictedTestCase(_filename),
|
||||||
m_sources(m_reader.sources()),
|
m_sources(m_reader.sources()),
|
||||||
m_lineOffset(m_reader.lineNumber()),
|
m_lineOffset(m_reader.lineNumber()),
|
||||||
@ -72,6 +72,21 @@ SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVer
|
|||||||
else
|
else
|
||||||
BOOST_THROW_EXCEPTION(runtime_error("Invalid compileViaYul value: " + choice + "."));
|
BOOST_THROW_EXCEPTION(runtime_error("Invalid compileViaYul value: " + choice + "."));
|
||||||
|
|
||||||
|
string compileToEwasm = m_reader.stringSetting("compileToEwasm", "false");
|
||||||
|
if (compileToEwasm == "also")
|
||||||
|
m_runWithEwasm = true;
|
||||||
|
else if (compileToEwasm == "false")
|
||||||
|
m_runWithEwasm = false;
|
||||||
|
else
|
||||||
|
BOOST_THROW_EXCEPTION(runtime_error("Invalid compileToEwasm value: " + compileToEwasm + "."));
|
||||||
|
|
||||||
|
if (m_runWithEwasm && !m_runWithYul)
|
||||||
|
BOOST_THROW_EXCEPTION(runtime_error("Invalid compileToEwasm value: " + compileToEwasm + ", compileViaYul need to be enabled."));
|
||||||
|
|
||||||
|
// run ewasm tests only, if an ewasm evmc vm was defined
|
||||||
|
if (m_runWithEwasm && !m_supportsEwasm)
|
||||||
|
m_runWithEwasm = false;
|
||||||
|
|
||||||
m_runWithABIEncoderV1Only = m_reader.boolSetting("ABIEncoderV1Only", false);
|
m_runWithABIEncoderV1Only = m_reader.boolSetting("ABIEncoderV1Only", false);
|
||||||
if (m_runWithABIEncoderV1Only && solidity::test::CommonOptions::get().useABIEncoderV2)
|
if (m_runWithABIEncoderV1Only && solidity::test::CommonOptions::get().useABIEncoderV2)
|
||||||
m_shouldRun = false;
|
m_shouldRun = false;
|
||||||
@ -88,156 +103,180 @@ SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVer
|
|||||||
|
|
||||||
TestCase::TestResult SemanticTest::run(ostream& _stream, string const& _linePrefix, bool _formatted)
|
TestCase::TestResult SemanticTest::run(ostream& _stream, string const& _linePrefix, bool _formatted)
|
||||||
{
|
{
|
||||||
|
TestResult result = TestResult::Success;
|
||||||
|
bool compileViaYul = m_runWithYul || m_enforceViaYul;
|
||||||
|
|
||||||
for (bool compileViaYul: set<bool>{!m_runWithoutYul, m_runWithYul || m_enforceViaYul})
|
if (m_runWithoutYul)
|
||||||
|
result = runTest(_stream, _linePrefix, _formatted, false, false);
|
||||||
|
|
||||||
|
if (compileViaYul && result == TestResult::Success)
|
||||||
|
result = runTest(_stream, _linePrefix, _formatted, true, false);
|
||||||
|
|
||||||
|
if (m_runWithEwasm && result == TestResult::Success)
|
||||||
|
result = runTest(_stream, _linePrefix, _formatted, true, true);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestCase::TestResult SemanticTest::runTest(ostream& _stream, string const& _linePrefix, bool _formatted, bool _compileViaYul, bool _compileToEwasm)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
try
|
bool success = true;
|
||||||
|
|
||||||
|
if (_compileViaYul && _compileToEwasm)
|
||||||
|
selectVM(evmc_capabilities::EVMC_CAPABILITY_EWASM);
|
||||||
|
else
|
||||||
|
selectVM(evmc_capabilities::EVMC_CAPABILITY_EVM1);
|
||||||
|
|
||||||
|
reset();
|
||||||
|
|
||||||
|
m_compileViaYul = _compileViaYul;
|
||||||
|
if (_compileToEwasm)
|
||||||
{
|
{
|
||||||
reset();
|
soltestAssert(m_compileViaYul, "");
|
||||||
bool success = true;
|
m_compileToEwasm = _compileToEwasm;
|
||||||
|
}
|
||||||
|
|
||||||
m_compileViaYul = compileViaYul;
|
m_compileViaYulCanBeSet = false;
|
||||||
m_compileViaYulCanBeSet = false;
|
|
||||||
|
|
||||||
if (compileViaYul)
|
if (_compileViaYul)
|
||||||
AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Running via Yul:" << endl;
|
AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Running via Yul:" << endl;
|
||||||
|
|
||||||
for (auto& test: m_tests)
|
for (auto& test: m_tests)
|
||||||
test.reset();
|
test.reset();
|
||||||
|
|
||||||
map<string, solidity::test::Address> libraries;
|
map<string, solidity::test::Address> libraries;
|
||||||
|
|
||||||
bool constructed = false;
|
bool constructed = false;
|
||||||
|
|
||||||
for (auto& test: m_tests)
|
for (auto& test: m_tests)
|
||||||
|
{
|
||||||
|
if (constructed)
|
||||||
{
|
{
|
||||||
if (constructed)
|
soltestAssert(!test.call().isLibrary, "Libraries have to be deployed before any other call.");
|
||||||
{
|
soltestAssert(
|
||||||
soltestAssert(!test.call().isLibrary, "Libraries have to be deployed before any other call.");
|
!test.call().isConstructor,
|
||||||
soltestAssert(!test.call().isConstructor, "Constructor has to be the first function call expect for library deployments.");
|
"Constructor has to be the first function call expect for library deployments.");
|
||||||
}
|
}
|
||||||
else if (test.call().isLibrary)
|
else if (test.call().isLibrary)
|
||||||
|
{
|
||||||
|
soltestAssert(
|
||||||
|
deploy(test.call().signature, 0, {}, libraries) && m_transactionSuccessful,
|
||||||
|
"Failed to deploy library " + test.call().signature);
|
||||||
|
libraries[test.call().signature] = m_contractAddress;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (test.call().isConstructor)
|
||||||
|
deploy("", test.call().value.value, test.call().arguments.rawBytes(), libraries);
|
||||||
|
else
|
||||||
|
soltestAssert(deploy("", 0, bytes(), libraries), "Failed to deploy contract.");
|
||||||
|
constructed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (test.call().isConstructor)
|
||||||
|
{
|
||||||
|
if (m_transactionSuccessful == test.call().expectations.failure)
|
||||||
|
success = false;
|
||||||
|
|
||||||
|
test.setFailure(!m_transactionSuccessful);
|
||||||
|
test.setRawBytes(bytes());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bytes output;
|
||||||
|
if (test.call().useCallWithoutSignature)
|
||||||
|
output = callLowLevel(test.call().arguments.rawBytes(), test.call().value.value);
|
||||||
|
else
|
||||||
{
|
{
|
||||||
soltestAssert(
|
soltestAssert(
|
||||||
deploy(test.call().signature, 0, {}, libraries) && m_transactionSuccessful,
|
m_allowNonExistingFunctions || m_compiler.methodIdentifiers(m_compiler.lastContractName())
|
||||||
"Failed to deploy library " + test.call().signature
|
.isMember(test.call().signature),
|
||||||
|
"The function " + test.call().signature + " is not known to the compiler");
|
||||||
|
|
||||||
|
output = callContractFunctionWithValueNoEncoding(
|
||||||
|
test.call().signature, test.call().value.value, test.call().arguments.rawBytes()
|
||||||
);
|
);
|
||||||
libraries[test.call().signature] = m_contractAddress;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (test.call().isConstructor)
|
|
||||||
deploy("", test.call().value.value, test.call().arguments.rawBytes(), libraries);
|
|
||||||
else
|
|
||||||
soltestAssert(deploy("", 0, bytes(), libraries), "Failed to deploy contract.");
|
|
||||||
constructed = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (test.call().isConstructor)
|
if ((m_transactionSuccessful == test.call().expectations.failure)
|
||||||
{
|
|| (output != test.call().expectations.rawBytes()))
|
||||||
if (m_transactionSuccessful == test.call().expectations.failure)
|
success = false;
|
||||||
success = false;
|
|
||||||
|
|
||||||
test.setFailure(!m_transactionSuccessful);
|
test.setFailure(!m_transactionSuccessful);
|
||||||
test.setRawBytes(bytes());
|
test.setRawBytes(std::move(output));
|
||||||
}
|
test.setContractABI(m_compiler.contractABI(m_compiler.lastContractName()));
|
||||||
else
|
|
||||||
{
|
|
||||||
bytes output;
|
|
||||||
if (test.call().useCallWithoutSignature)
|
|
||||||
output = callLowLevel(test.call().arguments.rawBytes(), test.call().value.value);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
soltestAssert(
|
|
||||||
m_allowNonExistingFunctions || m_compiler.methodIdentifiers(m_compiler.lastContractName()).isMember(test.call().signature),
|
|
||||||
"The function " + test.call().signature + " is not known to the compiler"
|
|
||||||
);
|
|
||||||
|
|
||||||
output = callContractFunctionWithValueNoEncoding(
|
|
||||||
test.call().signature,
|
|
||||||
test.call().value.value,
|
|
||||||
test.call().arguments.rawBytes()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((m_transactionSuccessful == test.call().expectations.failure) || (output != test.call().expectations.rawBytes()))
|
|
||||||
success = false;
|
|
||||||
|
|
||||||
test.setFailure(!m_transactionSuccessful);
|
|
||||||
test.setRawBytes(std::move(output));
|
|
||||||
test.setContractABI(m_compiler.contractABI(m_compiler.lastContractName()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (success && !m_runWithYul && compileViaYul)
|
if (success && !m_runWithYul && _compileViaYul)
|
||||||
|
{
|
||||||
|
m_compileViaYulCanBeSet = true;
|
||||||
|
AnsiColorized(_stream, _formatted, {BOLD, YELLOW}) <<
|
||||||
|
_linePrefix << endl <<
|
||||||
|
_linePrefix << "Test can pass via Yul and marked with compileViaYul: false." << endl;
|
||||||
|
return TestResult::Failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success && (m_runWithYul || !_compileViaYul))
|
||||||
|
{
|
||||||
|
AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Expected result:" << endl;
|
||||||
|
for (auto const& test: m_tests)
|
||||||
{
|
{
|
||||||
m_compileViaYulCanBeSet = true;
|
ErrorReporter errorReporter;
|
||||||
AnsiColorized(_stream, _formatted, {BOLD, YELLOW}) << _linePrefix << endl << _linePrefix
|
_stream << test.format(errorReporter, _linePrefix, false, _formatted) << endl;
|
||||||
<< "Test can pass via Yul and marked with compileViaYul: false." << endl;
|
_stream << errorReporter.format(_linePrefix, _formatted);
|
||||||
return TestResult::Failure;
|
|
||||||
}
|
}
|
||||||
|
_stream << endl;
|
||||||
if (!success && (m_runWithYul || !compileViaYul))
|
AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Obtained result:" << endl;
|
||||||
|
for (auto const& test: m_tests)
|
||||||
{
|
{
|
||||||
AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Expected result:" << endl;
|
ErrorReporter errorReporter;
|
||||||
for (auto const& test: m_tests)
|
_stream << test.format(errorReporter, _linePrefix, true, _formatted) << endl;
|
||||||
{
|
_stream << errorReporter.format(_linePrefix, _formatted);
|
||||||
ErrorReporter errorReporter;
|
}
|
||||||
_stream << test.format(errorReporter, _linePrefix, false, _formatted) << endl;
|
AnsiColorized(_stream, _formatted, {BOLD, RED})
|
||||||
_stream << errorReporter.format(_linePrefix, _formatted);
|
<< _linePrefix << endl
|
||||||
}
|
<< _linePrefix << "Attention: Updates on the test will apply the detected format displayed." << endl;
|
||||||
|
if (_compileViaYul && m_runWithoutYul)
|
||||||
|
{
|
||||||
|
_stream << _linePrefix << endl << _linePrefix;
|
||||||
|
AnsiColorized(_stream, _formatted, {RED_BACKGROUND}) << "Note that the test passed without Yul.";
|
||||||
_stream << endl;
|
_stream << endl;
|
||||||
AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Obtained result:" << endl;
|
|
||||||
for (auto const& test: m_tests)
|
|
||||||
{
|
|
||||||
ErrorReporter errorReporter;
|
|
||||||
_stream << test.format(errorReporter, _linePrefix, true, _formatted) << endl;
|
|
||||||
_stream << errorReporter.format(_linePrefix, _formatted);
|
|
||||||
}
|
|
||||||
AnsiColorized(_stream, _formatted, {BOLD, RED}) << _linePrefix << endl << _linePrefix
|
|
||||||
<< "Attention: Updates on the test will apply the detected format displayed." << endl;
|
|
||||||
if (compileViaYul && m_runWithoutYul)
|
|
||||||
{
|
|
||||||
_stream << _linePrefix << endl << _linePrefix;
|
|
||||||
AnsiColorized(_stream, _formatted, {RED_BACKGROUND})
|
|
||||||
<< "Note that the test passed without Yul.";
|
|
||||||
_stream << endl;
|
|
||||||
}
|
|
||||||
else if (!compileViaYul && m_runWithYul)
|
|
||||||
AnsiColorized(_stream, _formatted, {BOLD, YELLOW}) << _linePrefix << endl << _linePrefix
|
|
||||||
<< "Note that the test also has to pass via Yul." << endl;
|
|
||||||
return TestResult::Failure;
|
|
||||||
}
|
}
|
||||||
|
else if (!_compileViaYul && m_runWithYul)
|
||||||
|
AnsiColorized(_stream, _formatted, {BOLD, YELLOW})
|
||||||
|
<< _linePrefix << endl
|
||||||
|
<< _linePrefix << "Note that the test also has to pass via Yul." << endl;
|
||||||
|
return TestResult::Failure;
|
||||||
}
|
}
|
||||||
catch (WhiskersError const&)
|
}
|
||||||
{
|
catch (WhiskersError const&)
|
||||||
// this is an error in Whiskers template, so should be thrown anyway
|
{
|
||||||
|
// this is an error in Whiskers template, so should be thrown anyway
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (YulException const&)
|
||||||
|
{
|
||||||
|
// this should be an error in yul compilation or translation
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (boost::exception const&)
|
||||||
|
{
|
||||||
|
if (!_compileViaYul || m_runWithYul)
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
catch (YulException const&)
|
catch (std::exception const&)
|
||||||
{
|
{
|
||||||
// this should be an error in yul compilation or translation
|
if (!_compileViaYul || m_runWithYul)
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
catch (boost::exception const&)
|
catch (...)
|
||||||
{
|
{
|
||||||
if (compileViaYul && !m_runWithYul)
|
if (!_compileViaYul || m_runWithYul)
|
||||||
continue;
|
|
||||||
throw;
|
throw;
|
||||||
}
|
|
||||||
catch (std::exception const&)
|
|
||||||
{
|
|
||||||
if (compileViaYul && !m_runWithYul)
|
|
||||||
continue;
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
if (compileViaYul && !m_runWithYul)
|
|
||||||
continue;
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return TestResult::Success;
|
return TestResult::Success;
|
||||||
|
@ -40,9 +40,9 @@ class SemanticTest: public SolidityExecutionFramework, public EVMVersionRestrict
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static std::unique_ptr<TestCase> create(Config const& _options)
|
static std::unique_ptr<TestCase> create(Config const& _options)
|
||||||
{ return std::make_unique<SemanticTest>(_options.filename, _options.evmVersion, _options.enforceCompileViaYul); }
|
{ return std::make_unique<SemanticTest>(_options.filename, _options.evmVersion, _options.vmPaths, _options.enforceCompileViaYul); }
|
||||||
|
|
||||||
explicit SemanticTest(std::string const& _filename, langutil::EVMVersion _evmVersion, bool _enforceViaYul = false);
|
explicit SemanticTest(std::string const& _filename, langutil::EVMVersion _evmVersion, std::vector<boost::filesystem::path> const& _vmPaths, bool _enforceViaYul = false);
|
||||||
|
|
||||||
TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool _formatted = false) override;
|
TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool _formatted = false) override;
|
||||||
void printSource(std::ostream &_stream, std::string const& _linePrefix = "", bool _formatted = false) const override;
|
void printSource(std::ostream &_stream, std::string const& _linePrefix = "", bool _formatted = false) const override;
|
||||||
@ -59,10 +59,12 @@ public:
|
|||||||
/// Returns true if deployment was successful, false otherwise.
|
/// Returns true if deployment was successful, false otherwise.
|
||||||
bool deploy(std::string const& _contractName, u256 const& _value, bytes const& _arguments, std::map<std::string, solidity::test::Address> const& _libraries = {});
|
bool deploy(std::string const& _contractName, u256 const& _value, bytes const& _arguments, std::map<std::string, solidity::test::Address> const& _libraries = {});
|
||||||
private:
|
private:
|
||||||
|
TestResult runTest(std::ostream& _stream, std::string const& _linePrefix, bool _formatted, bool _compileViaYul, bool _compileToEwasm);
|
||||||
SourceMap m_sources;
|
SourceMap m_sources;
|
||||||
std::size_t m_lineOffset;
|
std::size_t m_lineOffset;
|
||||||
std::vector<TestFunctionCall> m_tests;
|
std::vector<TestFunctionCall> m_tests;
|
||||||
bool m_runWithYul = false;
|
bool m_runWithYul = false;
|
||||||
|
bool m_runWithEwasm = false;
|
||||||
bool m_runWithoutYul = true;
|
bool m_runWithoutYul = true;
|
||||||
bool m_enforceViaYul = false;
|
bool m_enforceViaYul = false;
|
||||||
bool m_runWithABIEncoderV1Only = false;
|
bool m_runWithABIEncoderV1Only = false;
|
||||||
|
@ -48,18 +48,38 @@ using namespace solidity::util;
|
|||||||
using namespace solidity::test;
|
using namespace solidity::test;
|
||||||
using namespace solidity::langutil;
|
using namespace solidity::langutil;
|
||||||
|
|
||||||
#define ALSO_VIA_YUL(CODE) \
|
#define ALSO_VIA_YUL(CODE) \
|
||||||
{ \
|
{ \
|
||||||
{ CODE } \
|
m_doEwasmTestrun = true; \
|
||||||
reset(); \
|
\
|
||||||
m_compileViaYul = true; \
|
m_compileViaYul = false; \
|
||||||
{ CODE } \
|
m_compileToEwasm = false; \
|
||||||
|
{ CODE } \
|
||||||
|
\
|
||||||
|
m_compileViaYul = true; \
|
||||||
|
reset(); \
|
||||||
|
{ CODE } \
|
||||||
|
\
|
||||||
|
if (m_doEwasmTestrun) \
|
||||||
|
{ \
|
||||||
|
m_compileToEwasm = true; \
|
||||||
|
reset(); \
|
||||||
|
{ CODE } \
|
||||||
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define DISABLE_EWASM_TESTRUN() \
|
||||||
|
{ m_doEwasmTestrun = false; }
|
||||||
|
|
||||||
namespace solidity::frontend::test
|
namespace solidity::frontend::test
|
||||||
{
|
{
|
||||||
|
|
||||||
BOOST_FIXTURE_TEST_SUITE(SolidityEndToEndTest, SolidityExecutionFramework)
|
struct SolidityEndToEndTestExecutionFramework: public SolidityExecutionFramework
|
||||||
|
{
|
||||||
|
bool m_doEwasmTestrun = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_SUITE(SolidityEndToEndTest, SolidityEndToEndTestExecutionFramework)
|
||||||
|
|
||||||
int constexpr roundTo32(int _num)
|
int constexpr roundTo32(int _num)
|
||||||
{
|
{
|
||||||
@ -115,6 +135,8 @@ BOOST_AUTO_TEST_CASE(recursive_calls)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
function<u256(u256)> recursive_calls_cpp = [&recursive_calls_cpp](u256 const& n) -> u256
|
function<u256(u256)> recursive_calls_cpp = [&recursive_calls_cpp](u256 const& n) -> u256
|
||||||
{
|
{
|
||||||
@ -140,6 +162,8 @@ BOOST_AUTO_TEST_CASE(while_loop)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
|
|
||||||
auto while_loop_cpp = [](u256 const& n) -> u256
|
auto while_loop_cpp = [](u256 const& n) -> u256
|
||||||
@ -168,6 +192,8 @@ BOOST_AUTO_TEST_CASE(do_while_loop)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
|
|
||||||
auto do_while_loop_cpp = [](u256 const& n) -> u256
|
auto do_while_loop_cpp = [](u256 const& n) -> u256
|
||||||
@ -213,6 +239,8 @@ BOOST_AUTO_TEST_CASE(do_while_loop_multiple_local_vars)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
|
|
||||||
auto do_while = [](u256 n) -> u256
|
auto do_while = [](u256 n) -> u256
|
||||||
@ -263,6 +291,8 @@ BOOST_AUTO_TEST_CASE(nested_loops)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
|
|
||||||
auto nested_loops_cpp = [](u256 n) -> u256
|
auto nested_loops_cpp = [](u256 n) -> u256
|
||||||
@ -329,6 +359,8 @@ BOOST_AUTO_TEST_CASE(nested_loops_multiple_local_vars)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
|
|
||||||
auto nested_loops_cpp = [](u256 n) -> u256
|
auto nested_loops_cpp = [](u256 n) -> u256
|
||||||
@ -383,6 +415,8 @@ BOOST_AUTO_TEST_CASE(for_loop_multiple_local_vars)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
|
|
||||||
auto for_loop = [](u256 n) -> u256
|
auto for_loop = [](u256 n) -> u256
|
||||||
@ -444,6 +478,8 @@ BOOST_AUTO_TEST_CASE(nested_for_loop_multiple_local_vars)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
|
|
||||||
auto for_loop = [](u256 n) -> u256
|
auto for_loop = [](u256 n) -> u256
|
||||||
@ -484,6 +520,8 @@ BOOST_AUTO_TEST_CASE(for_loop)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
|
|
||||||
auto for_loop_cpp = [](u256 const& n) -> u256
|
auto for_loop_cpp = [](u256 const& n) -> u256
|
||||||
@ -512,6 +550,8 @@ BOOST_AUTO_TEST_CASE(for_loop_empty)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
|
|
||||||
auto for_loop_empty_cpp = []() -> u256
|
auto for_loop_empty_cpp = []() -> u256
|
||||||
@ -542,6 +582,8 @@ BOOST_AUTO_TEST_CASE(for_loop_simple_init_expr)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
|
|
||||||
auto for_loop_simple_init_expr_cpp = [](u256 const& n) -> u256
|
auto for_loop_simple_init_expr_cpp = [](u256 const& n) -> u256
|
||||||
@ -665,6 +707,8 @@ BOOST_AUTO_TEST_CASE(many_local_variables)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
auto f = [](u256 const& x1, u256 const& x2, u256 const& x3) -> u256
|
auto f = [](u256 const& x1, u256 const& x2, u256 const& x3) -> u256
|
||||||
{
|
{
|
||||||
@ -689,6 +733,8 @@ BOOST_AUTO_TEST_CASE(short_circuiting)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
|
|
||||||
auto short_circuiting_cpp = [](u256 n) -> u256
|
auto short_circuiting_cpp = [](u256 n) -> u256
|
||||||
@ -801,6 +847,8 @@ BOOST_AUTO_TEST_CASE(compound_assign)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
|
|
||||||
u256 value1;
|
u256 value1;
|
||||||
@ -863,6 +911,8 @@ BOOST_AUTO_TEST_CASE(mapping_state)
|
|||||||
map<u160, bool> m_voted;
|
map<u160, bool> m_voted;
|
||||||
};
|
};
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
Ballot ballot;
|
Ballot ballot;
|
||||||
|
|
||||||
@ -936,6 +986,8 @@ BOOST_AUTO_TEST_CASE(mapping_state_inc_dec)
|
|||||||
return --table[value++];
|
return --table[value++];
|
||||||
};
|
};
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
value = 0;
|
value = 0;
|
||||||
table.clear();
|
table.clear();
|
||||||
@ -962,6 +1014,8 @@ BOOST_AUTO_TEST_CASE(multi_level_mapping)
|
|||||||
else return table[_x][_y] = _z;
|
else return table[_x][_y] = _z;
|
||||||
};
|
};
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
table.clear();
|
table.clear();
|
||||||
|
|
||||||
@ -998,6 +1052,8 @@ BOOST_AUTO_TEST_CASE(constructor)
|
|||||||
};
|
};
|
||||||
|
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
testContractAgainstCpp("get(uint256)", get, u256(6));
|
testContractAgainstCpp("get(uint256)", get, u256(6));
|
||||||
testContractAgainstCpp("get(uint256)", get, u256(7));
|
testContractAgainstCpp("get(uint256)", get, u256(7));
|
||||||
@ -1016,12 +1072,12 @@ BOOST_AUTO_TEST_CASE(blockchain)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
m_evmHost->tx_context.block_coinbase = EVMHost::convertToEVMC(Address("0x1212121212121212121212121212121212121212"));
|
m_evmcHost->tx_context.block_coinbase = EVMHost::convertToEVMC(Address("0x1212121212121212121212121212121212121212"));
|
||||||
m_evmHost->newBlock();
|
m_evmcHost->newBlock();
|
||||||
m_evmHost->newBlock();
|
m_evmcHost->newBlock();
|
||||||
m_evmHost->newBlock();
|
m_evmcHost->newBlock();
|
||||||
m_evmHost->newBlock();
|
m_evmcHost->newBlock();
|
||||||
m_evmHost->newBlock();
|
m_evmcHost->newBlock();
|
||||||
compileAndRun(sourceCode, 27);
|
compileAndRun(sourceCode, 27);
|
||||||
ABI_CHECK(callContractFunctionWithValue("someInfo()", 28), encodeArgs(28, u256("0x1212121212121212121212121212121212121212"), 7));
|
ABI_CHECK(callContractFunctionWithValue("someInfo()", 28), encodeArgs(28, u256("0x1212121212121212121212121212121212121212"), 7));
|
||||||
}
|
}
|
||||||
@ -1038,6 +1094,8 @@ BOOST_AUTO_TEST_CASE(send_ether)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
u256 amount(250);
|
u256 amount(250);
|
||||||
compileAndRun(sourceCode, amount + 1);
|
compileAndRun(sourceCode, amount + 1);
|
||||||
u160 address(23);
|
u160 address(23);
|
||||||
@ -1070,6 +1128,8 @@ BOOST_AUTO_TEST_CASE(transfer_ether)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode, 0, "B");
|
compileAndRun(sourceCode, 0, "B");
|
||||||
u160 const nonPayableRecipient = m_contractAddress;
|
u160 const nonPayableRecipient = m_contractAddress;
|
||||||
compileAndRun(sourceCode, 0, "C");
|
compileAndRun(sourceCode, 0, "C");
|
||||||
@ -1110,6 +1170,8 @@ BOOST_AUTO_TEST_CASE(log0)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
callContractFunction("a()");
|
callContractFunction("a()");
|
||||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
||||||
@ -1129,6 +1191,8 @@ BOOST_AUTO_TEST_CASE(log1)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
callContractFunction("a()");
|
callContractFunction("a()");
|
||||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
||||||
@ -1149,6 +1213,8 @@ BOOST_AUTO_TEST_CASE(log2)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
callContractFunction("a()");
|
callContractFunction("a()");
|
||||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
||||||
@ -1170,6 +1236,8 @@ BOOST_AUTO_TEST_CASE(log3)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
callContractFunction("a()");
|
callContractFunction("a()");
|
||||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
||||||
@ -1191,6 +1259,8 @@ BOOST_AUTO_TEST_CASE(log4)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
callContractFunction("a()");
|
callContractFunction("a()");
|
||||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
||||||
@ -1212,6 +1282,8 @@ BOOST_AUTO_TEST_CASE(log_in_constructor)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
||||||
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
|
BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
|
||||||
@ -1235,6 +1307,8 @@ BOOST_AUTO_TEST_CASE(selfdestruct)
|
|||||||
u256 amount(130);
|
u256 amount(130);
|
||||||
u160 address(23);
|
u160 address(23);
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode, amount);
|
compileAndRun(sourceCode, amount);
|
||||||
ABI_CHECK(callContractFunction("a(address)", address), bytes());
|
ABI_CHECK(callContractFunction("a(address)", address), bytes());
|
||||||
BOOST_CHECK(!addressHasCode(m_contractAddress));
|
BOOST_CHECK(!addressHasCode(m_contractAddress));
|
||||||
@ -1665,6 +1739,8 @@ BOOST_AUTO_TEST_CASE(gaslimit)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
auto result = callContractFunction("f()");
|
auto result = callContractFunction("f()");
|
||||||
ABI_CHECK(result, encodeArgs(gasLimit()));
|
ABI_CHECK(result, encodeArgs(gasLimit()));
|
||||||
@ -1681,6 +1757,8 @@ BOOST_AUTO_TEST_CASE(gasprice)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
ABI_CHECK(callContractFunction("f()"), encodeArgs(gasPrice()));
|
ABI_CHECK(callContractFunction("f()"), encodeArgs(gasPrice()));
|
||||||
)
|
)
|
||||||
@ -1772,6 +1850,8 @@ BOOST_AUTO_TEST_CASE(event)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
u256 value(18);
|
u256 value(18);
|
||||||
u256 id(0x1234);
|
u256 id(0x1234);
|
||||||
@ -1800,6 +1880,8 @@ BOOST_AUTO_TEST_CASE(event_emit)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
u256 value(18);
|
u256 value(18);
|
||||||
u256 id(0x1234);
|
u256 id(0x1234);
|
||||||
@ -1826,6 +1908,8 @@ BOOST_AUTO_TEST_CASE(event_no_arguments)
|
|||||||
)";
|
)";
|
||||||
|
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
callContractFunction("deposit()");
|
callContractFunction("deposit()");
|
||||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
||||||
@ -1850,6 +1934,8 @@ BOOST_AUTO_TEST_CASE(event_access_through_base_name_emit)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
callContractFunction("f()");
|
callContractFunction("f()");
|
||||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
||||||
@ -1889,6 +1975,8 @@ BOOST_AUTO_TEST_CASE(events_with_same_name)
|
|||||||
u160 const c_loggedAddress = m_contractAddress;
|
u160 const c_loggedAddress = m_contractAddress;
|
||||||
|
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
ABI_CHECK(callContractFunction("deposit()"), encodeArgs(u256(1)));
|
ABI_CHECK(callContractFunction("deposit()"), encodeArgs(u256(1)));
|
||||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
||||||
@ -1950,6 +2038,8 @@ BOOST_AUTO_TEST_CASE(events_with_same_name_inherited_emit)
|
|||||||
u160 const c_loggedAddress = m_contractAddress;
|
u160 const c_loggedAddress = m_contractAddress;
|
||||||
|
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
ABI_CHECK(callContractFunction("deposit()"), encodeArgs(u256(1)));
|
ABI_CHECK(callContractFunction("deposit()"), encodeArgs(u256(1)));
|
||||||
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
BOOST_REQUIRE_EQUAL(numLogs(), 1);
|
||||||
@ -1985,6 +2075,8 @@ BOOST_AUTO_TEST_CASE(event_anonymous)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
callContractFunction("deposit()");
|
callContractFunction("deposit()");
|
||||||
BOOST_REQUIRE_EQUAL(numLogTopics(0), 0);
|
BOOST_REQUIRE_EQUAL(numLogTopics(0), 0);
|
||||||
@ -2002,6 +2094,8 @@ BOOST_AUTO_TEST_CASE(event_anonymous_with_topics)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
u256 value(18);
|
u256 value(18);
|
||||||
u256 id(0x1234);
|
u256 id(0x1234);
|
||||||
@ -2028,6 +2122,8 @@ BOOST_AUTO_TEST_CASE(event_lots_of_data)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
u256 value(18);
|
u256 value(18);
|
||||||
u256 id(0x1234);
|
u256 id(0x1234);
|
||||||
@ -2247,6 +2343,8 @@ BOOST_AUTO_TEST_CASE(event_dynamic_array_storage)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
u256 x(42);
|
u256 x(42);
|
||||||
callContractFunction("createEvent(uint256)", x);
|
callContractFunction("createEvent(uint256)", x);
|
||||||
@ -2276,6 +2374,8 @@ BOOST_AUTO_TEST_CASE(event_dynamic_array_storage_v2)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
u256 x(42);
|
u256 x(42);
|
||||||
callContractFunction("createEvent(uint256)", x);
|
callContractFunction("createEvent(uint256)", x);
|
||||||
@ -2365,6 +2465,8 @@ BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
BOOST_CHECK(callContractFunction("f(uint256,uint256)", 5, 9) != encodeArgs(5, 8));
|
BOOST_CHECK(callContractFunction("f(uint256,uint256)", 5, 9) != encodeArgs(5, 8));
|
||||||
ABI_CHECK(callContractFunction("f(uint256,uint256)", 5, 9), encodeArgs(9, 8));
|
ABI_CHECK(callContractFunction("f(uint256,uint256)", 5, 9), encodeArgs(9, 8));
|
||||||
@ -2987,6 +3089,8 @@ BOOST_AUTO_TEST_CASE(fixed_array_cleanup)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
BOOST_CHECK(storageEmpty(m_contractAddress));
|
BOOST_CHECK(storageEmpty(m_contractAddress));
|
||||||
ABI_CHECK(callContractFunction("fill()"), bytes());
|
ABI_CHECK(callContractFunction("fill()"), bytes());
|
||||||
@ -3010,6 +3114,8 @@ BOOST_AUTO_TEST_CASE(short_fixed_array_cleanup)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
BOOST_CHECK(storageEmpty(m_contractAddress));
|
BOOST_CHECK(storageEmpty(m_contractAddress));
|
||||||
ABI_CHECK(callContractFunction("fill()"), bytes());
|
ABI_CHECK(callContractFunction("fill()"), bytes());
|
||||||
@ -3037,6 +3143,8 @@ BOOST_AUTO_TEST_CASE(dynamic_array_cleanup)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
BOOST_CHECK(storageEmpty(m_contractAddress));
|
BOOST_CHECK(storageEmpty(m_contractAddress));
|
||||||
ABI_CHECK(callContractFunction("fill()"), bytes());
|
ABI_CHECK(callContractFunction("fill()"), bytes());
|
||||||
@ -4305,6 +4413,8 @@ BOOST_AUTO_TEST_CASE(string_as_mapping_key)
|
|||||||
};
|
};
|
||||||
|
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode, 0, "Test");
|
compileAndRun(sourceCode, 0, "Test");
|
||||||
for (unsigned i = 0; i < strings.size(); i++)
|
for (unsigned i = 0; i < strings.size(); i++)
|
||||||
ABI_CHECK(callContractFunction(
|
ABI_CHECK(callContractFunction(
|
||||||
@ -5415,6 +5525,8 @@ BOOST_AUTO_TEST_CASE(no_nonpayable_circumvention_by_modifier)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode);
|
compileAndRun(sourceCode);
|
||||||
ABI_CHECK(callContractFunctionWithValue("f()", 27), encodeArgs());
|
ABI_CHECK(callContractFunctionWithValue("f()", 27), encodeArgs());
|
||||||
BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 0);
|
BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 0);
|
||||||
@ -5527,6 +5639,8 @@ BOOST_AUTO_TEST_CASE(contracts_separated_with_comment)
|
|||||||
contract C2 {}
|
contract C2 {}
|
||||||
)";
|
)";
|
||||||
ALSO_VIA_YUL(
|
ALSO_VIA_YUL(
|
||||||
|
DISABLE_EWASM_TESTRUN()
|
||||||
|
|
||||||
compileAndRun(sourceCode, 0, "C1");
|
compileAndRun(sourceCode, 0, "C1");
|
||||||
compileAndRun(sourceCode, 0, "C2");
|
compileAndRun(sourceCode, 0, "C2");
|
||||||
)
|
)
|
||||||
|
@ -43,6 +43,7 @@ bytes SolidityExecutionFramework::multiSourceCompileContract(
|
|||||||
entry.second = addPreamble(entry.second);
|
entry.second = addPreamble(entry.second);
|
||||||
|
|
||||||
m_compiler.reset();
|
m_compiler.reset();
|
||||||
|
m_compiler.enableEwasmGeneration(m_compileToEwasm);
|
||||||
m_compiler.setSources(sourcesWithPreamble);
|
m_compiler.setSources(sourcesWithPreamble);
|
||||||
m_compiler.setLibraries(_libraryAddresses);
|
m_compiler.setLibraries(_libraryAddresses);
|
||||||
m_compiler.setRevertStringBehaviour(m_revertStrings);
|
m_compiler.setRevertStringBehaviour(m_revertStrings);
|
||||||
@ -63,38 +64,40 @@ bytes SolidityExecutionFramework::multiSourceCompileContract(
|
|||||||
evmasm::LinkerObject obj;
|
evmasm::LinkerObject obj;
|
||||||
if (m_compileViaYul)
|
if (m_compileViaYul)
|
||||||
{
|
{
|
||||||
// Try compiling twice: If the first run fails due to stack errors, forcefully enable
|
if (m_compileToEwasm)
|
||||||
// the optimizer.
|
obj = m_compiler.ewasmObject(contractName);
|
||||||
for (bool forceEnableOptimizer: {false, true})
|
else
|
||||||
{
|
{
|
||||||
OptimiserSettings optimiserSettings = m_optimiserSettings;
|
// Try compiling twice: If the first run fails due to stack errors, forcefully enable
|
||||||
if (!forceEnableOptimizer && !optimiserSettings.runYulOptimiser)
|
// the optimizer.
|
||||||
|
for (bool forceEnableOptimizer: {false, true})
|
||||||
{
|
{
|
||||||
// Enable some optimizations on the first run
|
OptimiserSettings optimiserSettings = m_optimiserSettings;
|
||||||
optimiserSettings.runYulOptimiser = true;
|
if (!forceEnableOptimizer && !optimiserSettings.runYulOptimiser)
|
||||||
optimiserSettings.yulOptimiserSteps = "uljmul jmul";
|
{
|
||||||
}
|
// Enable some optimizations on the first run
|
||||||
else if (forceEnableOptimizer)
|
optimiserSettings.runYulOptimiser = true;
|
||||||
optimiserSettings = OptimiserSettings::full();
|
optimiserSettings.yulOptimiserSteps = "uljmul jmul";
|
||||||
|
}
|
||||||
|
else if (forceEnableOptimizer)
|
||||||
|
optimiserSettings = OptimiserSettings::full();
|
||||||
|
|
||||||
yul::AssemblyStack asmStack(
|
yul::AssemblyStack
|
||||||
m_evmVersion,
|
asmStack(m_evmVersion, yul::AssemblyStack::Language::StrictAssembly, optimiserSettings);
|
||||||
yul::AssemblyStack::Language::StrictAssembly,
|
bool analysisSuccessful = asmStack.parseAndAnalyze("", m_compiler.yulIROptimized(contractName));
|
||||||
optimiserSettings
|
solAssert(analysisSuccessful, "Code that passed analysis in CompilerStack can't have errors");
|
||||||
);
|
|
||||||
bool analysisSuccessful = asmStack.parseAndAnalyze("", m_compiler.yulIROptimized(contractName));
|
|
||||||
solAssert(analysisSuccessful, "Code that passed analysis in CompilerStack can't have errors");
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
asmStack.optimize();
|
asmStack.optimize();
|
||||||
obj = std::move(*asmStack.assemble(yul::AssemblyStack::Machine::EVM).bytecode);
|
obj = std::move(*asmStack.assemble(yul::AssemblyStack::Machine::EVM).bytecode);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
if (forceEnableOptimizer || optimiserSettings == OptimiserSettings::full())
|
if (forceEnableOptimizer || optimiserSettings == OptimiserSettings::full())
|
||||||
throw;
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,8 +43,8 @@ class SolidityExecutionFramework: public solidity::test::ExecutionFramework
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
SolidityExecutionFramework(): m_showMetadata(solidity::test::CommonOptions::get().showMetadata) {}
|
SolidityExecutionFramework(): m_showMetadata(solidity::test::CommonOptions::get().showMetadata) {}
|
||||||
explicit SolidityExecutionFramework(langutil::EVMVersion _evmVersion):
|
explicit SolidityExecutionFramework(langutil::EVMVersion _evmVersion, std::vector<boost::filesystem::path> const& _vmPaths):
|
||||||
ExecutionFramework(_evmVersion), m_showMetadata(solidity::test::CommonOptions::get().showMetadata)
|
ExecutionFramework(_evmVersion, _vmPaths), m_showMetadata(solidity::test::CommonOptions::get().showMetadata)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bytes const& compileAndRunWithoutCheck(
|
bytes const& compileAndRunWithoutCheck(
|
||||||
@ -76,8 +76,10 @@ public:
|
|||||||
/// the latter only if it is required.
|
/// the latter only if it is required.
|
||||||
static std::string addPreamble(std::string const& _sourceCode);
|
static std::string addPreamble(std::string const& _sourceCode);
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
solidity::frontend::CompilerStack m_compiler;
|
solidity::frontend::CompilerStack m_compiler;
|
||||||
bool m_compileViaYul = false;
|
bool m_compileViaYul = false;
|
||||||
|
bool m_compileToEwasm = false;
|
||||||
bool m_showMetadata = false;
|
bool m_showMetadata = false;
|
||||||
RevertStrings m_revertStrings = RevertStrings::Default;
|
RevertStrings m_revertStrings = RevertStrings::Default;
|
||||||
};
|
};
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include <liblangutil/Scanner.h>
|
#include <liblangutil/Scanner.h>
|
||||||
#include <libsolidity/parsing/Parser.h>
|
#include <libsolidity/parsing/Parser.h>
|
||||||
#include <libsolidity/analysis/NameAndTypeResolver.h>
|
#include <libsolidity/analysis/NameAndTypeResolver.h>
|
||||||
|
#include <libsolidity/analysis/Scoper.h>
|
||||||
#include <libsolidity/analysis/DeclarationTypeChecker.h>
|
#include <libsolidity/analysis/DeclarationTypeChecker.h>
|
||||||
#include <libsolidity/codegen/CompilerContext.h>
|
#include <libsolidity/codegen/CompilerContext.h>
|
||||||
#include <libsolidity/codegen/ExpressionCompiler.h>
|
#include <libsolidity/codegen/ExpressionCompiler.h>
|
||||||
@ -117,6 +118,7 @@ bytes compileFirstExpression(
|
|||||||
ErrorList errors;
|
ErrorList errors;
|
||||||
ErrorReporter errorReporter(errors);
|
ErrorReporter errorReporter(errors);
|
||||||
GlobalContext globalContext;
|
GlobalContext globalContext;
|
||||||
|
Scoper::assignScopes(*sourceUnit);
|
||||||
NameAndTypeResolver resolver(globalContext, solidity::test::CommonOptions::get().evmVersion(), errorReporter);
|
NameAndTypeResolver resolver(globalContext, solidity::test::CommonOptions::get().evmVersion(), errorReporter);
|
||||||
resolver.registerDeclarations(*sourceUnit);
|
resolver.registerDeclarations(*sourceUnit);
|
||||||
BOOST_REQUIRE_MESSAGE(resolver.resolveNamesAndTypes(*sourceUnit), "Resolving names failed");
|
BOOST_REQUIRE_MESSAGE(resolver.resolveNamesAndTypes(*sourceUnit), "Resolving names failed");
|
||||||
|
@ -17,9 +17,9 @@ contract C {
|
|||||||
// optimize-yul: true
|
// optimize-yul: true
|
||||||
// ----
|
// ----
|
||||||
// creation:
|
// creation:
|
||||||
// codeDepositCost: 614600
|
// codeDepositCost: 597000
|
||||||
// executionCost: 651
|
// executionCost: 632
|
||||||
// totalCost: 615251
|
// totalCost: 597632
|
||||||
// external:
|
// external:
|
||||||
// a(): 1029
|
// a(): 1029
|
||||||
// b(uint256): 2084
|
// b(uint256): 2084
|
||||||
|
@ -12,5 +12,7 @@ contract c {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// test() -> 1, 2, 3, 4
|
// test() -> 1, 2, 3, 4
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
contract C {
|
||||||
|
uint8[33] a;
|
||||||
|
uint32[9] b;
|
||||||
|
uint120[3] c;
|
||||||
|
|
||||||
|
function f() public returns (uint8, uint32, uint120) {
|
||||||
|
a[32] = 1; a[31] = 2; a[30] = 3;
|
||||||
|
b[0] = 1; b[1] = 2; b[2] = 3;
|
||||||
|
c[2] = 3; c[1] = 1;
|
||||||
|
return (a[32], b[1], c[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// f() -> 1, 2, 3
|
@ -8,4 +8,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning 2529: (82-89): Empty array "pop" detected here
|
// Warning 2529: (82-89): Empty array "pop" detected here.
|
||||||
|
@ -8,4 +8,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning 2529: (82-89): Empty array "pop" detected here
|
// Warning 2529: (82-89): Empty array "pop" detected here.
|
||||||
|
@ -8,5 +8,5 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning 2529: (82-89): Empty array "pop" detected here
|
// Warning 2529: (82-89): Empty array "pop" detected here.
|
||||||
// Warning 2529: (93-100): Empty array "pop" detected here
|
// Warning 2529: (93-100): Empty array "pop" detected here.
|
||||||
|
@ -8,4 +8,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning 2529: (94-101): Empty array "pop" detected here
|
// Warning 2529: (94-101): Empty array "pop" detected here.
|
||||||
|
@ -11,4 +11,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning 2529: (122-129): Empty array "pop" detected here
|
// Warning 2529: (122-129): Empty array "pop" detected here.
|
||||||
|
@ -11,4 +11,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning 2529: (127-134): Empty array "pop" detected here
|
// Warning 2529: (127-134): Empty array "pop" detected here.
|
||||||
|
@ -13,4 +13,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning 2529: (82-89): Empty array "pop" detected here
|
// Warning 2529: (82-89): Empty array "pop" detected here.
|
||||||
|
@ -10,4 +10,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning 6328: (153-176): Assertion violation happens here
|
// Warning 6328: (153-176): Assertion violation happens here.
|
||||||
|
@ -14,6 +14,6 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning 6328: (198-224): Assertion violation happens here
|
// Warning 6328: (198-224): Assertion violation happens here.
|
||||||
// Warning 6328: (228-254): Assertion violation happens here
|
// Warning 6328: (228-254): Assertion violation happens here.
|
||||||
// Warning 6328: (258-281): Assertion violation happens here
|
// Warning 6328: (258-281): Assertion violation happens here.
|
||||||
|
@ -16,7 +16,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning 6328: (222-248): Assertion violation happens here
|
// Warning 6328: (222-248): Assertion violation happens here.
|
||||||
// Warning 6328: (252-278): Assertion violation happens here
|
// Warning 6328: (252-278): Assertion violation happens here.
|
||||||
// Warning 6328: (282-305): Assertion violation happens here
|
// Warning 6328: (282-305): Assertion violation happens here.
|
||||||
// Warning 6328: (309-335): Assertion violation happens here
|
// Warning 6328: (309-335): Assertion violation happens here.
|
||||||
|
@ -7,4 +7,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning 2529: (82-89): Empty array "pop" detected here
|
// Warning 2529: (82-89): Empty array "pop" detected here.
|
||||||
|
@ -9,4 +9,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning 2529: (111-121): Empty array "pop" detected here
|
// Warning 2529: (111-121): Empty array "pop" detected here.
|
||||||
|
@ -7,4 +7,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning 2529: (76-83): Empty array "pop" detected here
|
// Warning 2529: (76-83): Empty array "pop" detected here.
|
||||||
|
@ -11,4 +11,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning 2529: (150-157): Empty array "pop" detected here
|
// Warning 2529: (150-157): Empty array "pop" detected here.
|
||||||
|
@ -10,5 +10,5 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning 3944: (162-177): Underflow (resulting value less than 0) happens here
|
// Warning 3944: (162-177): Underflow (resulting value less than 0) happens here.
|
||||||
// Warning 6328: (150-184): Assertion violation happens here
|
// Warning 6328: (150-184): Assertion violation happens here.
|
||||||
|
@ -8,5 +8,5 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning 6328: (113-139): Assertion violation happens here
|
// Warning 6328: (113-139): Assertion violation happens here.
|
||||||
// Warning 6328: (143-189): Assertion violation happens here
|
// Warning 6328: (143-189): Assertion violation happens here.
|
||||||
|
@ -10,6 +10,6 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning 6328: (122-148): Assertion violation happens here
|
// Warning 6328: (122-148): Assertion violation happens here.
|
||||||
// Warning 6328: (202-218): Assertion violation happens here
|
// Warning 6328: (202-218): Assertion violation happens here.
|
||||||
// Warning 6328: (222-278): Assertion violation happens here
|
// Warning 6328: (222-278): Assertion violation happens here.
|
||||||
|
@ -12,5 +12,5 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning 3944: (217-232): Underflow (resulting value less than 0) happens here
|
// Warning 3944: (217-232): Underflow (resulting value less than 0) happens here.
|
||||||
// Warning 6328: (205-239): Assertion violation happens here
|
// Warning 6328: (205-239): Assertion violation happens here.
|
||||||
|
@ -12,4 +12,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning 6328: (167-188): Assertion violation happens here
|
// Warning 6328: (167-188): Assertion violation happens here.
|
||||||
|
@ -18,6 +18,6 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning 6328: (193-217): Assertion violation happens here
|
// Warning 6328: (193-217): Assertion violation happens here.
|
||||||
// Warning 6328: (309-333): Assertion violation happens here
|
// Warning 6328: (309-333): Assertion violation happens here.
|
||||||
// Warning 6328: (419-436): Assertion violation happens here
|
// Warning 6328: (419-436): Assertion violation happens here.
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user