solang/sema/yul/
builtin.rs

1// SPDX-License-Identifier: Apache-2.0
2
3use crate::Target;
4use phf::{phf_map, phf_set};
5use std::fmt;
6
7#[allow(unused)]
8pub struct YulBuiltinPrototype {
9    pub name: &'static str,
10    pub no_args: u8,
11    pub no_returns: u8,
12    pub doc: &'static str,
13    pub ty: YulBuiltInFunction,
14    pub stops_execution: bool,
15    pub availability: [bool; 3],
16}
17
18impl YulBuiltinPrototype {
19    /// Checks if a certain Yul builtin is available for the given target
20    pub fn is_available(&self, target: &Target) -> bool {
21        match target {
22            Target::EVM => self.availability[0],
23            Target::Polkadot { .. } => self.availability[1],
24            Target::Solana => self.availability[2],
25            Target::Soroban => unimplemented!(),
26        }
27    }
28}
29
30// The enums declaration order should match that of the static vector containing the builtins
31#[derive(Clone, Debug, PartialEq, Eq, Copy)]
32#[repr(u8)]
33pub enum YulBuiltInFunction {
34    Stop = 0,
35    Add = 1,
36    Sub = 2,
37    Mul = 3,
38    Div = 4,
39    SDiv = 5,
40    Mod = 6,
41    SMod = 7,
42    Exp = 8,
43    Not = 9,
44    Lt = 10,
45    Gt = 11,
46    Slt = 12,
47    Sgt = 13,
48    Eq = 14,
49    IsZero = 15,
50    And = 16,
51    Or = 17,
52    Xor = 18,
53    Byte = 19,
54    Shl = 20,
55    Shr = 21,
56    Sar = 22,
57    AddMod = 23,
58    MulMod = 24,
59    SignExtend = 25,
60    Keccak256 = 26,
61    Pc = 27,
62    Pop = 28,
63    MLoad = 29,
64    MStore = 30,
65    MStore8 = 31,
66    SLoad = 32,
67    SStore = 33,
68    MSize = 34,
69    Gas = 35,
70    Address = 36,
71    Balance = 37,
72    SelfBalance = 38,
73    Caller = 39,
74    CallValue = 40,
75    CallDataLoad = 41,
76    CallDataSize = 42,
77    CallDataCopy = 43,
78    CodeSize = 44,
79    CodeCopy = 45,
80    ExtCodeSize = 46,
81    ExtCodeCopy = 47,
82    ReturnDataSize = 48,
83    ReturnDataCopy = 49,
84    ExtCodeHash = 50,
85    Create = 51,
86    Create2 = 52,
87    Call = 53,
88    CallCode = 54,
89    DelegateCall = 55,
90    StaticCall = 56,
91    Return = 57,
92    Revert = 58,
93    SelfDestruct = 59,
94    Invalid = 60,
95    Log0 = 61,
96    Log1 = 62,
97    Log2 = 63,
98    Log3 = 64,
99    Log4 = 65,
100    ChainId = 66,
101    BaseFee = 67,
102    Origin = 68,
103    GasPrice = 69,
104    BlockHash = 70,
105    CoinBase = 71,
106    Timestamp = 72,
107    Number = 73,
108    Difficulty = 74,
109    GasLimit = 75,
110    PrevRandao = 76,
111}
112
113// These are functions that do high level stuff in a contract and are not yet implemented.
114static UNSUPPORTED_BUILTINS: phf::Set<&'static str> = phf_set! {
115    "datasize", "dataoffset", "datacopy", "setimmutable", "loadimmutable",
116    "linkersymbol", "memoryguard"
117};
118
119/// Checks if bultin function is unsupported
120pub(crate) fn yul_unsupported_builtin(name: &str) -> bool {
121    UNSUPPORTED_BUILTINS.contains(name)
122}
123
124static BUILTIN_YUL_FUNCTIONS: phf::Map<&'static str, YulBuiltInFunction> = phf_map! {
125    "stop" => YulBuiltInFunction::Stop,
126    "add" => YulBuiltInFunction::Add,
127    "sub" => YulBuiltInFunction::Sub,
128    "mul" => YulBuiltInFunction::Mul,
129    "div" => YulBuiltInFunction::Div,
130    "sdiv" => YulBuiltInFunction::SDiv,
131    "mod" => YulBuiltInFunction::Mod,
132    "smod" => YulBuiltInFunction::SMod,
133    "exp" => YulBuiltInFunction::Exp,
134    "not" => YulBuiltInFunction::Not,
135    "lt" => YulBuiltInFunction::Lt,
136    "gt" => YulBuiltInFunction::Gt,
137    "slt" => YulBuiltInFunction::Slt,
138    "sgt" => YulBuiltInFunction::Sgt,
139    "eq" => YulBuiltInFunction::Eq,
140    "iszero" => YulBuiltInFunction::IsZero,
141    "and" => YulBuiltInFunction::And,
142    "or" => YulBuiltInFunction::Or,
143    "xor" => YulBuiltInFunction::Xor,
144    "byte" => YulBuiltInFunction::Byte,
145    "shl" => YulBuiltInFunction::Shl,
146    "shr" => YulBuiltInFunction::Shr,
147    "sar" => YulBuiltInFunction::Sar,
148    "addmod" => YulBuiltInFunction::AddMod,
149    "mulmod" => YulBuiltInFunction::MulMod,
150    "signextend" => YulBuiltInFunction::SignExtend,
151    "keccak256" => YulBuiltInFunction::Keccak256,
152    "pc" => YulBuiltInFunction::Pc,
153    "pop" => YulBuiltInFunction::Pop,
154    "mload" => YulBuiltInFunction::MLoad,
155    "mstore" => YulBuiltInFunction::MStore,
156    "mstore8" => YulBuiltInFunction::MStore8,
157    "sload" => YulBuiltInFunction::SLoad,
158    "sstore" => YulBuiltInFunction::SStore,
159    "msize" => YulBuiltInFunction::MSize,
160    "gas" => YulBuiltInFunction::Gas,
161    "address" => YulBuiltInFunction::Address,
162    "balance" => YulBuiltInFunction::Balance,
163    "selfbalance" => YulBuiltInFunction::SelfBalance,
164    "caller" => YulBuiltInFunction::Caller,
165    "callvalue" => YulBuiltInFunction::CallValue,
166    "calldataload" => YulBuiltInFunction::CallDataLoad,
167    "calldatasize" => YulBuiltInFunction::CallDataSize,
168    "calldatacopy" => YulBuiltInFunction::CallDataCopy,
169    "codesize" => YulBuiltInFunction::CodeSize,
170    "codecopy" => YulBuiltInFunction::CodeCopy,
171    "extcodesize" => YulBuiltInFunction::ExtCodeSize,
172    "extcodecopy" => YulBuiltInFunction::ExtCodeCopy,
173    "returndatasize" => YulBuiltInFunction::ReturnDataSize,
174    "returndatacopy" => YulBuiltInFunction::ReturnDataCopy,
175    "extcodehash" => YulBuiltInFunction::ExtCodeHash,
176    "create" => YulBuiltInFunction::Create,
177    "create2" => YulBuiltInFunction::Create2,
178    "call" => YulBuiltInFunction::Call,
179    "callcode" => YulBuiltInFunction::CallCode,
180    "delegatecall" => YulBuiltInFunction::DelegateCall,
181    "staticcall" => YulBuiltInFunction::StaticCall,
182    "return" => YulBuiltInFunction::Return,
183    "revert" => YulBuiltInFunction::Revert,
184    "selfdestruct" => YulBuiltInFunction::SelfDestruct,
185    "invalid" => YulBuiltInFunction::Invalid,
186    "log0" => YulBuiltInFunction::Log0,
187    "log1" => YulBuiltInFunction::Log1,
188    "log2" => YulBuiltInFunction::Log2,
189    "log3" => YulBuiltInFunction::Log3,
190    "log4" => YulBuiltInFunction::Log4,
191    "chainid" => YulBuiltInFunction::ChainId,
192    "basefee" => YulBuiltInFunction::BaseFee,
193    "origin" => YulBuiltInFunction::Origin,
194    "gasprice" => YulBuiltInFunction::GasPrice,
195    "blockhash" => YulBuiltInFunction::BlockHash,
196    "coinbase" => YulBuiltInFunction::CoinBase,
197    "timestamp" => YulBuiltInFunction::Timestamp,
198    "number" => YulBuiltInFunction::Number,
199    "difficulty" => YulBuiltInFunction::Difficulty,
200    "gaslimit" => YulBuiltInFunction::GasLimit,
201    "prevrandao" => YulBuiltInFunction::PrevRandao,
202};
203
204/// Retrieved the builtin function type from an identifier name
205pub fn parse_builtin_keyword(keyword: &str) -> Option<&YulBuiltInFunction> {
206    BUILTIN_YUL_FUNCTIONS.get(keyword)
207}
208
209impl YulBuiltInFunction {
210    /// Retrieve the prototype from the enum type
211    pub(crate) fn get_prototype_info(self) -> &'static YulBuiltinPrototype {
212        let index = self as usize;
213        &YUL_BUILTIN[index]
214    }
215
216    pub(crate) fn modify_state(self) -> bool {
217        matches!(
218            self,
219            YulBuiltInFunction::SStore
220                | YulBuiltInFunction::Log0
221                | YulBuiltInFunction::Log1
222                | YulBuiltInFunction::Log2
223                | YulBuiltInFunction::Log3
224                | YulBuiltInFunction::Log4
225                | YulBuiltInFunction::Create
226                | YulBuiltInFunction::Call
227                | YulBuiltInFunction::CallCode
228                | YulBuiltInFunction::DelegateCall
229                | YulBuiltInFunction::Create2
230                | YulBuiltInFunction::SelfDestruct
231        )
232    }
233
234    pub(crate) fn read_state(self) -> bool {
235        matches!(
236            self,
237            YulBuiltInFunction::Address
238                | YulBuiltInFunction::SelfBalance
239                | YulBuiltInFunction::Balance
240                | YulBuiltInFunction::Origin
241                | YulBuiltInFunction::Caller
242                | YulBuiltInFunction::CallValue
243                | YulBuiltInFunction::ChainId
244                | YulBuiltInFunction::BaseFee
245                | YulBuiltInFunction::PrevRandao
246                | YulBuiltInFunction::Gas
247                | YulBuiltInFunction::GasPrice
248                | YulBuiltInFunction::ExtCodeSize
249                | YulBuiltInFunction::ExtCodeCopy
250                | YulBuiltInFunction::ExtCodeHash
251                | YulBuiltInFunction::BlockHash
252                | YulBuiltInFunction::CoinBase
253                | YulBuiltInFunction::Timestamp
254                | YulBuiltInFunction::Number
255                | YulBuiltInFunction::Difficulty
256                | YulBuiltInFunction::GasLimit
257                | YulBuiltInFunction::StaticCall
258                | YulBuiltInFunction::SLoad
259        )
260    }
261}
262
263impl fmt::Display for YulBuiltInFunction {
264    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
265        let prototype = self.get_prototype_info();
266        f.write_str(prototype.name)
267    }
268}
269
270// Yul built-in functions.
271// Descriptions copied and slightly modified from: https://docs.soliditylang.org/en/v0.8.12/yul.html
272static YUL_BUILTIN: [YulBuiltinPrototype; 77] =
273    [
274        YulBuiltinPrototype {
275            name: "stop",
276            no_args: 0,
277            no_returns: 0,
278            doc: "Stop execution",
279            ty: YulBuiltInFunction::Stop,
280            stops_execution: true,
281            availability: [true, false, false],
282        },
283        YulBuiltinPrototype {
284            name: "add",
285            no_args: 2,
286            no_returns: 1,
287            doc: "add(x, y) returns x + y",
288            ty: YulBuiltInFunction::Add,
289            stops_execution: false,
290            availability: [true, true, true],
291        },
292        YulBuiltinPrototype {
293            name: "sub",
294            no_args: 2,
295            no_returns: 1,
296            doc: "sub(x, y) returns x - y",
297            ty: YulBuiltInFunction::Sub,
298            stops_execution: false,
299            availability: [true, true, true],
300        },
301        YulBuiltinPrototype {
302            name: "mul",
303            no_args: 2,
304            no_returns: 1,
305            doc: "mul(x, y) returns x*y",
306            ty: YulBuiltInFunction::Mul,
307            stops_execution: false,
308            availability: [true, true, true],
309        },
310        YulBuiltinPrototype {
311            name: "div",
312            no_args: 2,
313            no_returns: 1,
314            doc: "div(x, y) returns x/y or 0 if y == 0",
315            ty: YulBuiltInFunction::Div,
316            stops_execution: false,
317            availability: [true, true, true],
318        },
319        YulBuiltinPrototype {
320            name: "sdiv",
321            no_args: 2,
322            no_returns: 1,
323            doc: "sdiv(x, y) returns x/y or 0 if y==0. Used for signed numbers in two's complement",
324            ty: YulBuiltInFunction::SDiv,
325            stops_execution: false,
326            availability: [true, true, true],
327        },
328        YulBuiltinPrototype {
329            name: "mod",
330            no_args: 2,
331            no_returns: 1,
332            doc: "mod(x, y) returns x % y or 0 if y == 0",
333            ty: YulBuiltInFunction::Mod,
334            stops_execution: false,
335            availability: [true, true, true],
336        },
337        YulBuiltinPrototype {
338            name: "smod",
339            no_args: 2,
340            no_returns: 1,
341            doc: "smod(x, y) returns x % y or 0 if y == 0. Used for signed numbers in two's complement",
342            ty: YulBuiltInFunction::SMod,
343            stops_execution: false,
344            availability: [true, true, true],
345        },
346        YulBuiltinPrototype {
347            name: "exp",
348            no_args: 2,
349            no_returns: 1,
350            doc: "exp(x, y) returns x to the power of y",
351            ty: YulBuiltInFunction::Exp,
352            stops_execution: false,
353            availability: [true, true, true],
354        },
355        YulBuiltinPrototype {
356            name: "not",
357            no_args: 1,
358            no_returns: 1,
359            doc: "not(x): bitwise \"not\" of x (every bit is negated)",
360            ty: YulBuiltInFunction::Not,
361            stops_execution: false,
362            availability: [true, true, true],
363        },
364        YulBuiltinPrototype {
365            name: "lt",
366            no_args: 2,
367            no_returns: 1,
368            doc: "lt(x, y) returns 1 if x < y, 0 otherwise",
369            ty: YulBuiltInFunction::Lt,
370            stops_execution: false,
371            availability: [true, true, true],
372        },
373        YulBuiltinPrototype {
374            name: "gt",
375            no_args: 2,
376            no_returns: 1,
377            doc: "gt(x, y) returns 1 if x > y, 0 otherwise",
378            ty: YulBuiltInFunction::Gt,
379            stops_execution: false,
380            availability: [true, true, true],
381        },
382        YulBuiltinPrototype {
383            name: "slt",
384            no_args: 2,
385            no_returns: 1,
386            doc: "slt(x, y) returns 1 if x > y, 0 otherwise. Used for signed numbers in two's complement",
387            ty: YulBuiltInFunction::Slt,
388            stops_execution: false,
389            availability: [true, true, true],
390        },
391        YulBuiltinPrototype {
392            name: "sgt",
393            no_args: 2,
394            no_returns: 1,
395            doc: "sgt(x, y) returns 1 if x > y, 0 otherwise. Used for signed numbers in two's complement",
396            ty: YulBuiltInFunction::Sgt,
397            stops_execution: false,
398            availability: [true, true, true],
399        },
400        YulBuiltinPrototype {
401            name: "eq",
402            no_args: 2,
403            no_returns: 1,
404            doc: "eq(x, y) returns 1 if x == y, 0 otherwise",
405            ty: YulBuiltInFunction::Eq,
406            stops_execution: false,
407            availability: [true, true, true],
408        },
409        YulBuiltinPrototype {
410            name: "iszero",
411            no_args: 1,
412            no_returns: 1,
413            doc: "iszero(x) returns 1 if x == 0, 0 otherwise",
414            ty: YulBuiltInFunction::IsZero,
415            stops_execution: false,
416            availability: [true, true, true],
417        },
418        YulBuiltinPrototype {
419            name: "and",
420            no_args: 2,
421            no_returns: 1,
422            doc: "and(x, y) returns the bitwise \"and\" between x and y",
423            ty: YulBuiltInFunction::And,
424            stops_execution: false,
425            availability: [true, true, true],
426        },
427        YulBuiltinPrototype {
428            name: "or",
429            no_args: 2,
430            no_returns: 1,
431            doc: "or(x, y) returns the bitwise \"or\" between x and y",
432            ty: YulBuiltInFunction::Or,
433            stops_execution: false,
434            availability: [true, true, true],
435        },
436        YulBuiltinPrototype {
437            name: "xor",
438            no_args: 2,
439            no_returns: 1,
440            doc: "xor(x, y) returns the bitwise \"xor\" between x and y",
441            ty: YulBuiltInFunction::Xor,
442            stops_execution: false,
443            availability: [true, true, true],
444        },
445        YulBuiltinPrototype {
446            name: "byte",
447            no_args: 2,
448            no_returns: 1,
449            doc: "byte(n, x) returns the nth byte of x, where the most significant byte is the 0th",
450            ty: YulBuiltInFunction::Byte,
451            stops_execution: false,
452            availability: [true, true, true],
453        },
454        YulBuiltinPrototype {
455            name: "shl",
456            no_args: 2,
457            no_returns: 1,
458            doc: "shl(x, y) returns the logical shift left of y by x bits",
459            ty: YulBuiltInFunction::Shl,
460            stops_execution: false,
461            availability: [true, true, true],
462        },
463        YulBuiltinPrototype {
464            name: "shr",
465            no_args: 2,
466            no_returns: 1,
467            doc: "shr(x, y) returns the logical shift right of y by x bits",
468            ty: YulBuiltInFunction::Shr,
469            stops_execution: false,
470            availability: [true, true, true],
471        },
472        YulBuiltinPrototype {
473            name: "sar",
474            no_args: 2,
475            no_returns: 1,
476            doc: "signed arithmetic shift right y by x bits",
477            ty: YulBuiltInFunction::Sar,
478            stops_execution: false,
479            availability: [true, true, true],
480        },
481        YulBuiltinPrototype {
482            name: "addmod",
483            no_args: 3,
484            no_returns: 1,
485            doc: "addmod(x, y, m) returns (x + y) % m or 0 if m == 0",
486            ty: YulBuiltInFunction::AddMod,
487            stops_execution: false,
488            availability: [true, true, true],
489        },
490        YulBuiltinPrototype {
491            name: "mulmod",
492            no_args: 3,
493            no_returns: 1,
494            doc: "mulmod(x, y, m) returns (x * y) % m or 0 if m == 0",
495            ty: YulBuiltInFunction::MulMod,
496            stops_execution: false,
497            availability: [true, true, true],
498        },
499        YulBuiltinPrototype {
500            name: "signextend",
501            no_args: 2,
502            no_returns: 1,
503            doc: "signextend(i, x) sign extends from (i*8+7)th bit counting from least significant",
504            ty: YulBuiltInFunction::SignExtend,
505            stops_execution: false,
506            availability: [true, false, false],
507        },
508        YulBuiltinPrototype {
509            name: "keccak256",
510            no_args: 2,
511            no_returns: 1,
512            doc: "keccak256(p, n) performs keccak(mem[p...(p+n)])",
513            ty: YulBuiltInFunction::Keccak256,
514            stops_execution: false,
515            availability: [true, false, false],
516        },
517        YulBuiltinPrototype {
518            name: "pc",
519            no_args: 0,
520            no_returns: 1,
521            doc: "Returns the current position in code, i.e. the program counter",
522            ty: YulBuiltInFunction::Pc,
523            stops_execution: false,
524            availability: [true, false, false],
525        },
526        YulBuiltinPrototype {
527            name: "pop",
528            no_args: 1,
529            no_returns: 0,
530            doc: "pop(x) discard value x",
531            ty: YulBuiltInFunction::Pop,
532            stops_execution: false,
533            availability: [true, false, false],
534        },
535        YulBuiltinPrototype {
536            name: "mload",
537            no_args: 1,
538            no_returns: 1,
539            doc: "mload(p) returns mem[p...(p+32)]",
540            ty: YulBuiltInFunction::MLoad,
541            stops_execution: false,
542            availability: [true, false, false],
543        },
544        YulBuiltinPrototype {
545            name: "mstore",
546            no_args: 2,
547            no_returns: 0,
548            doc: "mstore(p, v) stores v into mem[p...(p+32)]",
549            ty: YulBuiltInFunction::MStore,
550            stops_execution: false,
551            availability: [true, false, false],
552        },
553        YulBuiltinPrototype {
554            name: "mstore8",
555            no_args: 2,
556            no_returns: 0,
557            doc: "mstore8(p, v) stores (v & 0xff) into mem[p] (modified a single byte of v)",
558            ty: YulBuiltInFunction::MStore8,
559            stops_execution: false,
560            availability: [true, false, false],
561        },
562        YulBuiltinPrototype {
563            name: "sload",
564            no_args: 1,
565            no_returns: 1,
566            doc: "sload(p) returns storage[p], i.e. memory on contract's storage",
567            ty: YulBuiltInFunction::SLoad,
568            stops_execution: false,
569            availability: [true, false, false],
570        },
571        YulBuiltinPrototype {
572            name: "sstore",
573            no_args: 2,
574            no_returns: 0,
575            doc: "sstore(p) stores v into storage[p]",
576            ty: YulBuiltInFunction::SStore,
577            stops_execution: false,
578            availability: [true, false, false],
579        },
580        YulBuiltinPrototype {
581            name: "msize",
582            no_args: 0,
583            no_returns: 1,
584            doc: "Returns the size of memory, i.e largest accessed memory index",
585            ty: YulBuiltInFunction::MSize,
586            stops_execution: false,
587            availability: [true, false, false],
588        },
589        YulBuiltinPrototype {
590            name: "gas",
591            no_args: 0,
592            no_returns: 1,
593            doc: "Returns gas still available to execution",
594            ty: YulBuiltInFunction::Gas,
595            stops_execution: false,
596            availability: [true, true, false],
597        },
598        YulBuiltinPrototype {
599            name: "address",
600            no_args: 0,
601            no_returns: 1,
602            doc: "Returns the address of the current contract / execution context",
603            ty: YulBuiltInFunction::Address,
604            stops_execution: false,
605            availability: [true, true, true],
606        },
607        YulBuiltinPrototype {
608            name: "balance",
609            no_args: 1,
610            no_returns: 1,
611            doc: "balance(a) returns the wei balance at address a",
612            ty: YulBuiltInFunction::Balance,
613            stops_execution: false,
614            availability: [true, true, false],
615        },
616        YulBuiltinPrototype {
617            name: "selfbalance",
618            no_args: 0,
619            no_returns: 1,
620            doc: "Returns the wei balance at the address of the current contract / execution context",
621            ty: YulBuiltInFunction::SelfBalance,
622            stops_execution: false,
623            availability: [true, true, false],
624        },
625        YulBuiltinPrototype {
626            name: "caller",
627            no_args: 0,
628            no_returns: 1,
629            doc: "Returns the call sender",
630            ty: YulBuiltInFunction::Caller,
631            stops_execution: false,
632            availability: [true, true, false],
633        },
634        YulBuiltinPrototype {
635            name: "callvalue",
636            no_args: 0,
637            no_returns: 1,
638            doc: "Returns the wei sent together with the current call",
639            ty: YulBuiltInFunction::CallValue,
640            stops_execution: false,
641            availability: [true, true, false],
642        },
643        YulBuiltinPrototype {
644            name: "calldataload",
645            no_args: 1,
646            no_returns: 1,
647            doc: "calldataload(p) returns call data starting from position p (32 bytes)",
648            ty: YulBuiltInFunction::CallDataLoad,
649            stops_execution: false,
650            availability: [true, false, false],
651        },
652        YulBuiltinPrototype {
653            name: "calldatasize",
654            no_args: 0,
655            no_returns: 1,
656            doc: "Returns the size of call data in bytes",
657            ty: YulBuiltInFunction::CallDataSize,
658            stops_execution: false,
659            availability: [true, false, false],
660        },
661        YulBuiltinPrototype {
662            name: "calldatacopy",
663            no_args: 3,
664            no_returns: 0,
665            doc: "calldatacopy(t, f, s) copies s bytes from calldata at position f to mem at position t",
666            ty: YulBuiltInFunction::CallDataCopy,
667            stops_execution: false,
668            availability: [true, false, false],
669        },
670        YulBuiltinPrototype {
671            name: "codesize",
672            no_args: 0,
673            no_returns: 1,
674            doc: "Returns the size of the current contract / execution context",
675            ty: YulBuiltInFunction::CodeSize,
676            stops_execution: false,
677            availability: [true, false, false],
678        },
679        YulBuiltinPrototype {
680            name: "codecopy",
681            no_args: 3,
682            no_returns: 0,
683            doc: "codecopy(t, f, s) copies s bytes from code at position f to mem at position t",
684            ty: YulBuiltInFunction::CodeCopy,
685            stops_execution: false,
686            availability: [true, false, false],
687        },
688        YulBuiltinPrototype {
689            name: "extcodesize",
690            no_args: 1,
691            no_returns: 1,
692            doc: "extcodesize(a) returns the size of the code at address a",
693            ty: YulBuiltInFunction::ExtCodeSize,
694            stops_execution: false,
695            availability: [true, false, false],
696        },
697        YulBuiltinPrototype {
698            name: "extcodecopy",
699            no_args: 4,
700            no_returns: 0,
701            doc: "extcodecopy(a, t, f, s) copies s bytes from code located at address a at position f to mem at position t",
702            ty: YulBuiltInFunction::ExtCodeCopy,
703            stops_execution: false,
704            availability: [true, false, false],
705        },
706        YulBuiltinPrototype {
707            name: "returndatasize",
708            no_args: 0,
709            no_returns: 1,
710            doc: "Returns the size of the last returndata",
711            ty: YulBuiltInFunction::ReturnDataSize,
712            stops_execution: false,
713            availability: [true, false, false],
714        },
715        YulBuiltinPrototype {
716            name: "returndatacopy",
717            no_args: 3,
718            no_returns: 0,
719            doc: "returndatacopy(t, f, s) copy s bytes from return data at position f to mem at position t",
720            ty: YulBuiltInFunction::ReturnDataCopy,
721            stops_execution: false,
722            availability: [true, false, false],
723        },
724        YulBuiltinPrototype {
725            name: "extcodehash",
726            no_args: 1,
727            no_returns: 1,
728            doc: "extcodehash(a) returns the code hash of address a",
729            ty: YulBuiltInFunction::ExtCodeHash,
730            stops_execution: false,
731            availability: [true, false, false],
732        },
733        YulBuiltinPrototype {
734            name: "create",
735            no_args: 3,
736            no_returns: 1,
737            doc: "create(v, p, n) creates new contract with code mem[p..(p+n)] and sends v wei. It returns the new address or 0 on error",
738            ty: YulBuiltInFunction::Create,
739            stops_execution: false,
740            availability: [true, false, false],
741        },
742        YulBuiltinPrototype {
743            name: "create2",
744            no_args: 4,
745            no_returns: 1,
746            doc: "create2(v, p, n, s) new contract with code mem[p...(p+n)] at address keccak256(0xff . this . s . keccak256(mem[p...(p+n)]) and sends v wei.\n 0xff is a 1 byte value, 'this' is the current contract's address as a 20 byte value and 's' is a big endian 256-bit value. it returns 0 on error.",
747            ty: YulBuiltInFunction::Create2,
748            stops_execution: false,
749            availability: [true, false, false],
750        },
751        YulBuiltinPrototype {
752            name: "call",
753            no_args: 7,
754            no_returns: 1,
755            doc: "call(g, a, v, in, insize, out, outsize) calls contract at address a with input mem[in...(in+insize)] providing f cas and v wei and outputs area mem[out...(out+outsize)]. It returns 0 on error and 1 on success",
756            ty: YulBuiltInFunction::Call,
757            stops_execution: false,
758            availability: [true, false, false],
759        },
760        YulBuiltinPrototype {
761            name: "callcode",
762            no_args: 7,
763            no_returns: 1,
764            doc: "Identical to call(g, a, v, in, insize, out, outsize), but only use the code from a and stay in the context of the current contract otherwise",
765            ty: YulBuiltInFunction::CallCode,
766            stops_execution: false,
767            availability: [true, false, false],
768        },
769        YulBuiltinPrototype {
770            name: "delegatecall",
771            no_args: 6,
772            no_returns: 1,
773            doc: "Identical to 'callcode' but also keep caller and callvalue",
774            ty: YulBuiltInFunction::DelegateCall,
775            stops_execution: false,
776            availability: [true, false, false],
777        },
778        YulBuiltinPrototype {
779            name: "staticcall",
780            no_args: 6,
781            no_returns: 1,
782            doc: "Identical to call(g, a, 0, in, insize, out, outsize), but do not allow state modifications",
783            ty: YulBuiltInFunction::StaticCall,
784            stops_execution: false,
785            availability: [true, false, false],
786        },
787        YulBuiltinPrototype {
788            name: "return",
789            no_args: 2,
790            no_returns: 0,
791            doc: "return(p, s) ends execution and returns data mem[p...(p+s)]",
792            ty: YulBuiltInFunction::Return,
793            stops_execution: true,
794            availability: [true, false, false],
795        },
796        YulBuiltinPrototype {
797            name: "revert",
798            no_args: 2,
799            no_returns: 0,
800            doc: "revert(p, s) ends execution, reverts state changes and returns data mem[p...(p+s)]",
801            ty: YulBuiltInFunction::Revert,
802            stops_execution: true,
803            availability: [true, false, false],
804        },
805        YulBuiltinPrototype {
806            name: "selfdestruct",
807            no_args: 1,
808            no_returns: 0,
809            doc: "selfdestruct(a) ends execution, destroy current contract and sends funds to a",
810            ty: YulBuiltInFunction::SelfDestruct,
811            stops_execution: true,
812            availability: [true, true, true],
813        },
814        YulBuiltinPrototype {
815            name: "invalid",
816            no_args: 0,
817            no_returns: 0,
818            doc: "Ends execution with invalid instruction",
819            ty: YulBuiltInFunction::Invalid,
820            stops_execution: true,
821            availability: [true, true, true],
822        },
823        YulBuiltinPrototype {
824            name: "log0",
825            no_args: 2,
826            no_returns: 0,
827            doc: "log(p, s): log without topics and data mem[p...(p+s)]",
828            ty: YulBuiltInFunction::Log0,
829            stops_execution: false,
830            availability: [true, false, false],
831        },
832        YulBuiltinPrototype {
833            name: "log1",
834            no_args: 3,
835            no_returns: 0,
836            doc: "log1(p, s, t1): log with topic t1 and data mem[p...(p+s)]",
837            ty: YulBuiltInFunction::Log1,
838            stops_execution: false,
839            availability: [true, false, false],
840        },
841        YulBuiltinPrototype {
842            name: "log2",
843            no_args: 4,
844            no_returns: 0,
845            doc: "log2(p, s, t1, t2): log with topics t1, t2 and data mem[p...(p+s)]",
846            ty: YulBuiltInFunction::Log2,
847            stops_execution: false,
848            availability: [true, false, false],
849        },
850        YulBuiltinPrototype {
851            name: "log3",
852            no_args: 5,
853            no_returns: 0,
854            doc: "log3(p, s, t1, t2, t3): log with topics t1, t2, t3 and data mem[p...(p+s)]",
855            ty: YulBuiltInFunction::Log3,
856            stops_execution: false,
857            availability: [true, false, false],
858        },
859        YulBuiltinPrototype {
860            name: "log4",
861            no_args: 6,
862            no_returns: 0,
863            doc: "log4(p, s, t1, t2, t3, t4): log with topics t1, t2, t3, t4 with data mem[p...(p+s)]",
864            ty: YulBuiltInFunction::Log4,
865            stops_execution: false,
866            availability: [true, false, false],
867        },
868        YulBuiltinPrototype {
869            name: "chainid",
870            no_args: 0,
871            no_returns: 1,
872            doc: "Returns the ID of the executing chain",
873            ty: YulBuiltInFunction::ChainId,
874            stops_execution: false,
875            availability: [true, false, false],
876        },
877        YulBuiltinPrototype {
878            name: "basefee",
879            no_args: 0,
880            no_returns: 1,
881            doc: "Return the current block's base fee",
882            ty: YulBuiltInFunction::BaseFee,
883            stops_execution: false,
884            availability: [true, false, false],
885        },
886        YulBuiltinPrototype {
887            name: "origin",
888            no_args: 0,
889            no_returns: 1,
890            doc: "Returns the transaction sender",
891            ty: YulBuiltInFunction::Origin,
892            stops_execution: false,
893            availability: [true, true, true],
894        },
895        YulBuiltinPrototype {
896            name: "gasprice",
897            no_args: 0,
898            no_returns: 1,
899            doc: "Returns the gas price of the transaction",
900            ty: YulBuiltInFunction::GasPrice,
901            stops_execution: false,
902            availability: [true, true, false],
903        },
904        YulBuiltinPrototype {
905            name: "blockhash",
906            no_args: 1,
907            no_returns: 1,
908            doc: "blockhash(b) return the hash of block #b - only valid for the last 256 executing block excluding current",
909            ty: YulBuiltInFunction::BlockHash,
910            stops_execution: false,
911            availability: [true, false, false],
912        },
913        YulBuiltinPrototype {
914            name: "coinbase",
915            no_args: 0,
916            no_returns: 1,
917            doc: "Returns the current mining beneficiary",
918            ty: YulBuiltInFunction::CoinBase,
919            stops_execution: false,
920            availability: [true, false, false],
921        },
922        YulBuiltinPrototype {
923            name: "timestamp",
924            no_args: 0,
925            no_returns: 1,
926            doc: "Returns the timestamp of the current block in seconds since the epoch",
927            ty: YulBuiltInFunction::Timestamp,
928            stops_execution: false,
929            availability: [true, true, true],
930        },
931        YulBuiltinPrototype {
932            name: "number",
933            no_args: 0,
934            no_returns: 1,
935            doc: "Returns the current block's number",
936            ty: YulBuiltInFunction::Number,
937            stops_execution: false,
938            availability: [true, true, true],
939        },
940        YulBuiltinPrototype {
941            name: "difficulty",
942            no_args: 0,
943            no_returns: 1,
944            doc: "Returns the difficulty of the current block",
945            ty: YulBuiltInFunction::Difficulty,
946            stops_execution: false,
947            availability: [true, false, false],
948        },
949        YulBuiltinPrototype {
950            name: "gaslimit",
951            no_args: 0,
952            no_returns: 1,
953            doc: "Returns the current block's gas limit",
954            ty: YulBuiltInFunction::GasLimit,
955            stops_execution: false,
956            availability: [true, false, false],
957        },
958        YulBuiltinPrototype {
959            name: "prevrandao",
960            no_args: 0,
961            no_returns: 1,
962            doc: "Random number provided by the beacon chain",
963            ty: YulBuiltInFunction::PrevRandao,
964            stops_execution: false,
965            availability: [true, false, false],
966        },
967    ];
968
969#[test]
970fn test_builtin_indexes() {
971    for item in &YUL_BUILTIN {
972        let name = item.name;
973        let ty = item.ty;
974
975        let parsed_ty = parse_builtin_keyword(name).unwrap();
976        assert_eq!(ty, *parsed_ty);
977        assert_eq!(name, parsed_ty.get_prototype_info().name);
978    }
979}