/src/solidity/libyul/backends/evm/EVMDialect.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | * Yul dialects for EVM. |
20 | | */ |
21 | | |
22 | | #include <libyul/backends/evm/EVMDialect.h> |
23 | | |
24 | | #include <libevmasm/Instruction.h> |
25 | | #include <libevmasm/SemanticInformation.h> |
26 | | #include <liblangutil/Exceptions.h> |
27 | | #include <libsolutil/StringUtils.h> |
28 | | #include <libyul/AST.h> |
29 | | #include <libyul/AsmAnalysisInfo.h> |
30 | | #include <libyul/AsmParser.h> |
31 | | #include <libyul/Exceptions.h> |
32 | | #include <libyul/Object.h> |
33 | | #include <libyul/Utilities.h> |
34 | | #include <libyul/backends/evm/AbstractAssembly.h> |
35 | | |
36 | | #include <range/v3/view/reverse.hpp> |
37 | | #include <range/v3/view/tail.hpp> |
38 | | |
39 | | #include <regex> |
40 | | |
41 | | using namespace std; |
42 | | using namespace solidity; |
43 | | using namespace solidity::yul; |
44 | | using namespace solidity::util; |
45 | | |
46 | | namespace |
47 | | { |
48 | | |
49 | | pair<YulString, BuiltinFunctionForEVM> createEVMFunction( |
50 | | string const& _name, |
51 | | evmasm::Instruction _instruction |
52 | | ) |
53 | 14.3M | { |
54 | 14.3M | evmasm::InstructionInfo info = evmasm::instructionInfo(_instruction); |
55 | 14.3M | BuiltinFunctionForEVM f; |
56 | 14.3M | f.name = YulString{_name}; |
57 | 14.3M | f.parameters.resize(static_cast<size_t>(info.args)); |
58 | 14.3M | f.returns.resize(static_cast<size_t>(info.ret)); |
59 | 14.3M | f.sideEffects = EVMDialect::sideEffectsOfInstruction(_instruction); |
60 | 14.3M | if (evmasm::SemanticInformation::terminatesControlFlow(_instruction)) |
61 | 978k | { |
62 | 978k | f.controlFlowSideEffects.canContinue = false; |
63 | 978k | if (evmasm::SemanticInformation::reverts(_instruction)) |
64 | 391k | { |
65 | 391k | f.controlFlowSideEffects.canTerminate = false; |
66 | 391k | f.controlFlowSideEffects.canRevert = true; |
67 | 391k | } |
68 | 587k | else |
69 | 587k | { |
70 | 587k | f.controlFlowSideEffects.canTerminate = true; |
71 | 587k | f.controlFlowSideEffects.canRevert = false; |
72 | 587k | } |
73 | 978k | } |
74 | 14.3M | f.isMSize = _instruction == evmasm::Instruction::MSIZE; |
75 | 14.3M | f.literalArguments.clear(); |
76 | 14.3M | f.instruction = _instruction; |
77 | 14.3M | f.generateCode = [_instruction]( |
78 | 14.3M | FunctionCall const&, |
79 | 14.3M | AbstractAssembly& _assembly, |
80 | 14.3M | BuiltinContext& |
81 | 14.3M | ) { |
82 | 5.22M | _assembly.appendInstruction(_instruction); |
83 | 5.22M | }; |
84 | | |
85 | 14.3M | return {f.name, move(f)}; |
86 | 14.3M | } |
87 | | |
88 | | pair<YulString, BuiltinFunctionForEVM> createFunction( |
89 | | string _name, |
90 | | size_t _params, |
91 | | size_t _returns, |
92 | | SideEffects _sideEffects, |
93 | | vector<optional<LiteralKind>> _literalArguments, |
94 | | std::function<void(FunctionCall const&, AbstractAssembly&, BuiltinContext&)> _generateCode |
95 | | ) |
96 | 852k | { |
97 | 852k | yulAssert(_literalArguments.size() == _params || _literalArguments.empty(), ""); |
98 | | |
99 | 852k | YulString name{std::move(_name)}; |
100 | 852k | BuiltinFunctionForEVM f; |
101 | 852k | f.name = name; |
102 | 852k | f.parameters.resize(_params); |
103 | 852k | f.returns.resize(_returns); |
104 | 852k | f.sideEffects = std::move(_sideEffects); |
105 | 852k | f.literalArguments = std::move(_literalArguments); |
106 | 852k | f.isMSize = false; |
107 | 852k | f.instruction = {}; |
108 | 852k | f.generateCode = std::move(_generateCode); |
109 | 852k | return {name, f}; |
110 | 852k | } |
111 | | |
112 | | set<YulString> createReservedIdentifiers(langutil::EVMVersion _evmVersion) |
113 | 195k | { |
114 | | // TODO remove this in 0.9.0. We allow creating functions or identifiers in Yul with the name |
115 | | // basefee for VMs before london. |
116 | 195k | auto baseFeeException = [&](evmasm::Instruction _instr) -> bool |
117 | 27.9M | { |
118 | 27.9M | return _instr == evmasm::Instruction::BASEFEE && _evmVersion < langutil::EVMVersion::london(); |
119 | 27.9M | }; |
120 | | |
121 | 195k | set<YulString> reserved; |
122 | 195k | for (auto const& instr: evmasm::c_instructions) |
123 | 27.9M | { |
124 | 27.9M | string name = toLower(instr.first); |
125 | 27.9M | if (!baseFeeException(instr.second)) |
126 | 27.9M | reserved.emplace(name); |
127 | 27.9M | } |
128 | 195k | reserved += vector<YulString>{ |
129 | 195k | "linkersymbol"_yulstring, |
130 | 195k | "datasize"_yulstring, |
131 | 195k | "dataoffset"_yulstring, |
132 | 195k | "datacopy"_yulstring, |
133 | 195k | "setimmutable"_yulstring, |
134 | 195k | "loadimmutable"_yulstring, |
135 | 195k | }; |
136 | 195k | return reserved; |
137 | 195k | } |
138 | | |
139 | | map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVersion, bool _objectAccess) |
140 | 195k | { |
141 | 195k | map<YulString, BuiltinFunctionForEVM> builtins; |
142 | 195k | for (auto const& instr: evmasm::c_instructions) |
143 | 27.9M | { |
144 | 27.9M | string name = toLower(instr.first); |
145 | 27.9M | auto const opcode = instr.second; |
146 | | |
147 | 27.9M | if ( |
148 | 27.9M | !evmasm::isDupInstruction(opcode) && |
149 | 27.9M | !evmasm::isSwapInstruction(opcode) && |
150 | 27.9M | !evmasm::isPushInstruction(opcode) && |
151 | 27.9M | opcode != evmasm::Instruction::JUMP && |
152 | 27.9M | opcode != evmasm::Instruction::JUMPI && |
153 | 27.9M | opcode != evmasm::Instruction::JUMPDEST && |
154 | 27.9M | _evmVersion.hasOpcode(opcode) |
155 | 27.9M | ) |
156 | 14.3M | builtins.emplace(createEVMFunction(name, opcode)); |
157 | 27.9M | } |
158 | | |
159 | 195k | if (_objectAccess) |
160 | 121k | { |
161 | 121k | builtins.emplace(createFunction("linkersymbol", 1, 1, SideEffects{}, {LiteralKind::String}, []( |
162 | 121k | FunctionCall const& _call, |
163 | 121k | AbstractAssembly& _assembly, |
164 | 121k | BuiltinContext& |
165 | 121k | ) { |
166 | 0 | yulAssert(_call.arguments.size() == 1, ""); |
167 | 0 | Expression const& arg = _call.arguments.front(); |
168 | 0 | _assembly.appendLinkerSymbol(std::get<Literal>(arg).value.str()); |
169 | 0 | })); |
170 | | |
171 | 121k | builtins.emplace(createFunction( |
172 | 121k | "memoryguard", |
173 | 121k | 1, |
174 | 121k | 1, |
175 | 121k | SideEffects{}, |
176 | 121k | {LiteralKind::Number}, |
177 | 121k | []( |
178 | 121k | FunctionCall const& _call, |
179 | 121k | AbstractAssembly& _assembly, |
180 | 121k | BuiltinContext& |
181 | 121k | ) { |
182 | 0 | yulAssert(_call.arguments.size() == 1, ""); |
183 | 0 | Literal const* literal = get_if<Literal>(&_call.arguments.front()); |
184 | 0 | yulAssert(literal, ""); |
185 | 0 | _assembly.appendConstant(valueOfLiteral(*literal)); |
186 | 0 | }) |
187 | 121k | ); |
188 | | |
189 | 121k | builtins.emplace(createFunction("datasize", 1, 1, SideEffects{}, {LiteralKind::String}, []( |
190 | 121k | FunctionCall const& _call, |
191 | 121k | AbstractAssembly& _assembly, |
192 | 121k | BuiltinContext& _context |
193 | 121k | ) { |
194 | 207 | yulAssert(_context.currentObject, "No object available."); |
195 | 207 | yulAssert(_call.arguments.size() == 1, ""); |
196 | 207 | Expression const& arg = _call.arguments.front(); |
197 | 207 | YulString dataName = std::get<Literal>(arg).value; |
198 | 207 | if (_context.currentObject->name == dataName) |
199 | 71 | _assembly.appendAssemblySize(); |
200 | 136 | else |
201 | 136 | { |
202 | 136 | vector<size_t> subIdPath = |
203 | 136 | _context.subIDs.count(dataName) == 0 ? |
204 | 0 | _context.currentObject->pathToSubObject(dataName) : |
205 | 136 | vector<size_t>{_context.subIDs.at(dataName)}; |
206 | 136 | yulAssert(!subIdPath.empty(), "Could not find assembly object <" + dataName.str() + ">."); |
207 | 136 | _assembly.appendDataSize(subIdPath); |
208 | 136 | } |
209 | 207 | })); |
210 | 121k | builtins.emplace(createFunction("dataoffset", 1, 1, SideEffects{}, {LiteralKind::String}, []( |
211 | 121k | FunctionCall const& _call, |
212 | 121k | AbstractAssembly& _assembly, |
213 | 121k | BuiltinContext& _context |
214 | 121k | ) { |
215 | 146 | yulAssert(_context.currentObject, "No object available."); |
216 | 146 | yulAssert(_call.arguments.size() == 1, ""); |
217 | 146 | Expression const& arg = _call.arguments.front(); |
218 | 146 | YulString dataName = std::get<Literal>(arg).value; |
219 | 146 | if (_context.currentObject->name == dataName) |
220 | 3 | _assembly.appendConstant(0); |
221 | 143 | else |
222 | 143 | { |
223 | 143 | vector<size_t> subIdPath = |
224 | 143 | _context.subIDs.count(dataName) == 0 ? |
225 | 0 | _context.currentObject->pathToSubObject(dataName) : |
226 | 143 | vector<size_t>{_context.subIDs.at(dataName)}; |
227 | 143 | yulAssert(!subIdPath.empty(), "Could not find assembly object <" + dataName.str() + ">."); |
228 | 143 | _assembly.appendDataOffset(subIdPath); |
229 | 143 | } |
230 | 146 | })); |
231 | 121k | builtins.emplace(createFunction( |
232 | 121k | "datacopy", |
233 | 121k | 3, |
234 | 121k | 0, |
235 | 121k | SideEffects{false, true, false, false, true, SideEffects::None, SideEffects::None, SideEffects::Write}, |
236 | 121k | {}, |
237 | 121k | []( |
238 | 121k | FunctionCall const&, |
239 | 121k | AbstractAssembly& _assembly, |
240 | 121k | BuiltinContext& |
241 | 121k | ) { |
242 | 100 | _assembly.appendInstruction(evmasm::Instruction::CODECOPY); |
243 | 100 | } |
244 | 121k | )); |
245 | 121k | builtins.emplace(createFunction( |
246 | 121k | "setimmutable", |
247 | 121k | 3, |
248 | 121k | 0, |
249 | 121k | SideEffects{false, false, false, false, true, SideEffects::None, SideEffects::None, SideEffects::Write}, |
250 | 121k | {std::nullopt, LiteralKind::String, std::nullopt}, |
251 | 121k | []( |
252 | 121k | FunctionCall const& _call, |
253 | 121k | AbstractAssembly& _assembly, |
254 | 121k | BuiltinContext& |
255 | 121k | ) { |
256 | 0 | yulAssert(_call.arguments.size() == 3, ""); |
257 | 0 | YulString identifier = std::get<Literal>(_call.arguments[1]).value; |
258 | 0 | _assembly.appendImmutableAssignment(identifier.str()); |
259 | 0 | } |
260 | 121k | )); |
261 | 121k | builtins.emplace(createFunction( |
262 | 121k | "loadimmutable", |
263 | 121k | 1, |
264 | 121k | 1, |
265 | 121k | SideEffects{}, |
266 | 121k | {LiteralKind::String}, |
267 | 121k | []( |
268 | 121k | FunctionCall const& _call, |
269 | 121k | AbstractAssembly& _assembly, |
270 | 121k | BuiltinContext& |
271 | 121k | ) { |
272 | 0 | yulAssert(_call.arguments.size() == 1, ""); |
273 | 0 | _assembly.appendImmutable(std::get<Literal>(_call.arguments.front()).value.str()); |
274 | 0 | } |
275 | 121k | )); |
276 | 121k | } |
277 | 195k | return builtins; |
278 | 195k | } |
279 | | |
280 | | regex const& verbatimPattern() |
281 | 627M | { |
282 | 627M | regex static const pattern{"verbatim_([1-9]?[0-9])i_([1-9]?[0-9])o"}; |
283 | 627M | return pattern; |
284 | 627M | } |
285 | | |
286 | | } |
287 | | |
288 | | |
289 | | EVMDialect::EVMDialect(langutil::EVMVersion _evmVersion, bool _objectAccess): |
290 | | m_objectAccess(_objectAccess), |
291 | | m_evmVersion(_evmVersion), |
292 | | m_functions(createBuiltins(_evmVersion, _objectAccess)), |
293 | | m_reserved(createReservedIdentifiers(_evmVersion)) |
294 | 195k | { |
295 | 195k | } |
296 | | |
297 | | BuiltinFunctionForEVM const* EVMDialect::builtin(YulString _name) const |
298 | 711M | { |
299 | 711M | if (m_objectAccess) |
300 | 627M | { |
301 | 627M | smatch match; |
302 | 627M | if (regex_match(_name.str(), match, verbatimPattern())) |
303 | 1.33k | return verbatimFunction(stoul(match[1]), stoul(match[2])); |
304 | 627M | } |
305 | 711M | auto it = m_functions.find(_name); |
306 | 711M | if (it != m_functions.end()) |
307 | 592M | return &it->second; |
308 | 119M | else |
309 | 119M | return nullptr; |
310 | 711M | } |
311 | | |
312 | | bool EVMDialect::reservedIdentifier(YulString _name) const |
313 | 92.5M | { |
314 | 92.5M | if (m_objectAccess) |
315 | 80.6M | if (_name.str().substr(0, "verbatim"s.size()) == "verbatim") |
316 | 40 | return true; |
317 | 92.5M | return m_reserved.count(_name) != 0; |
318 | 92.5M | } |
319 | | |
320 | | EVMDialect const& EVMDialect::strictAssemblyForEVM(langutil::EVMVersion _version) |
321 | 11.6M | { |
322 | 11.6M | static map<langutil::EVMVersion, unique_ptr<EVMDialect const>> dialects; |
323 | 11.6M | static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }}; |
324 | 11.6M | if (!dialects[_version]) |
325 | 70.3k | dialects[_version] = make_unique<EVMDialect>(_version, false); |
326 | 11.6M | return *dialects[_version]; |
327 | 11.6M | } |
328 | | |
329 | | EVMDialect const& EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion _version) |
330 | 391k | { |
331 | 391k | static map<langutil::EVMVersion, unique_ptr<EVMDialect const>> dialects; |
332 | 391k | static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }}; |
333 | 391k | if (!dialects[_version]) |
334 | 95.0k | dialects[_version] = make_unique<EVMDialect>(_version, true); |
335 | 391k | return *dialects[_version]; |
336 | 391k | } |
337 | | |
338 | | SideEffects EVMDialect::sideEffectsOfInstruction(evmasm::Instruction _instruction) |
339 | 14.3M | { |
340 | 14.3M | auto translate = [](evmasm::SemanticInformation::Effect _e) -> SideEffects::Effect |
341 | 43.1M | { |
342 | 43.1M | return static_cast<SideEffects::Effect>(_e); |
343 | 43.1M | }; |
344 | | |
345 | 14.3M | return SideEffects{ |
346 | 14.3M | evmasm::SemanticInformation::movable(_instruction), |
347 | 14.3M | evmasm::SemanticInformation::movableApartFromEffects(_instruction), |
348 | 14.3M | evmasm::SemanticInformation::canBeRemoved(_instruction), |
349 | 14.3M | evmasm::SemanticInformation::canBeRemovedIfNoMSize(_instruction), |
350 | 14.3M | true, // cannotLoop |
351 | 14.3M | translate(evmasm::SemanticInformation::otherState(_instruction)), |
352 | 14.3M | translate(evmasm::SemanticInformation::storage(_instruction)), |
353 | 14.3M | translate(evmasm::SemanticInformation::memory(_instruction)), |
354 | 14.3M | }; |
355 | 14.3M | } |
356 | | |
357 | | BuiltinFunctionForEVM const* EVMDialect::verbatimFunction(size_t _arguments, size_t _returnVariables) const |
358 | 1.33k | { |
359 | 1.33k | pair<size_t, size_t> key{_arguments, _returnVariables}; |
360 | 1.33k | shared_ptr<BuiltinFunctionForEVM const>& function = m_verbatimFunctions[key]; |
361 | 1.33k | if (!function) |
362 | 932 | { |
363 | 932 | BuiltinFunctionForEVM builtinFunction = createFunction( |
364 | 932 | "verbatim_" + to_string(_arguments) + "i_" + to_string(_returnVariables) + "o", |
365 | 932 | 1 + _arguments, |
366 | 932 | _returnVariables, |
367 | 932 | SideEffects::worst(), |
368 | 932 | vector<optional<LiteralKind>>{LiteralKind::String} + vector<optional<LiteralKind>>(_arguments), |
369 | 932 | [=]( |
370 | 932 | FunctionCall const& _call, |
371 | 932 | AbstractAssembly& _assembly, |
372 | 932 | BuiltinContext& |
373 | 932 | ) { |
374 | 0 | yulAssert(_call.arguments.size() == (1 + _arguments), ""); |
375 | 0 | Expression const& bytecode = _call.arguments.front(); |
376 | |
|
377 | 0 | _assembly.appendVerbatim( |
378 | 0 | asBytes(std::get<Literal>(bytecode).value.str()), |
379 | 0 | _arguments, |
380 | 0 | _returnVariables |
381 | 0 | ); |
382 | 0 | } |
383 | 932 | ).second; |
384 | 932 | builtinFunction.isMSize = true; |
385 | 932 | function = make_shared<BuiltinFunctionForEVM const>(move(builtinFunction)); |
386 | 932 | } |
387 | 1.33k | return function.get(); |
388 | 1.33k | } |
389 | | |
390 | | EVMDialectTyped::EVMDialectTyped(langutil::EVMVersion _evmVersion, bool _objectAccess): |
391 | | EVMDialect(_evmVersion, _objectAccess) |
392 | 0 | { |
393 | 0 | defaultType = "u256"_yulstring; |
394 | 0 | boolType = "bool"_yulstring; |
395 | 0 | types = {defaultType, boolType}; |
396 | | |
397 | | // Set all types to ``defaultType`` |
398 | 0 | for (auto& fun: m_functions) |
399 | 0 | { |
400 | 0 | for (auto& p: fun.second.parameters) |
401 | 0 | p = defaultType; |
402 | 0 | for (auto& r: fun.second.returns) |
403 | 0 | r = defaultType; |
404 | 0 | } |
405 | |
|
406 | 0 | m_functions["lt"_yulstring].returns = {"bool"_yulstring}; |
407 | 0 | m_functions["gt"_yulstring].returns = {"bool"_yulstring}; |
408 | 0 | m_functions["slt"_yulstring].returns = {"bool"_yulstring}; |
409 | 0 | m_functions["sgt"_yulstring].returns = {"bool"_yulstring}; |
410 | 0 | m_functions["eq"_yulstring].returns = {"bool"_yulstring}; |
411 | | |
412 | | // "not" and "bitnot" replace "iszero" and "not" |
413 | 0 | m_functions["bitnot"_yulstring] = m_functions["not"_yulstring]; |
414 | 0 | m_functions["bitnot"_yulstring].name = "bitnot"_yulstring; |
415 | 0 | m_functions["not"_yulstring] = m_functions["iszero"_yulstring]; |
416 | 0 | m_functions["not"_yulstring].name = "not"_yulstring; |
417 | 0 | m_functions["not"_yulstring].returns = {"bool"_yulstring}; |
418 | 0 | m_functions["not"_yulstring].parameters = {"bool"_yulstring}; |
419 | 0 | m_functions.erase("iszero"_yulstring); |
420 | |
|
421 | 0 | m_functions["bitand"_yulstring] = m_functions["and"_yulstring]; |
422 | 0 | m_functions["bitand"_yulstring].name = "bitand"_yulstring; |
423 | 0 | m_functions["bitor"_yulstring] = m_functions["or"_yulstring]; |
424 | 0 | m_functions["bitor"_yulstring].name = "bitor"_yulstring; |
425 | 0 | m_functions["bitxor"_yulstring] = m_functions["xor"_yulstring]; |
426 | 0 | m_functions["bitxor"_yulstring].name = "bitxor"_yulstring; |
427 | 0 | m_functions["and"_yulstring].parameters = {"bool"_yulstring, "bool"_yulstring}; |
428 | 0 | m_functions["and"_yulstring].returns = {"bool"_yulstring}; |
429 | 0 | m_functions["or"_yulstring].parameters = {"bool"_yulstring, "bool"_yulstring}; |
430 | 0 | m_functions["or"_yulstring].returns = {"bool"_yulstring}; |
431 | 0 | m_functions["xor"_yulstring].parameters = {"bool"_yulstring, "bool"_yulstring}; |
432 | 0 | m_functions["xor"_yulstring].returns = {"bool"_yulstring}; |
433 | 0 | m_functions["popbool"_yulstring] = m_functions["pop"_yulstring]; |
434 | 0 | m_functions["popbool"_yulstring].name = "popbool"_yulstring; |
435 | 0 | m_functions["popbool"_yulstring].parameters = {"bool"_yulstring}; |
436 | 0 | m_functions.insert(createFunction("bool_to_u256", 1, 1, {}, {}, []( |
437 | 0 | FunctionCall const&, |
438 | 0 | AbstractAssembly&, |
439 | 0 | BuiltinContext& |
440 | 0 | ) {})); |
441 | 0 | m_functions["bool_to_u256"_yulstring].parameters = {"bool"_yulstring}; |
442 | 0 | m_functions["bool_to_u256"_yulstring].returns = {"u256"_yulstring}; |
443 | 0 | m_functions.insert(createFunction("u256_to_bool", 1, 1, {}, {}, []( |
444 | 0 | FunctionCall const&, |
445 | 0 | AbstractAssembly& _assembly, |
446 | 0 | BuiltinContext& |
447 | 0 | ) { |
448 | | // TODO this should use a Panic. |
449 | | // A value larger than 1 causes an invalid instruction. |
450 | 0 | _assembly.appendConstant(2); |
451 | 0 | _assembly.appendInstruction(evmasm::Instruction::DUP2); |
452 | 0 | _assembly.appendInstruction(evmasm::Instruction::LT); |
453 | 0 | AbstractAssembly::LabelID inRange = _assembly.newLabelId(); |
454 | 0 | _assembly.appendJumpToIf(inRange); |
455 | 0 | _assembly.appendInstruction(evmasm::Instruction::INVALID); |
456 | 0 | _assembly.appendLabel(inRange); |
457 | 0 | })); |
458 | 0 | m_functions["u256_to_bool"_yulstring].parameters = {"u256"_yulstring}; |
459 | 0 | m_functions["u256_to_bool"_yulstring].returns = {"bool"_yulstring}; |
460 | 0 | } |
461 | | |
462 | | BuiltinFunctionForEVM const* EVMDialectTyped::discardFunction(YulString _type) const |
463 | 0 | { |
464 | 0 | if (_type == "bool"_yulstring) |
465 | 0 | return builtin("popbool"_yulstring); |
466 | 0 | else |
467 | 0 | { |
468 | 0 | yulAssert(_type == defaultType, ""); |
469 | 0 | return builtin("pop"_yulstring); |
470 | 0 | } |
471 | 0 | } |
472 | | |
473 | | BuiltinFunctionForEVM const* EVMDialectTyped::equalityFunction(YulString _type) const |
474 | 0 | { |
475 | 0 | if (_type == "bool"_yulstring) |
476 | 0 | return nullptr; |
477 | 0 | else |
478 | 0 | { |
479 | 0 | yulAssert(_type == defaultType, ""); |
480 | 0 | return builtin("eq"_yulstring); |
481 | 0 | } |
482 | 0 | } |
483 | | |
484 | | EVMDialectTyped const& EVMDialectTyped::instance(langutil::EVMVersion _version) |
485 | 0 | { |
486 | 0 | static map<langutil::EVMVersion, unique_ptr<EVMDialectTyped const>> dialects; |
487 | 0 | static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }}; |
488 | 0 | if (!dialects[_version]) |
489 | 0 | dialects[_version] = make_unique<EVMDialectTyped>(_version, true); |
490 | 0 | return *dialects[_version]; |
491 | 0 | } |