2018-06-05 17:43:23 +00:00
###
Yul
###
2017-04-18 12:12:04 +00:00
2018-06-05 17:43:23 +00:00
.. _yul:
2017-04-18 12:12:04 +00:00
2018-06-05 17:43:23 +00:00
.. index :: ! assembly, ! asm, ! evmasm, ! yul, julia, iulia
2017-04-18 12:12:04 +00:00
2019-03-13 16:17:33 +00:00
Yul (previously also called JULIA or IULIA) is an intermediate language that can be
compiled to bytecode for different backends.
Support for EVM 1.0, EVM 1.5 and eWASM is planned, and it is designed to be a usable common denominator of all three
platforms. It can already be used for "inline assembly" inside Solidity and future versions of the Solidity compiler
will use Yul as an intermediate language. Yul is a good target for high-level optimisation stages that can benefit all target platforms equally.
With the "inline assembly" flavour, Yul can be used as a language setting
2017-04-21 14:34:40 +00:00
for the :ref: `standard-json interface <compiler-api>` :
::
{
"language": "Yul",
"sources": { "input.yul": { "content": "{ sstore(0, 1) }" } },
"settings": {
"outputSelection": { "*": { "* ": ["*"], "": [ "* " ] } },
"optimizer": { "enabled": true, "details": { "yul": true } }
}
}
2019-03-13 16:17:33 +00:00
And on the command line interface with the `` --strict-assembly `` parameter.
2017-04-21 14:34:40 +00:00
2019-03-13 16:17:33 +00:00
.. warning ::
2018-01-04 16:19:45 +00:00
2019-03-13 16:17:33 +00:00
Yul is in active development and bytecode generation is fully implemented only for untyped Yul (everything is `` u256 `` )
and with EVM 1.0 as target, :ref: `EVM opcodes <opcodes>` are used as built-in functions.
2018-01-04 16:19:45 +00:00
2018-06-05 17:43:23 +00:00
The core components of Yul are functions, blocks, variables, literals,
2017-11-22 13:17:31 +00:00
for-loops, if-statements, switch-statements, expressions and assignments to variables.
2017-04-18 12:12:04 +00:00
2018-06-05 17:43:23 +00:00
Yul is typed, both variables and literals must specify the type with postfix
2017-04-18 15:40:31 +00:00
notation. The supported types are `` bool `` , `` u8 `` , `` s8 `` , `` u32 `` , `` s32 `` ,
`` u64 `` , `` s64 `` , `` u128 `` , `` s128 `` , `` u256 `` and `` s256 `` .
2018-06-05 17:43:23 +00:00
Yul in itself does not even provide operators. If the EVM is targeted,
2017-04-18 12:12:04 +00:00
opcodes will be available as built-in functions, but they can be reimplemented
2017-04-18 12:41:16 +00:00
if the backend changes. For a list of mandatory built-in functions, see the section below.
2017-04-18 12:12:04 +00:00
The following example program assumes that the EVM opcodes `` mul `` , `` div ``
and `` mod `` are available either natively or as functions and computes exponentiation.
2019-05-10 04:11:23 +00:00
As per the warning above, the following code is untyped and can be compiled using `` solc --strict-assembly `` .
2017-04-18 12:12:04 +00:00
.. code ::
{
2019-05-10 04:11:23 +00:00
function power(base, exponent) -> result
2017-04-18 12:12:04 +00:00
{
switch exponent
2019-05-10 04:11:23 +00:00
case 0 { result := 1 }
case 1 { result := base }
2018-10-10 18:54:21 +00:00
default
2017-04-18 12:12:04 +00:00
{
2019-05-10 04:11:23 +00:00
result := power(mul(base, base), div(exponent, 2))
switch mod(exponent, 2)
case 1 { result := mul(base, result) }
2017-04-18 12:12:04 +00:00
}
}
}
It is also possible to implement the same function using a for-loop
2017-07-12 16:07:02 +00:00
instead of with recursion. Here, we need the EVM opcodes `` lt `` (less-than)
2017-04-18 12:12:04 +00:00
and `` add `` to be available.
.. code ::
{
2019-05-10 04:11:23 +00:00
function power(base, exponent) -> result
2017-04-18 12:12:04 +00:00
{
2019-05-10 04:11:23 +00:00
result := 1
for { let i := 0 } lt(i, exponent) { i := add(i, 1) }
2017-04-18 12:12:04 +00:00
{
result := mul(result, base)
}
}
}
2018-06-05 17:43:23 +00:00
Specification of Yul
====================
2017-04-18 12:12:04 +00:00
2018-06-05 17:43:23 +00:00
This chapter describes Yul code. It is usually placed inside a Yul object, which is described in the following chapter.
2017-04-21 16:35:56 +00:00
2017-04-18 12:12:04 +00:00
Grammar::
Block = '{' Statement* '}'
Statement =
Block |
FunctionDefinition |
VariableDeclaration |
Assignment |
2018-09-29 17:42:44 +00:00
If |
2017-04-18 12:12:04 +00:00
Expression |
Switch |
ForLoop |
2019-10-28 14:25:02 +00:00
BreakContinue |
Leave
2017-04-18 12:12:04 +00:00
FunctionDefinition =
2017-04-21 16:04:27 +00:00
'function' Identifier '(' TypedIdentifierList? ')'
( '->' TypedIdentifierList )? Block
2017-04-18 12:12:04 +00:00
VariableDeclaration =
2017-04-21 16:04:27 +00:00
'let' TypedIdentifierList ( ':=' Expression )?
2017-04-18 12:12:04 +00:00
Assignment =
2017-04-21 16:04:27 +00:00
IdentifierList ':=' Expression
2017-04-18 12:12:04 +00:00
Expression =
FunctionCall | Identifier | Literal
2017-11-22 13:17:31 +00:00
If =
'if' Expression Block
2017-04-18 12:12:04 +00:00
Switch =
2018-09-10 05:51:51 +00:00
'switch' Expression ( Case+ Default? | Default )
2017-04-18 12:12:04 +00:00
Case =
2017-05-19 22:15:07 +00:00
'case' Literal Block
2018-09-10 05:51:51 +00:00
Default =
'default' Block
2017-04-18 12:12:04 +00:00
ForLoop =
'for' Block Expression Block Block
BreakContinue =
'break' | 'continue'
2019-10-28 14:25:02 +00:00
Leave = 'leave'
2017-04-18 12:12:04 +00:00
FunctionCall =
Identifier '(' ( Expression ( ',' Expression )* )? ')'
2019-04-24 11:16:43 +00:00
Identifier = [a-zA-Z_$] [a-zA-Z_$0-9.]*
2017-04-18 12:12:04 +00:00
IdentifierList = Identifier ( ',' Identifier)*
2017-04-21 16:35:44 +00:00
TypeName = Identifier | BuiltinTypeName
BuiltinTypeName = 'bool' | [us] ( '8' | '32' | '64' | '128' | '256' )
TypedIdentifierList = Identifier ':' TypeName ( ',' Identifier ':' TypeName )*
2017-04-18 12:12:04 +00:00
Literal =
2017-05-19 23:05:14 +00:00
(NumberLiteral | StringLiteral | HexLiteral | TrueLiteral | FalseLiteral) ':' TypeName
2017-04-18 12:12:04 +00:00
NumberLiteral = HexNumber | DecimalNumber
HexLiteral = 'hex' ('"' ([0-9a-fA-F]{2})* '"' | '\'' ([0-9a-fA-F]{2})* '\'')
StringLiteral = '"' ([^"\r\n\\] | '\\' .)* '"'
2017-05-19 23:05:14 +00:00
TrueLiteral = 'true'
FalseLiteral = 'false'
2017-04-18 12:12:04 +00:00
HexNumber = '0x' [0-9a-fA-F]+
DecimalNumber = [0-9]+
Restrictions on the Grammar
---------------------------
2017-07-12 18:09:13 +00:00
Switches must have at least one case (including the default case).
2019-01-15 12:40:10 +00:00
If all possible values of the expression are covered, a default case should
not be allowed (i.e. a switch with a `` bool `` expression that has both a
true and a false case should not allow a default case). All case values need to
have the same type.
2017-04-21 16:49:04 +00:00
2017-07-12 18:09:13 +00:00
Every expression evaluates to zero or more values. Identifiers and Literals
evaluate to exactly
2017-04-21 12:56:19 +00:00
one value and function calls evaluate to a number of values equal to the
2017-07-12 18:09:13 +00:00
number of return values of the function called.
2017-04-18 12:12:04 +00:00
2017-07-12 18:09:13 +00:00
In variable declarations and assignments, the right-hand-side expression
2017-04-21 12:56:19 +00:00
(if present) has to evaluate to a number of values equal to the number of
variables on the left-hand-side.
2017-07-12 18:09:13 +00:00
This is the only situation where an expression evaluating
to more than one value is allowed.
2017-04-21 12:56:19 +00:00
2017-07-12 18:09:13 +00:00
Expressions that are also statements (i.e. at the block level) have to
evaluate to zero values.
2017-04-21 12:56:19 +00:00
2017-07-12 18:09:13 +00:00
In all other situations, expressions have to evaluate to exactly one value.
The `` continue `` and `` break `` statements can only be used inside loop bodies
and have to be in the same function as the loop (or both have to be at the
top level).
2019-10-28 14:25:02 +00:00
The `` leave `` statement can only be used inside a function.
2017-04-21 12:56:19 +00:00
The condition part of the for-loop has to evaluate to exactly one value.
2019-11-20 15:47:38 +00:00
Functions cannot be defined anywhere inside for loop init blocks.
2017-04-21 12:56:19 +00:00
2017-04-21 15:58:55 +00:00
Literals cannot be larger than the their type. The largest type defined is 256-bit wide.
2017-04-18 12:12:04 +00:00
2017-07-12 18:09:13 +00:00
Scoping Rules
-------------
2018-06-05 17:43:23 +00:00
Scopes in Yul are tied to Blocks (exceptions are functions and the for loop
2017-07-12 18:09:13 +00:00
as explained below) and all declarations
(`` FunctionDefinition `` , `` VariableDeclaration `` )
introduce new identifiers into these scopes.
Identifiers are visible in
the block they are defined in (including all sub-nodes and sub-blocks).
2019-11-19 15:10:46 +00:00
As an exception, identifiers defined directly in the "init" part of the for-loop
2017-07-12 18:09:13 +00:00
(the first block) are visible in all other parts of the for-loop
(but not outside of the loop).
Identifiers declared in the other parts of the for loop respect the regular
2018-12-21 15:49:11 +00:00
syntactical scoping rules.
2019-11-19 15:10:46 +00:00
This means a for-loop of the form `` for { I... } C { P... } { B... } `` is equivalent
to `` { I... for {} C { P... } { B... } } `` .
2017-07-12 18:09:13 +00:00
The parameters and return parameters of functions are visible in the
function body and their names cannot overlap.
Variables can only be referenced after their declaration. In particular,
variables cannot be referenced in the right hand side of their own variable
declaration.
Functions can be referenced already before their declaration (if they are visible).
Shadowing is disallowed, i.e. you cannot declare an identifier at a point
where another identifier with the same name is also visible, even if it is
not accessible.
Inside functions, it is not possible to access a variable that was declared
outside of that function.
2017-04-18 12:12:04 +00:00
Formal Specification
--------------------
2018-06-05 17:43:23 +00:00
We formally specify Yul by providing an evaluation function E overloaded
2017-04-18 12:12:04 +00:00
on the various nodes of the AST. Any functions can have side effects, so
2017-07-12 18:09:13 +00:00
E takes two state objects and the AST node and returns two new
state objects and a variable number of other values.
The two state objects are the global state object
2017-04-18 12:12:04 +00:00
(which in the context of the EVM is the memory, storage and state of the
2017-07-12 18:09:13 +00:00
blockchain) and the local state object (the state of local variables, i.e. a
2017-04-18 12:12:04 +00:00
segment of the stack in the EVM).
2017-07-12 18:09:13 +00:00
If the AST node is a statement, E returns the two state objects and a "mode",
2019-10-28 14:25:02 +00:00
which is used for the `` break `` , `` continue `` and `` leave `` statements.
2017-07-12 18:09:13 +00:00
If the AST node is an expression, E returns the two state objects and
as many values as the expression evaluates to.
2017-04-18 12:12:04 +00:00
2017-04-21 10:22:58 +00:00
The exact nature of the global state is unspecified for this high level
2017-07-12 18:09:13 +00:00
description. The local state `` L `` is a mapping of identifiers `` i `` to values `` v `` ,
denoted as `` L[i] = v `` .
For an identifier `` v `` , let `` $v `` be the name of the identifier.
We will use a destructuring notation for the AST nodes.
2017-04-18 12:12:04 +00:00
.. code ::
E(G, L, <{St1, ..., Stn}>: Block) =
2017-07-12 18:09:13 +00:00
let G1, L1, mode = E(G, L, St1, ..., Stn)
let L2 be a restriction of L1 to the identifiers of L
G1, L2, mode
2017-04-21 12:56:19 +00:00
E(G, L, St1, ..., Stn: Statement) =
if n is zero:
2017-08-07 14:28:10 +00:00
G, L, regular
2017-04-21 12:56:19 +00:00
else:
2017-07-12 18:09:13 +00:00
let G1, L1, mode = E(G, L, St1)
2017-04-21 12:56:19 +00:00
if mode is regular then
2017-07-12 18:09:13 +00:00
E(G1, L1, St2, ..., Stn)
2017-04-21 12:56:19 +00:00
otherwise
2017-07-12 18:09:13 +00:00
G1, L1, mode
E(G, L, FunctionDefinition) =
2017-04-21 12:56:19 +00:00
G, L, regular
2019-09-12 17:36:37 +00:00
E(G, L, <let var_1, ..., var_n := rhs>: VariableDeclaration) =
E(G, L, <var_1, ..., var_n := rhs>: Assignment)
E(G, L, <let var_1, ..., var_n>: VariableDeclaration) =
let L1 be a copy of L where L1[$var_i] = 0 for i = 1, ..., n
2017-07-12 18:09:13 +00:00
G, L1, regular
2019-09-12 17:36:37 +00:00
E(G, L, <var_1, ..., var_n := rhs>: Assignment) =
2017-07-12 18:09:13 +00:00
let G1, L1, v1, ..., vn = E(G, L, rhs)
2019-09-12 17:36:37 +00:00
let L2 be a copy of L1 where L2[$var_i] = vi for i = 1, ..., n
2017-07-12 18:09:13 +00:00
G, L2, regular
2017-04-21 12:56:19 +00:00
E(G, L, <for { i1, ..., in } condition post body>: ForLoop) =
if n >= 1:
2019-10-28 14:25:02 +00:00
let G1, L, mode = E(G, L, i1, ..., in)
// mode has to be regular or leave due to the syntactic restrictions
if mode is leave then
G1, L1 restricted to variables of L, leave
otherwise
let G2, L2, mode = E(G1, L1, for {} condition post body)
G2, L2 restricted to variables of L, mode
2017-04-21 12:56:19 +00:00
else:
2017-07-12 18:09:13 +00:00
let G1, L1, v = E(G, L, condition)
2017-04-21 12:56:19 +00:00
if v is false:
2017-07-12 18:09:13 +00:00
G1, L1, regular
2017-04-21 12:56:19 +00:00
else:
2017-07-12 18:09:13 +00:00
let G2, L2, mode = E(G1, L, body)
2017-04-21 12:56:19 +00:00
if mode is break:
2017-07-12 18:09:13 +00:00
G2, L2, regular
2019-10-28 14:25:02 +00:00
otherwise if mode is leave:
G2, L2, leave
2017-04-21 12:56:19 +00:00
else:
2017-07-12 18:09:13 +00:00
G3, L3, mode = E(G2, L2, post)
2019-10-28 14:25:02 +00:00
if mode is leave:
G2, L3, leave
otherwise
E(G3, L3, for {} condition post body)
2017-04-21 12:56:19 +00:00
E(G, L, break: BreakContinue) =
G, L, break
E(G, L, continue: BreakContinue) =
G, L, continue
2019-10-28 14:25:02 +00:00
E(G, L, leave: Leave) =
G, L, leave
2017-11-22 13:17:31 +00:00
E(G, L, <if condition body>: If) =
let G0, L0, v = E(G, L, condition)
2017-11-23 17:52:04 +00:00
if v is true:
2017-11-22 13:17:31 +00:00
E(G0, L0, body)
else:
G0, L0, regular
2017-08-15 19:15:43 +00:00
E(G, L, <switch condition case l1:t1 st1 ... case ln:tn stn>: Switch) =
2017-11-22 13:17:31 +00:00
E(G, L, switch condition case l1:t1 st1 ... case ln:tn stn default {})
2017-08-15 19:15:43 +00:00
E(G, L, <switch condition case l1:t1 st1 ... case ln:tn stn default st'>: Switch) =
let G0, L0, v = E(G, L, condition)
// i = 1 .. n
// Evaluate literals, context doesn't matter
2017-08-16 10:29:12 +00:00
let _, _, v1 = E(G0, L0, l1)
2017-08-15 19:15:43 +00:00
...
2017-08-16 10:29:12 +00:00
let _, _, vn = E(G0, L0, ln)
2017-08-15 19:15:43 +00:00
if there exists smallest i such that vi = v:
E(G0, L0, sti)
else:
E(G0, L0, st')
2017-04-21 12:56:19 +00:00
E(G, L, <name>: Identifier) =
2017-08-07 14:28:10 +00:00
G, L, L[$name]
2017-04-21 12:56:19 +00:00
E(G, L, <fname(arg1, ..., argn)>: FunctionCall) =
2017-04-18 12:12:04 +00:00
G1, L1, vn = E(G, L, argn)
...
G(n-1), L(n-1), v2 = E(G(n-2), L(n-2), arg2)
Gn, Ln, v1 = E(G(n-1), L(n-1), arg1)
2017-04-21 10:22:58 +00:00
Let <function fname (param1, ..., paramn) -> ret1, ..., retm block>
2017-07-12 18:09:13 +00:00
be the function of name $fname visible at the point of the call.
2017-04-21 12:56:19 +00:00
Let L' be a new local state such that
2017-07-12 18:09:13 +00:00
L'[$parami] = vi and L'[$reti] = 0 for all i.
2017-08-07 14:28:10 +00:00
Let G'', L'', mode = E(Gn, L', block)
G'', Ln, L''[$ret1], ..., L''[$retm]
2017-04-18 12:12:04 +00:00
E(G, L, l: HexLiteral) = G, L, hexString(l),
2017-07-12 18:09:13 +00:00
where hexString decodes l from hex and left-aligns it into 32 bytes
2017-04-18 12:12:04 +00:00
E(G, L, l: StringLiteral) = G, L, utf8EncodeLeftAligned(l),
where utf8EncodeLeftAligned performs a utf8 encoding of l
and aligns it left into 32 bytes
E(G, L, n: HexNumber) = G, L, hex(n)
where hex is the hexadecimal decoding function
E(G, L, n: DecimalNumber) = G, L, dec(n),
where dec is the decimal decoding function
2017-04-18 12:41:16 +00:00
2017-04-20 11:48:49 +00:00
Type Conversion Functions
-------------------------
2018-06-05 17:43:23 +00:00
Yul has no support for implicit type conversion and therefore functions exist to provide explicit conversion.
2017-04-20 11:48:49 +00:00
When converting a larger type to a shorter type a runtime exception can occur in case of an overflow.
2018-05-09 14:58:31 +00:00
Truncating conversions are supported between the following types:
- `` bool ``
- `` u32 ``
- `` u64 ``
- `` u256 ``
- `` s256 ``
For each of these a type conversion function exists having the prototype in the form of `` <input_type>to<output_type>(x:<input_type>) -> y:<output_type> `` ,
such as `` u32tobool(x:u32) -> y:bool `` , `` u256tou32(x:u256) -> y:u32 `` or `` s256tou256(x:s256) -> y:u256 `` .
2017-11-22 17:25:40 +00:00
.. note ::
`` u32tobool(x:u32) -> y:bool `` can be implemented as `` y := not(iszerou256(x)) `` and
`` booltou32(x:bool) -> y:u32 `` can be implemented as `` switch x case true:bool { y := 1:u32 } case false:bool { y := 0:u32 } ``
2017-04-20 11:48:49 +00:00
2017-04-18 12:41:16 +00:00
Low-level Functions
-------------------
The following functions must be available:
+---------------------------------------------------------------------------------------------------------------+
2017-11-22 17:25:40 +00:00
| *Logic* |
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| not(x:bool) ‑ > z:bool | logical not |
2017-11-22 17:25:40 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| and(x:bool, y:bool) ‑ > z:bool | logical and |
2017-11-22 17:25:40 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| or(x:bool, y:bool) ‑ > z:bool | logical or |
2017-11-22 17:25:40 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| xor(x:bool, y:bool) ‑ > z:bool | xor |
2017-11-22 17:25:40 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2018-07-10 07:17:33 +00:00
| *Arithmetic* |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| addu256(x:u256, y:u256) ‑ > z:u256 | x + y |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| subu256(x:u256, y:u256) ‑ > z:u256 | x - y |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| mulu256(x:u256, y:u256) ‑ > z:u256 | x * y |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| divu256(x:u256, y:u256) ‑ > z:u256 | x / y |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| divs256(x:s256, y:s256) ‑ > z:s256 | x / y, for signed numbers in two's complement |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| modu256(x:u256, y:u256) ‑ > z:u256 | x % y |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| mods256(x:s256, y:s256) ‑ > z:s256 | x % y, for signed numbers in two's complement |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| signextendu256(i:u256, x:u256) ‑ > z:u256 | sign extend from (i*8+7)th bit counting from least significant |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| expu256(x:u256, y:u256) ‑ > z:u256 | x to the power of y |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| addmodu256(x:u256, y:u256, m:u256) ‑ > z:u256| (x + y) % m with arbitrary precision arithmetic |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| mulmodu256(x:u256, y:u256, m:u256) ‑ > z:u256| (x * y) % m with arbitrary precision arithmetic |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| ltu256(x:u256, y:u256) ‑ > z:bool | true if x < y, false otherwise |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| gtu256(x:u256, y:u256) ‑ > z:bool | true if x > y, false otherwise |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| lts256(x:s256, y:s256) ‑ > z:bool | true if x < y, false otherwise |
2017-11-22 17:25:40 +00:00
| | (for signed numbers in two's complement) |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| gts256(x:s256, y:s256) ‑ > z:bool | true if x > y, false otherwise |
2017-11-22 17:25:40 +00:00
| | (for signed numbers in two's complement) |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| equ256(x:u256, y:u256) ‑ > z:bool | true if x == y, false otherwise |
2017-11-22 17:25:40 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| iszerou256(x:u256) ‑ > z:bool | true if x == 0, false otherwise |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| notu256(x:u256) ‑ > z:u256 | ~x, every bit of x is negated |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| andu256(x:u256, y:u256) ‑ > z:u256 | bitwise and of x and y |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| oru256(x:u256, y:u256) ‑ > z:u256 | bitwise or of x and y |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| xoru256(x:u256, y:u256) ‑ > z:u256 | bitwise xor of x and y |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| shlu256(x:u256, y:u256) ‑ > z:u256 | logical left shift of x by y |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| shru256(x:u256, y:u256) ‑ > z:u256 | logical right shift of x by y |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| sars256(x:s256, y:u256) ‑ > z:u256 | arithmetic right shift of x by y |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| byte(n:u256, x:u256) ‑ > v:u256 | nth byte of x, where the most significant byte is the 0th byte |
2018-02-27 00:43:12 +00:00
| | Cannot this be just replaced by and256(shr256(n, x), 0xff) and |
| | let it be optimised out by the EVM backend? |
+---------------------------------------------+-----------------------------------------------------------------+
2017-04-18 12:41:16 +00:00
| *Memory and storage* |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| mload(p:u256) ‑ > v:u256 | mem[p..(p+32)) |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2017-04-20 11:57:02 +00:00
| mstore(p:u256, v:u256) | mem[p..(p+32)) := v |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2017-04-20 11:57:02 +00:00
| mstore8(p:u256, v:u256) | mem[p] := v & 0xff - only modifies a single byte |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| sload(p:u256) ‑ > v:u256 | storage[p] |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2017-04-20 11:57:02 +00:00
| sstore(p:u256, v:u256) | storage[p] := v |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| msize() ‑ > size:u256 | size of memory, i.e. largest accessed memory index, albeit due |
2017-04-18 12:41:16 +00:00
| | due to the memory extension function, which extends by words, |
| | this will always be a multiple of 32 bytes |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2017-04-18 12:41:16 +00:00
| *Execution control* |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2018-10-10 09:50:49 +00:00
| create(v:u256, p:u256, n:u256) | create new contract with code mem[p..(p+n)) and send v wei |
2017-04-18 12:41:16 +00:00
| | and return the new address |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2018-10-10 09:50:49 +00:00
| create2(v:u256, p:u256, n:u256, s:u256) | create new contract with code mem[p...(p+n)) at address |
| | keccak256(0xff . this . s . keccak256(mem[p...(p+n))) |
2018-09-27 23:08:19 +00:00
| | and send v wei and return the new address, where `` 0xff `` is a |
2018-10-10 09:50:49 +00:00
| | 8 byte value, `` this `` is the current contract's address |
| | as a 20 byte value and `` s `` is a big-endian 256-bit value |
2018-09-27 23:08:19 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2017-04-20 11:57:02 +00:00
| call(g:u256, a:u256, v:u256, in:u256, | call contract at address a with input mem[in..(in+insize)) |
| insize:u256, out:u256, | providing g gas and v wei and output area |
| outsize:u256) | mem[out..(out+outsize)) returning 0 on error (eg. out of gas) |
2019-03-13 13:34:05 +00:00
| ‑ > r:u256 | and 1 on success |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2017-04-20 11:57:02 +00:00
| callcode(g:u256, a:u256, v:u256, in:u256, | identical to `` call `` but only use the code from a |
| insize:u256, out:u256, | and stay in the context of the |
2019-03-13 13:34:05 +00:00
| outsize:u256) ‑ > r:u256 | current contract otherwise |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2017-04-20 11:57:02 +00:00
| delegatecall(g:u256, a:u256, in:u256, | identical to `` callcode `` , |
| insize:u256, out:u256, | but also keep `` caller `` |
2019-03-13 13:34:05 +00:00
| outsize:u256) ‑ > r:u256 | and `` callvalue `` |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2017-04-18 12:41:16 +00:00
| abort() | abort (equals to invalid instruction on EVM) |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2017-04-20 11:57:02 +00:00
| return(p:u256, s:u256) | end execution, return data mem[p..(p+s)) |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2017-04-20 11:57:02 +00:00
| revert(p:u256, s:u256) | end execution, revert state changes, return data mem[p..(p+s)) |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2017-04-20 11:57:02 +00:00
| selfdestruct(a:u256) | end execution, destroy current contract and send funds to a |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2017-04-20 11:57:02 +00:00
| log0(p:u256, s:u256) | log without topics and data mem[p..(p+s)) |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2017-04-20 11:57:02 +00:00
| log1(p:u256, s:u256, t1:u256) | log with topic t1 and data mem[p..(p+s)) |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2017-04-20 11:57:02 +00:00
| log2(p:u256, s:u256, t1:u256, t2:u256) | log with topics t1, t2 and data mem[p..(p+s)) |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2017-04-20 11:57:02 +00:00
| log3(p:u256, s:u256, t1:u256, t2:u256, | log with topics t, t2, t3 and data mem[p..(p+s)) |
| t3:u256) | |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2017-04-20 11:57:02 +00:00
| log4(p:u256, s:u256, t1:u256, t2:u256, | log with topics t1, t2, t3, t4 and data mem[p..(p+s)) |
| t3:u256, t4:u256) | |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2017-04-18 12:41:16 +00:00
| *State queries* |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| blockcoinbase() ‑ > address:u256 | current mining beneficiary |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| blockdifficulty() ‑ > difficulty:u256 | difficulty of the current block |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| blockgaslimit() ‑ > limit:u256 | block gas limit of the current block |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| blockhash(b:u256) ‑ > hash:u256 | hash of block nr b - only for last 256 blocks excluding current |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| blocknumber() ‑ > block:u256 | current block number |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| blocktimestamp() ‑ > timestamp:u256 | timestamp of the current block in seconds since the epoch |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| txorigin() ‑ > address:u256 | transaction sender |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| txgasprice() ‑ > price:u256 | gas price of the transaction |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| gasleft() ‑ > gas:u256 | gas still available to execution |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| balance(a:u256) ‑ > v:u256 | wei balance at address a |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| this() ‑ > address:u256 | address of the current contract / execution context |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| caller() ‑ > address:u256 | call sender (excluding delegatecall) |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| callvalue() ‑ > v:u256 | wei sent together with the current call |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| calldataload(p:u256) ‑ > v:u256 | call data starting from position p (32 bytes) |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| calldatasize() ‑ > v:u256 | size of call data in bytes |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2017-04-20 11:57:02 +00:00
| calldatacopy(t:u256, f:u256, s:u256) | copy s bytes from calldata at position f to mem at position t |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| codesize() ‑ > size:u256 | size of the code of the current contract / execution context |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2017-04-20 11:57:02 +00:00
| codecopy(t:u256, f:u256, s:u256) | copy s bytes from code at position f to mem at position t |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| extcodesize(a:u256) ‑ > size:u256 | size of the code at address a |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2017-04-20 11:57:02 +00:00
| extcodecopy(a:u256, t:u256, f:u256, s:u256) | like codecopy(t, f, s) but take code at address a |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2018-09-27 23:08:19 +00:00
| extcodehash(a:u256) | code hash of address a |
+---------------------------------------------+-----------------------------------------------------------------+
2017-04-18 12:41:16 +00:00
| *Others* |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2017-11-22 17:25:40 +00:00
| discard(unused:bool) | discard value |
+---------------------------------------------+-----------------------------------------------------------------+
2017-04-20 11:57:02 +00:00
| discardu256(unused:u256) | discard value |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| splitu256tou64(x:u256) ‑ > (x1:u64, x2:u64, | split u256 to four u64's |
2018-05-16 00:11:27 +00:00
| x3:u64, x4:u64) | |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2017-04-20 11:57:28 +00:00
| combineu64tou256(x1:u64, x2:u64, x3:u64, | combine four u64's into a single u256 |
2019-03-13 13:34:05 +00:00
| x4:u64) ‑ > (x:u256) | |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| keccak256(p:u256, s:u256) ‑ > v:u256 | keccak(mem[p...(p+s))) |
2018-02-27 00:43:12 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2018-11-14 16:33:02 +00:00
| *Object access* | |
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| datasize(name:string) ‑ > size:u256 | size of the data object in bytes, name has to be string literal |
2018-11-14 16:33:02 +00:00
+---------------------------------------------+-----------------------------------------------------------------+
2019-03-13 13:34:05 +00:00
| dataoffset(name:string) ‑ > offset:u256 | offset of the data object inside the data area in bytes, |
2018-11-14 16:33:02 +00:00
| | name has to be string literal |
+---------------------------------------------+-----------------------------------------------------------------+
| datacopy(dst:u256, src:u256, len:u256) | copy len bytes from the data area starting at offset src bytes |
| | to memory at position dst |
+---------------------------------------------+-----------------------------------------------------------------+
2017-04-19 12:40:56 +00:00
Backends
--------
2018-06-05 17:43:23 +00:00
Backends or targets are the translators from Yul to a specific bytecode. Each of the backends can expose functions
2017-04-19 12:40:56 +00:00
prefixed with the name of the backend. We reserve `` evm_ `` and `` ewasm_ `` prefixes for the two proposed backends.
Backend: EVM
------------
The EVM target will have all the underlying EVM opcodes exposed with the `evm_` prefix.
Backend: "EVM 1.5"
------------------
TBD
Backend: eWASM
--------------
TBD
2017-04-21 16:35:56 +00:00
2018-06-05 17:43:23 +00:00
Specification of Yul Object
===========================
2017-04-21 16:35:56 +00:00
2018-11-14 16:33:02 +00:00
Yul objects are used to group named code and data sections.
The functions `` datasize `` , `` dataoffset `` and `` datacopy ``
can be used to access these sections from within code.
Hex strings can be used to specify data in hex encoding,
regular strings in native encoding. For code,
`` datacopy `` will access its assembled binary representation.
2017-04-21 16:35:56 +00:00
Grammar::
2018-11-28 10:32:05 +00:00
Object = 'object' StringLiteral '{' Code ( Object | Data )* '}'
2017-04-21 16:35:56 +00:00
Code = 'code' Block
2018-11-14 16:33:02 +00:00
Data = 'data' StringLiteral ( HexLiteral | StringLiteral )
2017-04-21 16:35:56 +00:00
HexLiteral = 'hex' ('"' ([0-9a-fA-F]{2})* '"' | '\'' ([0-9a-fA-F]{2})* '\'')
StringLiteral = '"' ([^"\r\n\\] | '\\' .)* '"'
2018-06-05 17:43:23 +00:00
Above, `` Block `` refers to `` Block `` in the Yul code grammar explained in the previous chapter.
2017-04-21 16:35:56 +00:00
2018-06-05 17:43:23 +00:00
An example Yul Object is shown below:
2017-04-21 16:35:56 +00:00
2018-06-05 05:48:25 +00:00
.. code ::
2017-04-21 16:35:56 +00:00
// Code consists of a single object. A single "code" node is the code of the object.
// Every (other) named object or data section is serialized and
// made accessible to the special built-in functions datacopy / dataoffset / datasize
2018-11-14 16:33:02 +00:00
// Access to nested objects can be performed by joining the names using `` . `` .
// The current object and sub-objects and data items inside the current object
// are in scope without nested access.
object "Contract1" {
2017-04-21 16:35:56 +00:00
code {
2019-05-10 04:11:23 +00:00
function allocate(size) -> ptr {
ptr := mload(0x40)
if iszero(ptr) { ptr := 0x60 }
mstore(0x40, add(ptr, size))
}
2018-11-14 16:33:02 +00:00
// first create "runtime.Contract2"
2019-05-10 04:11:23 +00:00
let size := datasize("runtime.Contract2")
let offset := allocate(size)
2017-04-21 16:35:56 +00:00
// This will turn into a memory->memory copy for eWASM and
// a codecopy for EVM
2018-11-14 16:33:02 +00:00
datacopy(offset, dataoffset("runtime.Contract2"), size)
// constructor parameter is a single number 0x1234
mstore(add(offset, size), 0x1234)
2019-05-10 04:11:23 +00:00
pop(create(offset, add(size, 32), 0))
2018-11-14 16:33:02 +00:00
// now return the runtime object (this is
// constructor code)
size := datasize("runtime")
offset := allocate(size)
// This will turn into a memory->memory copy for eWASM and
// a codecopy for EVM
datacopy(offset, dataoffset("runtime"), size)
2017-04-21 16:35:56 +00:00
return(offset, size)
}
data "Table2" hex"4123"
object "runtime" {
code {
2019-05-10 04:11:23 +00:00
function allocate(size) -> ptr {
ptr := mload(0x40)
if iszero(ptr) { ptr := 0x60 }
mstore(0x40, add(ptr, size))
}
2017-04-21 16:35:56 +00:00
// runtime code
2019-05-10 04:11:23 +00:00
let size := datasize("Contract2")
let offset := allocate(size)
2017-04-21 16:35:56 +00:00
// This will turn into a memory->memory copy for eWASM and
// a codecopy for EVM
2018-11-14 16:33:02 +00:00
datacopy(offset, dataoffset("Contract2"), size)
2017-04-21 16:35:56 +00:00
// constructor parameter is a single number 0x1234
mstore(add(offset, size), 0x1234)
2019-05-10 04:11:23 +00:00
pop(create(offset, add(size, 32), 0))
2017-04-21 16:35:56 +00:00
}
// Embedded object. Use case is that the outside is a factory contract,
// and Contract2 is the code to be created by the factory
object "Contract2" {
code {
// code here ...
}
object "runtime" {
code {
// code here ...
}
2019-05-10 04:11:23 +00:00
}
2017-04-21 16:35:56 +00:00
2019-05-10 04:11:23 +00:00
data "Table1" hex"4123"
2017-04-21 16:35:56 +00:00
}
}
}