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