Coverage Report

Created: 2025-06-24 07:59

/src/solidity/libyul/SideEffects.h
Line
Count
Source
1
/*
2
  This file is part of solidity.
3
4
  solidity is free software: you can redistribute it and/or modify
5
  it under the terms of the GNU General Public License as published by
6
  the Free Software Foundation, either version 3 of the License, or
7
  (at your option) any later version.
8
9
  solidity is distributed in the hope that it will be useful,
10
  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
  GNU General Public License for more details.
13
14
  You should have received a copy of the GNU General Public License
15
  along with solidity.  If not, see <http://www.gnu.org/licenses/>.
16
*/
17
// SPDX-License-Identifier: GPL-3.0
18
19
#pragma once
20
21
#include <algorithm>
22
#include <set>
23
24
namespace solidity::yul
25
{
26
27
/**
28
 * Side effects of code.
29
 *
30
 * The default-constructed value applies to the "empty code".
31
 */
32
struct SideEffects
33
{
34
  /// Corresponds to the effect that a Yul-builtin has on a generic data location (storage, memory
35
  /// and other blockchain state).
36
  enum Effect
37
  {
38
    None,
39
    Read,
40
    Write
41
  };
42
43
  friend Effect operator+(Effect const& _a, Effect const& _b)
44
572M
  {
45
572M
    return static_cast<Effect>(std::max(static_cast<int>(_a), static_cast<int>(_b)));
46
572M
  }
47
48
  /// If true, expressions in this code can be freely moved and copied without altering the
49
  /// semantics.
50
  /// At statement level, it means that functions containing this code can be
51
  /// called multiple times, their calls can be rearranged and calls can also be
52
  /// deleted without changing the semantics.
53
  /// This means it cannot depend on storage, memory or transient storage, cannot have any side-effects,
54
  /// but it can depend on state that is constant across an EVM-call.
55
  bool movable = true;
56
  /// If true, the expressions in this code can be moved or copied (together with their arguments)
57
  /// across control flow branches and instructions as long as these instructions' 'effects' do
58
  /// not influence the 'effects' of the aforementioned expressions.
59
  bool movableApartFromEffects = true;
60
  /// If true, the code can be removed without changing the semantics.
61
  bool canBeRemoved = true;
62
  /// If true, the code can be removed without changing the semantics as long as
63
  /// the whole program does not contain the msize instruction.
64
  bool canBeRemovedIfNoMSize = true;
65
  /// If false, the code calls a for-loop or a recursive function, and therefore potentially loops
66
  /// infinitely. All builtins are set to true by default, even `invalid()`.
67
  bool cannotLoop = true;
68
  /// Can write, read or have no effect on the blockchain state, when the value of `otherState` is
69
  /// `Write`, `Read` or `None` respectively.
70
  Effect otherState = None;
71
  /// Can write, read or have no effect on storage, when the value of `storage` is `Write`, `Read`
72
  /// or `None` respectively. When the value is `Write`, the expression can invalidate storage,
73
  /// potentially indirectly through external calls.
74
  Effect storage = None;
75
  /// Can write, read or have no effect on memory, when the value of `memory` is `Write`, `Read`
76
  /// or `None` respectively. Note that, when the value is `Read`, the expression can have an
77
  /// effect on `msize()`.
78
  Effect memory = None;
79
  /// Can write, read or have no effect on transient storage, when the value of `transientStorage` is `Write`, `Read`
80
  /// or `None` respectively.  When the value is `Write`, the expression can invalidate transient storage,
81
  /// potentially indirectly through external calls.
82
  Effect transientStorage = None;
83
84
  /// @returns the worst-case side effects.
85
  static SideEffects worst()
86
47.6M
  {
87
47.6M
    return SideEffects{false, false, false, false, false, Write, Write, Write, Write};
88
47.6M
  }
89
90
  /// @returns the combined side effects of two pieces of code.
91
  SideEffects operator+(SideEffects const& _other)
92
143M
  {
93
143M
    return SideEffects{
94
143M
      movable && _other.movable,
95
143M
      movableApartFromEffects && _other.movableApartFromEffects,
96
143M
      canBeRemoved && _other.canBeRemoved,
97
143M
      canBeRemovedIfNoMSize && _other.canBeRemovedIfNoMSize,
98
143M
      cannotLoop && _other.cannotLoop,
99
143M
      otherState + _other.otherState,
100
143M
      storage + _other.storage,
101
143M
      memory + _other.memory,
102
143M
      transientStorage + _other.transientStorage
103
143M
    };
104
143M
  }
105
106
  /// Adds the side effects of another piece of code to this side effect.
107
  SideEffects& operator+=(SideEffects const& _other)
108
143M
  {
109
143M
    *this = *this + _other;
110
143M
    return *this;
111
143M
  }
112
113
  bool operator==(SideEffects const& _other) const
114
45.6M
  {
115
45.6M
    return
116
45.6M
      movable == _other.movable &&
117
45.6M
      movableApartFromEffects == _other.movableApartFromEffects &&
118
45.6M
      canBeRemoved == _other.canBeRemoved &&
119
45.6M
      canBeRemovedIfNoMSize == _other.canBeRemovedIfNoMSize &&
120
45.6M
      cannotLoop == _other.cannotLoop &&
121
45.6M
      otherState == _other.otherState &&
122
45.6M
      storage == _other.storage &&
123
45.6M
      memory == _other.memory &&
124
45.6M
      transientStorage == _other.transientStorage;
125
45.6M
  }
126
};
127
128
}