/src/solidity/libsolidity/experimental/codegen/IRGenerator.cpp
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 | | #include <libsolidity/experimental/codegen/IRGenerator.h> |
20 | | #include <libsolidity/experimental/codegen/IRGenerationContext.h> |
21 | | #include <libsolidity/experimental/codegen/IRGeneratorForStatements.h> |
22 | | |
23 | | #include <libsolidity/experimental/codegen/Common.h> |
24 | | |
25 | | #include <libsolidity/experimental/analysis/Analysis.h> |
26 | | #include <libsolidity/experimental/analysis/TypeInference.h> |
27 | | |
28 | | #include <libsolidity/experimental/ast/TypeSystemHelper.h> |
29 | | |
30 | | #include <libyul/AsmPrinter.h> |
31 | | #include <libyul/AST.h> |
32 | | #include <libyul/optimiser/ASTCopier.h> |
33 | | |
34 | | #include <liblangutil/SourceReferenceFormatter.h> |
35 | | |
36 | | #include <libsolutil/Whiskers.h> |
37 | | |
38 | | #include <range/v3/view/drop_last.hpp> |
39 | | |
40 | | #include <variant> |
41 | | |
42 | | using namespace solidity; |
43 | | using namespace solidity::frontend::experimental; |
44 | | using namespace solidity::langutil; |
45 | | using namespace solidity::util; |
46 | | |
47 | | IRGenerator::IRGenerator( |
48 | | EVMVersion _evmVersion, |
49 | | frontend::RevertStrings, std::map<std::string, unsigned int>, |
50 | | DebugInfoSelection const&, |
51 | | CharStreamProvider const*, |
52 | | Analysis const& _analysis |
53 | | ): |
54 | 0 | m_evmVersion(_evmVersion), |
55 | | //m_debugInfoSelection(_debugInfoSelection), |
56 | | //m_soliditySourceProvider(_soliditySourceProvider), |
57 | 0 | m_env(_analysis.typeSystem().env().clone()), |
58 | 0 | m_context{_analysis, &m_env, {}, {}} |
59 | 0 | { |
60 | 0 | } |
61 | | |
62 | | std::string IRGenerator::run( |
63 | | ContractDefinition const& _contract, |
64 | | bytes const& /*_cborMetadata*/, |
65 | | std::map<ContractDefinition const*, std::string_view const> const& /*_otherYulSources*/ |
66 | | ) |
67 | 0 | { |
68 | 0 | Whiskers t(R"( |
69 | 0 | object "<CreationObject>" { |
70 | 0 | code { |
71 | 0 | codecopy(0, dataoffset("<DeployedObject>"), datasize("<DeployedObject>")) |
72 | 0 | return(0, datasize("<DeployedObject>")) |
73 | 0 | } |
74 | 0 | object "<DeployedObject>" { |
75 | 0 | code { |
76 | 0 | <code> |
77 | 0 | } |
78 | 0 | } |
79 | 0 | } |
80 | 0 | )"); |
81 | 0 | t("CreationObject", IRNames::creationObject(_contract)); |
82 | 0 | t("DeployedObject", IRNames::deployedObject(_contract)); |
83 | 0 | t("code", generate(_contract)); |
84 | |
|
85 | 0 | return t.render(); |
86 | 0 | } |
87 | | |
88 | | std::string IRGenerator::generate(ContractDefinition const& _contract) |
89 | 0 | { |
90 | 0 | std::stringstream code; |
91 | 0 | code << "{\n"; |
92 | 0 | if (_contract.fallbackFunction()) |
93 | 0 | { |
94 | 0 | auto type = m_context.analysis.annotation<TypeInference>(*_contract.fallbackFunction()).type; |
95 | 0 | solAssert(type); |
96 | 0 | type = m_context.env->resolve(*type); |
97 | 0 | code << IRNames::function(*m_context.env, *_contract.fallbackFunction(), *type) << "()\n"; |
98 | 0 | m_context.enqueueFunctionDefinition(_contract.fallbackFunction(), *type); |
99 | 0 | } |
100 | 0 | code << "revert(0,0)\n"; |
101 | 0 | code << "}\n"; |
102 | |
|
103 | 0 | while (!m_context.functionQueue.empty()) |
104 | 0 | { |
105 | 0 | auto queueEntry = m_context.functionQueue.front(); |
106 | 0 | m_context.functionQueue.pop_front(); |
107 | 0 | auto& generatedTypes = m_context.generatedFunctions.insert(std::make_pair(queueEntry.function, std::vector<Type>{})).first->second; |
108 | 0 | if (!util::contains_if(generatedTypes, [&](auto const& _generatedType) { return m_context.env->typeEquals(_generatedType, queueEntry.type); })) |
109 | 0 | { |
110 | 0 | generatedTypes.emplace_back(queueEntry.type); |
111 | 0 | code << generate(*queueEntry.function, queueEntry.type); |
112 | 0 | } |
113 | 0 | } |
114 | |
|
115 | 0 | return code.str(); |
116 | 0 | } |
117 | | |
118 | | std::string IRGenerator::generate(FunctionDefinition const& _function, Type _type) |
119 | 0 | { |
120 | 0 | TypeEnvironment newEnv = m_context.env->clone(); |
121 | 0 | ScopedSaveAndRestore envRestore{m_context.env, &newEnv}; |
122 | 0 | auto type = m_context.analysis.annotation<TypeInference>(_function).type; |
123 | 0 | solAssert(type); |
124 | 0 | for (auto err: newEnv.unify(*type, _type)) |
125 | 0 | { |
126 | 0 | TypeEnvironmentHelpers helper{newEnv}; |
127 | 0 | solAssert(false, helper.typeToString(*type) + " <-> " + helper.typeToString(_type)); |
128 | 0 | } |
129 | 0 | std::stringstream code; |
130 | 0 | code << "function " << IRNames::function(newEnv, _function, _type) << "("; |
131 | 0 | if (_function.parameters().size() > 1) |
132 | 0 | for (auto const& arg: _function.parameters() | ranges::views::drop_last(1)) |
133 | 0 | code << IRNames::localVariable(*arg) << ", "; |
134 | 0 | if (!_function.parameters().empty()) |
135 | 0 | code << IRNames::localVariable(*_function.parameters().back()); |
136 | 0 | code << ")"; |
137 | 0 | if (_function.experimentalReturnExpression()) |
138 | 0 | { |
139 | 0 | auto returnType = m_context.analysis.annotation<TypeInference>(*_function.experimentalReturnExpression()).type; |
140 | 0 | solAssert(returnType); |
141 | 0 | if (!m_env.typeEquals(*returnType, m_context.analysis.typeSystem().type(PrimitiveType::Unit, {}))) |
142 | 0 | { |
143 | | // TODO: destructure tuples. |
144 | 0 | code << " -> " << IRNames::localVariable(*_function.experimentalReturnExpression()) << " "; |
145 | 0 | } |
146 | 0 | } |
147 | 0 | code << "{\n"; |
148 | 0 | for (auto _statement: _function.body().statements()) |
149 | 0 | { |
150 | 0 | IRGeneratorForStatements statementGenerator{m_context}; |
151 | 0 | code << statementGenerator.generate(*_statement); |
152 | 0 | } |
153 | 0 | code << "}\n"; |
154 | 0 | return code.str(); |
155 | 0 | } |