/src/solidity/libsolidity/codegen/ir/IRGeneratorForStatements.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 | | * Component that translates Solidity code into Yul at statement level and below. |
20 | | */ |
21 | | |
22 | | #pragma once |
23 | | |
24 | | #include <libsolidity/ast/ASTVisitor.h> |
25 | | #include <libsolidity/codegen/ir/IRLValue.h> |
26 | | #include <libsolidity/codegen/ir/IRVariable.h> |
27 | | #include <libsolidity/interface/OptimiserSettings.h> |
28 | | |
29 | | #include <functional> |
30 | | |
31 | | namespace solidity::frontend |
32 | | { |
33 | | |
34 | | class IRGenerationContext; |
35 | | class YulUtilFunctions; |
36 | | |
37 | | /** |
38 | | * Base class for the statement generator. |
39 | | * Encapsulates access to the yul code stream and handles source code locations. |
40 | | */ |
41 | | class IRGeneratorForStatementsBase: public ASTConstVisitor |
42 | | { |
43 | | public: |
44 | | IRGeneratorForStatementsBase(IRGenerationContext& _context): |
45 | 15.6k | m_context(_context) |
46 | 15.6k | {} |
47 | | |
48 | | virtual std::string code() const; |
49 | | std::ostringstream& appendCode(bool _addLocationComment = true); |
50 | | protected: |
51 | | void setLocation(ASTNode const& _node); |
52 | | langutil::SourceLocation m_currentLocation = {}; |
53 | | langutil::SourceLocation m_lastLocation = {}; |
54 | | IRGenerationContext& m_context; |
55 | | private: |
56 | | std::ostringstream m_code; |
57 | | }; |
58 | | |
59 | | /** |
60 | | * Component that translates Solidity's AST into Yul at statement level and below. |
61 | | * It is an AST visitor that appends to an internal string buffer. |
62 | | */ |
63 | | class IRGeneratorForStatements: public IRGeneratorForStatementsBase |
64 | | { |
65 | | public: |
66 | | IRGeneratorForStatements( |
67 | | IRGenerationContext& _context, |
68 | | YulUtilFunctions& _utils, |
69 | | OptimiserSettings& _optimiserSettings, |
70 | | std::function<std::string()> _placeholderCallback = {} |
71 | | ): |
72 | 15.6k | IRGeneratorForStatementsBase(_context), |
73 | 15.6k | m_placeholderCallback(std::move(_placeholderCallback)), |
74 | 15.6k | m_utils(_utils), |
75 | 15.6k | m_optimiserSettings(_optimiserSettings) |
76 | 15.6k | {} |
77 | | |
78 | | std::string code() const override; |
79 | | |
80 | | /// Generate the code for the statements in the block; |
81 | | void generate(Block const& _block); |
82 | | |
83 | | /// Generates code to initialize the given state variable. |
84 | | void initializeStateVar(VariableDeclaration const& _varDecl); |
85 | | /// Generates code to initialize the given local variable. |
86 | | void initializeLocalVar(VariableDeclaration const& _varDecl); |
87 | | |
88 | | /// Calculates expression's value and returns variable where it was stored |
89 | | IRVariable evaluateExpression(Expression const& _expression, Type const& _to); |
90 | | |
91 | | /// Defines @a _var using the value of @a _value while performing type conversions, if required. |
92 | | void define(IRVariable const& _var, IRVariable const& _value) |
93 | 45.3k | { |
94 | 45.3k | bool _declare = true; |
95 | 45.3k | declareAssign(_var, _value, _declare); |
96 | 45.3k | } |
97 | | |
98 | | /// Defines @a _var using the value of @a _value while performing type conversions, if required. |
99 | | /// It also cleans the value of the variable. |
100 | | void defineAndCleanup(IRVariable const& _var, IRVariable const& _value) |
101 | 0 | { |
102 | 0 | bool _forceCleanup = true; |
103 | 0 | bool _declare = true; |
104 | 0 | declareAssign(_var, _value, _declare, _forceCleanup); |
105 | 0 | } |
106 | | |
107 | | /// @returns the name of a function that computes the value of the given constant |
108 | | /// and also generates the function. |
109 | | std::string constantValueFunction(VariableDeclaration const& _constant); |
110 | | |
111 | | void endVisit(VariableDeclarationStatement const& _variableDeclaration) override; |
112 | | bool visit(Conditional const& _conditional) override; |
113 | | bool visit(Assignment const& _assignment) override; |
114 | | bool visit(TupleExpression const& _tuple) override; |
115 | | void endVisit(PlaceholderStatement const& _placeholder) override; |
116 | | bool visit(Block const& _block) override; |
117 | | void endVisit(Block const& _block) override; |
118 | | bool visit(IfStatement const& _ifStatement) override; |
119 | | bool visit(ForStatement const& _forStatement) override; |
120 | | bool visit(WhileStatement const& _whileStatement) override; |
121 | | bool visit(Continue const& _continueStatement) override; |
122 | | bool visit(Break const& _breakStatement) override; |
123 | | void endVisit(Return const& _return) override; |
124 | | bool visit(UnaryOperation const& _unaryOperation) override; |
125 | | bool visit(BinaryOperation const& _binOp) override; |
126 | | void endVisit(FunctionCall const& _funCall) override; |
127 | | void endVisit(FunctionCallOptions const& _funCallOptions) override; |
128 | | bool visit(MemberAccess const& _memberAccess) override; |
129 | | void endVisit(MemberAccess const& _memberAccess) override; |
130 | | bool visit(InlineAssembly const& _inlineAsm) override; |
131 | | void endVisit(IndexAccess const& _indexAccess) override; |
132 | | void endVisit(IndexRangeAccess const& _indexRangeAccess) override; |
133 | | void endVisit(Identifier const& _identifier) override; |
134 | | bool visit(Literal const& _literal) override; |
135 | | void endVisit(RevertStatement const& _revertStatement) override; |
136 | | |
137 | | bool visit(TryStatement const& _tryStatement) override; |
138 | | bool visit(TryCatchClause const& _tryCatchClause) override; |
139 | | |
140 | | private: |
141 | | /// Handles all catch cases of a try statement, except the success-case. |
142 | | void handleCatch(TryStatement const& _tryStatement); |
143 | | void handleCatchFallback(TryCatchClause const& _fallback); |
144 | | |
145 | | /// Generates code to revert with an error. The error arguments are assumed to |
146 | | /// be already evaluated and available in local IRVariables, but not yet |
147 | | /// converted. |
148 | | void revertWithError( |
149 | | std::string const& _signature, |
150 | | std::vector<Type const*> const& _parameterTypes, |
151 | | std::vector<ASTPointer<Expression const>> const& _errorArguments |
152 | | ); |
153 | | |
154 | | void handleVariableReference( |
155 | | VariableDeclaration const& _variable, |
156 | | Expression const& _referencingExpression |
157 | | ); |
158 | | |
159 | | /// Appends code to call an external function with the given arguments. |
160 | | /// All involved expressions have already been visited. |
161 | | void appendExternalFunctionCall( |
162 | | FunctionCall const& _functionCall, |
163 | | std::vector<ASTPointer<Expression const>> const& _arguments |
164 | | ); |
165 | | |
166 | | /// Appends code for .call / .delegatecall / .staticcall. |
167 | | /// All involved expressions have already been visited. |
168 | | void appendBareCall( |
169 | | FunctionCall const& _functionCall, |
170 | | std::vector<ASTPointer<Expression const>> const& _arguments |
171 | | ); |
172 | | |
173 | | /// Requests and assigns the internal ID of the referenced function to the referencing |
174 | | /// expression and adds the function to the internal dispatch. |
175 | | /// If the function is called right away, it does nothing. |
176 | | void assignInternalFunctionIDIfNotCalledDirectly( |
177 | | Expression const& _expression, |
178 | | FunctionDefinition const& _referencedFunction |
179 | | ); |
180 | | |
181 | | /// Generates the required conversion code and @returns an IRVariable referring to the value of @a _variable |
182 | | IRVariable convert(IRVariable const& _variable, Type const& _to); |
183 | | |
184 | | /// Generates the required conversion code and @returns an IRVariable referring to the value of @a _variable |
185 | | /// It also cleans the value of the variable. |
186 | | IRVariable convertAndCleanup(IRVariable const& _from, Type const& _to); |
187 | | |
188 | | /// @returns a Yul expression representing the current value of @a _expression, |
189 | | /// converted to type @a _to if it does not yet have that type. |
190 | | std::string expressionAsType(Expression const& _expression, Type const& _to); |
191 | | |
192 | | /// @returns a Yul expression representing the current value of @a _expression, |
193 | | /// converted to type @a _to if it does not yet have that type. |
194 | | /// It also cleans the value, in case it already has type @a _to. |
195 | | std::string expressionAsCleanedType(Expression const& _expression, Type const& _to); |
196 | | |
197 | | /// @returns an output stream that can be used to define @a _var using a function call or |
198 | | /// single stack slot expression. |
199 | | std::ostream& define(IRVariable const& _var); |
200 | | |
201 | | /// Assigns @a _var to the value of @a _value while performing type conversions, if required. |
202 | 7.57k | void assign(IRVariable const& _var, IRVariable const& _value) { declareAssign(_var, _value, false); } |
203 | | /// Declares variable @a _var. |
204 | | void declare(IRVariable const& _var); |
205 | | |
206 | | void declareAssign(IRVariable const& _var, IRVariable const& _value, bool _define, bool _forceCleanup = false); |
207 | | |
208 | | /// @returns an IRVariable with the zero |
209 | | /// value of @a _type. |
210 | | /// @param _splitFunctionTypes if false, returns two zeroes |
211 | | IRVariable zeroValue(Type const& _type, bool _splitFunctionTypes = true); |
212 | | |
213 | | void appendAndOrOperatorCode(BinaryOperation const& _binOp); |
214 | | void appendSimpleUnaryOperation(UnaryOperation const& _operation, Expression const& _expr); |
215 | | |
216 | | /// @returns code to perform the given binary operation in the given type on the two values. |
217 | | std::string binaryOperation( |
218 | | langutil::Token _op, |
219 | | Type const& _type, |
220 | | std::string const& _left, |
221 | | std::string const& _right |
222 | | ); |
223 | | |
224 | | /// @returns code to perform the given shift operation. |
225 | | /// The operation itself will be performed in the type of the value, |
226 | | /// while the amount to shift can have its own type. |
227 | | std::string shiftOperation(langutil::Token _op, IRVariable const& _value, IRVariable const& _shiftAmount); |
228 | | |
229 | | /// Assigns the value of @a _value to the lvalue @a _lvalue. |
230 | | void writeToLValue(IRLValue const& _lvalue, IRVariable const& _value); |
231 | | |
232 | | /// @returns a fresh IR variable containing the value of the lvalue @a _lvalue. |
233 | | IRVariable readFromLValue(IRLValue const& _lvalue); |
234 | | |
235 | | /// Stores the given @a _lvalue in m_currentLValue, if it will be written to (willBeWrittenTo). Otherwise |
236 | | /// defines the expression @a _expression by reading the value from @a _lvalue. |
237 | | void setLValue(Expression const& _expression, IRLValue _lvalue); |
238 | | void generateLoop( |
239 | | Statement const& _body, |
240 | | Expression const* _conditionExpression, |
241 | | Statement const* _initExpression = nullptr, |
242 | | ExpressionStatement const* _loopExpression = nullptr, |
243 | | bool _isDoWhile = false, |
244 | | bool _isSimpleCounterLoop = false |
245 | | ); |
246 | | |
247 | | static Type const& type(Expression const& _expression); |
248 | | |
249 | | std::string linkerSymbol(ContractDefinition const& _library) const; |
250 | | |
251 | | std::function<std::string()> m_placeholderCallback; |
252 | | YulUtilFunctions& m_utils; |
253 | | std::optional<IRLValue> m_currentLValue; |
254 | | OptimiserSettings m_optimiserSettings; |
255 | | }; |
256 | | |
257 | | } |