diff --git a/content/00.zksync-era/40.tooling/20.hardhat/30.plugins/40.hardhat-zksync-solc.md b/content/00.zksync-era/40.tooling/20.hardhat/30.plugins/40.hardhat-zksync-solc.md index 23c367d4..77f97478 100644 --- a/content/00.zksync-era/40.tooling/20.hardhat/30.plugins/40.hardhat-zksync-solc.md +++ b/content/00.zksync-era/40.tooling/20.hardhat/30.plugins/40.hardhat-zksync-solc.md @@ -144,7 +144,7 @@ For Solidity versions older than 0.8, only this compilation mode is available an `fallback_to_optimizing_for_size` option is supported for zksolc compiler version 1.3.21 or higher. :: -### Compiler informations +### Compiler integrations The zksolc compilers are stored in the cache folder with the path `{cache}/hardhat-nodejs/compilers-v2/zksolc`. In this location, you can inspect the locally stored compiler versions. @@ -157,7 +157,7 @@ This approach is implemented to provide a caching mechanism, avoiding the risk o ### ZKsync Era Solidity compiler -Due to [several codegen limitations](/zksync-protocol/compiler/specification/evmla-translator) +Due to [several codegen limitations](https://matter-labs.github.io/era-compiler-solidity/latest/eravm/02-evm-assembly-translator.html) of the [upstream Solidity compiler](https://github.com/ethereum/solidity), our team had to [fork it](%%zk_git_repo_era-solidity%%) in order to effectively address and resolve these constraints. @@ -165,8 +165,7 @@ For usage of EraVM compiler, `eraVersion` should be added inside `solidity` prop ```typescript solidity: { - version: "0.8.17", - eraVersion: "1.0.0" //optional. Compile contracts with EraVM compiler + version: "0.8.28" }, ``` @@ -232,7 +231,7 @@ To understand what the factory dependencies are, read more about them #### Error in plugin @matterlabs/hardhat-zksync-solc: Invalid zksolc compiler version This error is returned when the version defined in the `hardhat.config.ts` file is lower -than the minimal required (versions are defined in file [compilerVersion.json](#compiler-informations)). +than the minimal required (versions are defined in file [compilerVersion.json](#compiler-integrations)). Update the version to solve the issue. #### Why is there an `unexpected end of JSON input` compilation error? diff --git a/content/20.zksync-protocol/50.compiler/20.specification/10.index.md b/content/20.zksync-protocol/50.compiler/20.specification/10.index.md deleted file mode 100644 index 25b1687c..00000000 --- a/content/20.zksync-protocol/50.compiler/20.specification/10.index.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -title: Overview -description: ---- - -This is a technical deep-dive into the specifics of how the compiler works. -If you're looking to just deploy a contract, -please visit [Toolchain](/zksync-protocol/compiler/toolchain) to understand the specifics around our Solidity, Vyper and LLVM compilers. - -## Glossary - -| Entity | Description | -| ------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| zksolc | The Solidity compiler, developed by Matter Labs. | -| solc | The original Solidity compiler, developed by the Ethereum community. Called by zksolc as a subprocess to get the IRs of the source code of the project. | -| LLVM | The compiler framework, used for optimizations and assembly generation. | -| EraVM assembler/linker | The tool written in Rust. Translates the assembly emitted by LLVM to the target bytecode. | -| Virtual machine | The ZKsync Era virtual machine called EraVM with a custom instruction set. | -| [EraVM specification](%%zk_git_repo_eravm-spec%%/spec.html) | A combination of a human readable documentation and a formal description of EraVM, including its structure and operation, instruction syntax, semantic, and encoding. | -| Intermediate representation (IR) | The data structure or code used internally by the compiler to represent source code. | -| Yul | One of the Solidity IRs. Is a superset of the assembly available in Solidity. Used by default for contracts written in Solidity ≥0.8. | -| EVMLA | One of the Solidity IRs called EVM legacy assembly. Is a predecessor of Yul, but must closer to the pure EVM bytecode. Used by default for contracts written in Solidity <0.8. | -| LLVM IR | The IR native to the LLVM framework. | -| EraVM assembly | The text representation of the EraVM bytecode. Emitted by the LLVM framework. Translated into the EraVM bytecode by the EraVM assembler/linker. | -| EraVM bytecode | The smart contract bytecode, executed by EraVM. | -| Stack | The segment of the non-persistent contract memory. Consists of two parts: global data and function stack frame. | -| Heap | The segment of the non-persistent contract memory. All the data is globally accessible by both the compiler and user code. The allocation is handled by the solc’s Yul/EVMLA allocator only. | -| Auxiliary heap | The segment of the non-persistent contract memory, introduced to avoid conflicts with the solc’s allocator. All the data is globally accessible by the compiler only. The allocation is handled by the zksolc’s compiler only. All contract calls specific to ZKsync, including the system contracts, are made via the auxiliary heap. It is also used to return data (e.g. the array of immutables) from the constructor. | -| Calldata | The segment of the non-persistent contract memory. The heap or auxiliary heap of the parent/caller contract. | -| Return data | The segment of the non-persistent contract memory. The heap or auxiliary heap of the child/callee contract. | -| Contract storage | The persistent contract memory. No relevant differences from that of EVM. | -| System contracts | The special set of ZKsync kernel contracts written in Solidity by Matter Labs. | -| Contract context | The special storage of VM that keeps data like the current address, the caller’s address, etc. | - -## Concepts - -- [Code Separation](/zksync-protocol/compiler/specification/code-separation) -- [System Contracts](/zksync-protocol/compiler/specification/system-contracts) -- [Exception Handling](/zksync-protocol/compiler/specification/exception-handling) -- [EVMLA translator](/zksync-protocol/compiler/specification/evmla-translator) -- [Binary layout, linking and loading](/zksync-protocol/compiler/specification/binary-layout) diff --git a/content/20.zksync-protocol/50.compiler/20.specification/20.code-separation.md b/content/20.zksync-protocol/50.compiler/20.specification/20.code-separation.md deleted file mode 100644 index 9fb44b2b..00000000 --- a/content/20.zksync-protocol/50.compiler/20.specification/20.code-separation.md +++ /dev/null @@ -1,79 +0,0 @@ ---- -title: Code separation -description: ---- - -On both EVM and EraVM the code is separated into two parts: deploy code and runtime code. The deploy code is executed -only once, when the contract is deployed. The runtime code is executed every time the contract is called. However, on -EraVM the deploy code and runtime code are deployed together, and they are not split into two separate chunks of -bytecode. - -The constructor is added to the contract as a regular public function which is called by System Contracts during -deployment. - -Just like on EVM, the deploy code on EraVM is represented by a single constructor, named differently in different -languages: - -| Language | Name | -| -------- | ----------------- | -| Solidity | `constructor` | -| Yul | `object ""` | -| Vyper | `__init__` | - -The constructor is merged with the runtime code by the LLVM IR generator of our compiler, and a minimal contract on -EraVM looks like on the examples below. - -### LLVM IR - -In the example below, contract `@__entry` arguments `%0`-`%11` correspond to registers `r1`-`r12` on EraVM. - -```txt -; Function Attrs: nofree noreturn null_pointer_is_valid -define i256 @__entry(ptr addrspace(3) nocapture readnone %0, i256 %1, i256 %2, i256 %3, i256 %4, i256 %5, i256 %6, i256 %7, i256 %8, i256 %9, i256 %10, i256 %11) local_unnamed_addr #1 personality ptr @__personality { -entry: - %is_deploy_code_call_flag_truncated = and i256 %1, 1 ; check if the call is a deploy code call - %is_deploy_code_call_flag.not = icmp eq i256 %is_deploy_code_call_flag_truncated, 0 ; invert the flag - br i1 %is_deploy_code_call_flag.not, label %runtime_code_call_block, label %deploy_code_call_block ; branch to the deploy code block if the flag is set - -deploy_code_call_block: ; preds = %entry - store i256 32, ptr addrspace(2) inttoptr (i256 256 to ptr addrspace(2)), align 256 ; store the offset of the array of immutables - store i256 0, ptr addrspace(2) inttoptr (i256 288 to ptr addrspace(2)), align 32 ; store the length of the array of immutables - tail call void @llvm.syncvm.return(i256 53919893334301279589334030174039261352344891250716429051063678533632) ; return the array of immutables using EraVM return ABI data encoding - unreachable - -runtime_code_call_block: ; preds = %entry - store i256 42, ptr addrspace(1) null, align 4294967296 ; store a value to return - tail call void @llvm.syncvm.return(i256 2535301200456458802993406410752) ; return the value using EraVM return ABI data encoding - unreachable -} -``` - -### EraVM Assembly - -```asm - .text - .file "default.yul" - .globl __entry -__entry: -.func_begin0: - and! 1, r2, r1 ; check if the call is a deploy code call - jump.ne @.BB0_1 ; branch to the deploy code block if the flag is set - add 42, r0, r1 ; move the value to return into r1 - st.1 0, r1 ; store the value to return - add @CPI0_1[0], r0, r1 ; move the return ABI data into r1 - ret.ok.to_label r1, @DEFAULT_FAR_RETURN ; return the value -.BB0_1: - add 32, r0, r1 ; move the offset of the array of immutables into r1 - st.2 256, r1 ; store the offset of the array of immutables - st.2 288, r0 ; store the length of the array of immutables - add @CPI0_0[0], r0, r1 ; move the return ABI data into r1 - ret.ok.to_label r1, @DEFAULT_FAR_RETURN ; return the array of immutables -.func_end0: - - .note.GNU-stack - .rodata -CPI0_0: - .cell 53919893334301279589334030174039261352344891250716429051063678533632 -CPI0_1: - .cell 2535301200456458802993406410752 -``` diff --git a/content/20.zksync-protocol/50.compiler/20.specification/30.system-contracts.md b/content/20.zksync-protocol/50.compiler/20.specification/30.system-contracts.md deleted file mode 100644 index 998d2b62..00000000 --- a/content/20.zksync-protocol/50.compiler/20.specification/30.system-contracts.md +++ /dev/null @@ -1,140 +0,0 @@ ---- -title: System contracts -description: ---- - -Many EVM instructions require special handling by the System Contracts. Among them are: `ORIGIN`, -`CALLVALUE`, `BALANCE`, `CREATE`, `SHA3`, and others. To see the full detailed list of instructions that require special -handling, see -[the EVM instructions reference](/zksync-protocol/compiler/specification/instructions/evm). - -There are several types of System Contracts from the perspective of how they are handled by the ZKsync Era compilers: - -1. [Environmental data storage](#environmental-data-storage). -2. [KECCAK256 hash function](#keccak256-hash-function). -3. [Contract deployer](#contract-deployer). -4. [Ether value simulator](#ether-value-simulator). -5. [Simulator of immutables](#simulator-of-immutables). -6. [Event handler](#event-handler). - -### Environmental Data Storage - -Such storage contracts are accessed with static calls in order to retrieve values for the block, transaction, and other -environmental entities: `CHAINID`, `DIFFICULTY`, `BLOCKHASH`, etc. - -One good example of such contract is -[SystemContext](%%zk_git_repo_era-contracts%%/blob/main/system-contracts/contracts/SystemContext.sol) that provides -the majority of the environmental data. - -Since EVM is not using external calls for these instructions, we must use [the auxiliary heap](#auxiliary-heap) for -their calldata. - -Steps to handle such instructions: - -1. Store the calldata for the System Contract call on the auxiliary heap. -2. Call the System Contract with a static call. -3. Check the return status code of the call. -4. [Revert or throw](/zksync-protocol/compiler/specification/exception-handling) - if the status code is zero. -5. Read the ABI data and extract the result. All such System Contracts return a single 256-bit value. -6. Return the value as the result of the original instruction. - -For reference, see -[the LLVM IR codegen source code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/context/function/llvm_runtime.rs#L488). - -### KECCAK256 Hash Function - -Handling of this function is similar to [Environmental Data Storage](#environmental-data-storage) with one difference: - -Since EVM also uses heap to store the calldata for `KECCAK256`, the required memory chunk is allocated by the IR -generator, and ZKsync Era compiler does not need to use [the auxiliary heap](#auxiliary-heap). - -For reference, see -[the LLVM IR codegen source code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/context/function/llvm_runtime.rs). - -### Contract Deployer - -See [handling CREATE](/zksync-protocol/differences/evm-instructions#create-create2) -and -[dependency code substitution instructions](/zksync-protocol/differences/evm-instructions#datasize-dataoffset-datacopy) -on ZKsync Era documentation. - -For reference, see LLVM IR codegen for -[the deployer call](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/context/function/runtime/deployer_call.rs) -and -[CREATE-related instructions](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/evm/create.rs). - -### Ether Value Simulator - -EraVM does not support passing Ether natively, so this is handled by a special System Contract called -[MsgValueSimulator](%%zk_git_repo_era-contracts%%/blob/main/system-contracts/contracts/MsgValueSimulator.sol). - -An external call is redirected through the simulator if the following conditions are met: - -1. The [call](/zksync-protocol/compiler/specification/instructions/evm/call) has the Ether value parameter. -2. The Ether value is non-zero. - -Calls to the simulator require extra data passed via ABI using registers: - -1. Ether value. -2. The address of the contract to call. -3. The [system call bit](%%zk_git_repo_matter-labs-github-io%%/eravm-spec/spec.html#to_system), -which is only set if a call to the [ContractDeployer](#contract-deployer) is being redirected, that is `CREATE` or `CREATE2` is called with non-zero Ether. - -Passing Ether value in EraVM is implemented by using a combination of: - -- a special 128-bit register [`context_u128`](%%zk_git_repo_matter-labs-github-io%%/eravm-spec/spec.html#gs_context_u128) -which is a part of the EraVM [transient state](%%zk_git_repo_matter-labs-github-io%%/eravm-spec/spec.html#StateDefinitions); -- an [immutable value of `context_u128`](%%zk_git_repo_matter-labs-github-io%%/eravm-spec/spec.html#ecf_context_u128_value) -captured in the stack frame in a moment of a call. - -The process of setting up a value and capturing it is described in details in the section [Context Register of the EraVM specification](%%zk_git_repo_matter-labs-github-io%%/eravm-spec/spec.html#StateDefinitions). - -For reference, see [the LLVM IR codegen source code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/evm/call.rs#L530). - -### Simulator of Immutables - -See [handling immutables](/zksync-protocol/differences/evm-instructions#setimmutable-loadimmutable) -on ZKsync Era documentation. - -For reference, see LLVM IR codegen for -[instructions for immutables](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/evm/immutable.rs) -and -[RETURN from the deploy code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/evm/return.rs#L28). - -### Event Handler - -Event payloads are sent to a special System Contract called -[EventWriter](%%zk_git_repo_era-contracts%%/blob/main/system-contracts/contracts/EventWriter.yul). -Like on EVM, the payload consists of topics and data: - -1. The topics with a length-prefix are passed via ABI using registers. -2. The data is passed via the default heap, like on EVM. - -For reference, see -[the LLVM IR codegen source code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/evm/event.rs). - -## Auxiliary Heap - -Both [zksolc](https://matter-labs.github.io/era-compiler-solidity/latest/) and [zkvyper](https://matter-labs.github.io/era-compiler-vyper/latest/) -compilers for EraVM operate on [the IR level](/zksync-protocol/compiler/toolchain#ir-compilers), -so they cannot control the heap memory allocator which remains a responsibility of -[the high-level source code compilers](/zksync-protocol/compiler/toolchain#high-level-source-code-compilers) emitting the IRs. - -However, there are several cases where EraVM needs to allocate memory on the heap and EVM does not. The auxiliary heap is -used for these cases: - -[Returning immutables](/zksync-protocol/differences/evm-instructions#setimmutable-loadimmutable) - -1. Returning immutables from the constructor. -2. Allocating calldata and return data for calling the System Contracts. - -While the ordinary heap contains calldata and return data for calls to **user contracts**, auxiliary heap contains calldata -and return data for calls to **System Contracts**. This ensures better compatibility with EVM as users should be able to call -EraVM-specific System Contracts in a transparent way, without System Contracts affecting calldata or return data. -This prevents situations where calling System Contracts interferes with the heap layout expected by the contract developer. - -For more details on the heaps, refer to the EraVM specification, -which describes [types of heaps](%%zk_git_repo_matter-labs-github-io%%/eravm-spec/spec.html#data_page_params), -their connections to the [stack frames and memory growth](%%zk_git_repo_matter-labs-github-io%%/eravm-spec/spec.html#ctx_heap_page_id), -and their role in [communication between contracts](%%zk_git_repo_matter-labs-github-io%%/eravm-spec/spec.html#MemoryForwarding). diff --git a/content/20.zksync-protocol/50.compiler/20.specification/40.exception-handling.md b/content/20.zksync-protocol/50.compiler/20.specification/40.exception-handling.md deleted file mode 100644 index 75d3671e..00000000 --- a/content/20.zksync-protocol/50.compiler/20.specification/40.exception-handling.md +++ /dev/null @@ -1,132 +0,0 @@ ---- -title: Exception handling -description: ---- - -This document explains some peculiarities of the exception handling (EH) in zkEVM architecture. - -In a nutshell, there are two EH mechanisms in zkEVM: contract-level and function-level. -The former was inherited from the EVM architecture, and the latter is more common to general-purpose languages. - -| | Contract Level | Function Level | -| ------------ | --------------- | ----------------------------------------------------------------------------------------------------- | -| Yul Example | revert(0, 0) | verbatim("throw") | -| Native to | EVM | General-purpose languages | -| Handled by | zkEVM | Compiler | -| Catchable by | Caller contract | Caller function | -| Efficient | Yes | Huge size impact due to numerous catch blocks. Extra cycles are needed for propagating the exception. | - -## Contract Level - -This type of exceptions is inherited from the EVM architecture. On EVM, such instructions as `REVERT` and `INVALID`, -immediately terminate the contract execution and return the control to the callee. It is impossible to catch them -within the contract, and it can be only done on the callee side with checking the call status code. - -```solidity -// callee -revert(0, 0) - -// caller -let success = call(...) -if iszero(success) { - // option 1: rethrow on the contract level - returndatacopy(...) - revert(...) - - // option 2: rethrow on the function level - verbatim("throw") // only available in the Yul mode and upcoming zkEVM solc -} -``` - -zkEVM behaves exactly the same. The VM automatically unwinds the call stack up to the uppermost function frame -of the contract, leaving no possibility to catch and handle it on the way. - -These types of exceptions are more efficient, as you can revert at any point of the execution without propagating -the control flow all the way up to the uppermost function frame. - -### Implementation - -In EraVM, contracts call each other using [`far_call` instruction](%%zk_git_repo_eravm-spec%%/spec.html#FarCalls). -It [accepts the address of the exception handler](%%zk_git_repo_eravm-spec%%/spec.html#OpFarCall) as one of its arguments. - -## Function Level - -This type of exceptions is more common to general-purpose languages like C++. That is why it was easy to support -within the LLVM framework, even though it is not supported by the smart contract languages we work with. -That is also one of the reasons why the two EH mechanisms are handled separately and barely interact in the high-level code. - -In general-purpose languages a set of EH tools is usually available, e.g. `try` , `throw`, and `catch` keywords that -define which piece of code may throw and how the exception must be handled. However, these tools are not available -in Solidity and its EVM Yul dialect, so some extensions have been added in the zkEVM Yul dialect compiled by zksolc, -but there are limitations, some of which are dictated by the nature of smart contracts: - -1. Every function beginning with `ZKSYNC_NEAR_CALL` is implicitly wrapped with `try`. If there is an exception handler defined, the following will happen: - - A panic will be caught by the caller of such function. - - The control will be transferred to EH function. - There can be only one EH function and it must be named `ZKSYNC_CATCH_NEAR_CALL`. - It is not very efficient, because all functions must have an LLVM IR `catch` block that will catch and propagate the exception and call the EH function. - - When the EH function has finished executing, the caller of `ZKSYNC_NEAR_CALL` receives the control back. -2. Every operation is `throw`. -Since any instruction can panic due to out-of-gas, all of them can throw. -It is another thing reducing the potential for optimizations. -3. The `catch` block is represented by the `ZKSYNC_CATCH_NEAR_CALL` function in Yul. -A panic in `ZKSYNC_NEAR_CALL` will make **their caller** catch the exception and call the EH function. -After the EH function is executed, the control is returned to the caller of `ZKSYNC_NEAR_CALL`. - -```solidity -// Follow the numbers for the order of execution. The call order is: -// caller -> ZKSYNC_NEAR_CALL_callee -> callee_even_deeper -> ZKSYNC_CATCH_NEAR_CALL -> caller - -function ZKSYNC_NEAR_CALL_callee() -> value { // 03 - value := callee_even_deeper() // 04 -} - -function callee_even_deeper() -> value { // 05 - verbatim("throw") // 06 -} - -// In every function an implicit 'catch' block in LLVM IR is created. -// This block will do the following: -// 1. Keep the return value ('zero') zero-initialized if one is expected -// 2. Call the EH function ('ZKSYNC_CATCH_NEAR_CALL') -// 3. Return the control flow to the next instruction ('value := 42') -function caller() -> value { // 01 - let zero := ZKSYNC_NEAR_CALL_callee() // 02 - value := 42 // 09 -} - -// This handler could also be doing a revert. -// Reverts in EH functions work in the same way as without EH at all. -// They immediately terminate the execution and the control is given to the contract callee. -function ZKSYNC_CATCH_NEAR_CALL() { // 07 - log0(...) // 08 -} -``` - -Having all the overhead above, the `catch` blocks are only generated if there is the EH function `ZKSYNC_CATCH_NEAR_CALL` -defined in the contract. Otherwise there is no need to catch panics and they will be propagated to the callee contract -automatically by the VM execution environment. - -### Implementation - -In EraVM, there are two ways of implementing contract-local function calls: - -1. Saving the return address and using a [`jump`](%%zk_git_repo_eravm-spec%%/spec.html#JumpDefinition) instruction to call; -using [`jump`](%%zk_git_repo_eravm-spec%%/spec.html#JumpDefinition) instruction with saved return address to return. -2. Using - [`call`](%%zk_git_repo_eravm-spec%%/spec.html#NearCallDefinition) - instruction to call; using one of `ret` instructions with modifiers - [`ok`](%%zk_git_repo_eravm-spec%%/spec.html#NearRetDefinition), - [`revert`](%%zk_git_repo_eravm-spec%%/spec.html#NearRevertDefinition), or - [`panic`](%%zk_git_repo_eravm-spec%%/spec.html#step_oppanic) to return. - -Using `jump` is more lightweight and cheaper, but using `call`/`ret` is more feature-rich: - -1. In case of panic or revert, the storage effects and queues of this function are rolled back. -2. It is possible to pass a portion of available gas; the unused gas will be returned to the caller, unless the function panicked. -3. It is possible to set up a custom exception handler. - -Prefixing Yul function name with `ZKSYNC_NEAR_CALL_` allows to use this -additional, platform-specific functionality, implemented by the `call` -instruction. For other functions, the choice between `call`/`ret` or `jump` is -up to the compiler. diff --git a/content/20.zksync-protocol/50.compiler/20.specification/50.evmla-translator.md b/content/20.zksync-protocol/50.compiler/20.specification/50.evmla-translator.md deleted file mode 100644 index cb997381..00000000 --- a/content/20.zksync-protocol/50.compiler/20.specification/50.evmla-translator.md +++ /dev/null @@ -1,765 +0,0 @@ ---- -title: EVM Legacy Assembly translator -description: ---- - -There are two Solidity IRs used in our pipeline: Yul and EVM legacy assembly. The latter is used for older versions of -Solidity, more precisely <=0.7. - -EVM legacy assembly is very challenging to translate to LLVM IR, since it obfuscates the control flow of the program and -uses a lot of dynamic jumps. Most of the jumps can be translated to static ones by using a form of static analysis, -but some of them are impossible to resolve this way. - -## ZKsync Fork of the Solidity Compiler - -There were several issues with the existing codegen of the original *solc* compiler: - -1. Internal function pointers are written to memory or storage, and then loaded and called dynamically. -2. With local recursion, there is another stack frame allocated on every iteration. -3. Some try-catch patterns leave values on the stack, hindering stack analysis. - -All the issues have been resolved in [our fork of the Solidity compiler](https://github.com/matter-labs/era-solidity), -where we have changed the codegen to remove the dynamic jumps and add the necessary metadata. - -## Source Code - -In this section you can see a minimal example of a Solidity contract and its EVM legacy assembly translated to LLVM IR which is -eventually compiled to EraVM bytecode. - -```solidity -contract Example { - function main() public pure returns (uint256 result) { - result = 42; - } -} -``` - -## EVM Legacy Assembly - -Produced by the upstream Solidity compiler v0.7.6. - -```txt -| Line | Instruction | Value/Tag | -| ---- | ------------ | --------- | -| 000 | PUSH | 80 | -| 001 | PUSH | 40 | -| 002 | MSTORE | | -| 003 | CALLVALUE | | -| 004 | DUP1 | | -| 005 | ISZERO | | -| 006 | PUSH | [tag] 1 | -| 007 | JUMPI | | -| 008 | PUSH | 0 | -| 009 | DUP1 | | -| 010 | REVERT | | -| 011 | Tag 1 | | -| 012 | JUMPDEST | | -| 013 | POP | | -| 014 | PUSH | 4 | -| 015 | CALLDATASIZE | | -| 016 | LT | | -| 017 | PUSH | [tag] 2 | -| 018 | JUMPI | | -| 019 | PUSH | 0 | -| 020 | CALLDATALOAD | | -| 021 | PUSH | E0 | -| 022 | SHR | | -| 023 | DUP1 | | -| 024 | PUSH | 5A8AC02D | -| 025 | EQ | | -| 026 | PUSH | [tag] 3 | -| 027 | JUMPI | | -| 028 | Tag 2 | | -| 029 | JUMPDEST | | -| 030 | PUSH | 0 | -| 031 | DUP1 | | -| 032 | REVERT | | -| 033 | Tag 3 | | -| 034 | JUMPDEST | | -| 035 | PUSH | [tag] 4 | -| 036 | PUSH | [tag] 5 | -| 037 | JUMP | [in] | -| 038 | Tag 4 | | -| 039 | JUMPDEST | | -| 040 | PUSH | 40 | -| 041 | DUP1 | | -| 042 | MLOAD | | -| 043 | SWAP2 | | -| 044 | DUP3 | | -| 045 | MSTORE | | -| 046 | MLOAD | | -| 047 | SWAP1 | | -| 048 | DUP2 | | -| 049 | SWAP1 | | -| 050 | SUB | | -| 051 | PUSH | 20 | -| 052 | ADD | | -| 053 | SWAP1 | | -| 054 | RETURN | | -| 055 | Tag 5 | | -| 056 | JUMPDEST | | -| 057 | PUSH | 2A | -| 058 | SWAP1 | | -| 059 | JUMP | [out] | -``` - -## EthIR - -EthIR (Ethereal IR) is a special IR used by our translator to represent EVM legacy assembly and prepare it for the -translation to LLVM IR. The IR solves several purposes: - -1. Tracking the stack state to extract jump destinations. -2. Duplicating blocks that are reachable with different stack states. -3. Restoring the complete control-flow graph of the contract using the abovementioned data. -4. Resolving dependencies and static data chunks. - -Data format: - -1. `V_` - value returned by an instruction ``. -2. `T_` - tag of a block ``. -3. `40` - hexadecimal constant. -4. `tests/solidity/simple/default.sol:Test` - contract definition. - -Stack format: `[ V_CALLVALUE ]` (current values) - `[ V_CALLVALUE ]` (popped values) + `[ V_ISZERO ]` (pushed values) - -```text -// The default entry function of the contract. -function main { -// The maximum stack size in the function. - stack_usage: 6 -block_dt_0/0: // Deploy Code Tag 0, Instance 0. -// PUSHed 0x80 onto the stack. - PUSH 80 [ ] + [ 80 ] -// PUSHed 0x40 onto the stack. - PUSH 40 [ 80 ] + [ 40 ] -// POPped 0x40 at 0x80 from the stack to store 0x80 at 0x40. - MSTORE [ ] - [ 80 | 40 ] -// PUSHed CALLVALUE onto the stack. - CALLVALUE [ ] + [ V_CALLVALUE ] - DUP1 [ V_CALLVALUE ] + [ V_CALLVALUE ] - ISZERO [ V_CALLVALUE ] - [ V_CALLVALUE ] + [ V_ISZERO ] - PUSH [tag] 1 [ V_CALLVALUE | V_ISZERO ] + [ T_1 ] -// JUMPI schedules rt_0/0 for analysis with the current stack state. - JUMPI [ V_CALLVALUE ] - [ V_ISZERO | T_1 ] - PUSH 0 [ V_CALLVALUE ] + [ 0 ] - DUP1 [ V_CALLVALUE | 0 ] + [ 0 ] - REVERT [ V_CALLVALUE ] - [ 0 | 0 ] -block_dt_1/0: (predecessors: dt_0/0) // Deploy Code Tag 1, Instance 0; the only predecessor of this block is dt_0/0. -// JUMPDESTs are ignored as we are only interested in the stack state and tag destinations. - JUMPDEST [ V_CALLVALUE ] - POP [ ] - [ V_CALLVALUE ] - PUSH #[$] tests/solidity/simple/default.sol:Test [ ] + [ tests/solidity/simple/default.sol:Test ] - DUP1 [ tests/solidity/simple/default.sol:Test ] + [ tests/solidity/simple/default.sol:Test ] - PUSH [$] tests/solidity/simple/default.sol:Test [ tests/solidity/simple/default.sol:Test | tests/solidity/simple/default.sol:Test ] + [ tests/solidity/simple/default.sol:Test ] - PUSH 0 [ tests/solidity/simple/default.sol:Test | tests/solidity/simple/default.sol:Test | tests/solidity/simple/default.sol:Test ] + [ 0 ] - CODECOPY [ tests/solidity/simple/default.sol:Test ] - [ tests/solidity/simple/default.sol:Test | tests/solidity/simple/default.sol:Test | 0 ] - PUSH 0 [ tests/solidity/simple/default.sol:Test ] + [ 0 ] - RETURN [ ] - [ tests/solidity/simple/default.sol:Test | 0 ] -// The runtime code is analyzed in the same control-flow graph as the deploy code, as it is possible to call its functions from the constructor. -block_rt_0/0: // Deploy Code Tag 0, Instance 0. - PUSH 80 [ ] + [ 80 ] - PUSH 40 [ 80 ] + [ 40 ] - MSTORE [ ] - [ 80 | 40 ] - CALLVALUE [ ] + [ V_CALLVALUE ] - DUP1 [ V_CALLVALUE ] + [ V_CALLVALUE ] - ISZERO [ V_CALLVALUE ] - [ V_CALLVALUE ] + [ V_ISZERO ] - PUSH [tag] 1 [ V_CALLVALUE | V_ISZERO ] + [ T_1 ] - JUMPI [ V_CALLVALUE ] - [ V_ISZERO | T_1 ] - PUSH 0 [ V_CALLVALUE ] + [ 0 ] - DUP1 [ V_CALLVALUE | 0 ] + [ 0 ] - REVERT [ V_CALLVALUE ] - [ 0 | 0 ] -block_rt_1/0: (predecessors: rt_0/0) // Runtime Code Tag 1, Instance 0; the only predecessor of this block is rt_0/0. - JUMPDEST [ V_CALLVALUE ] - POP [ ] - [ V_CALLVALUE ] - PUSH 4 [ ] + [ 4 ] - CALLDATASIZE [ 4 ] + [ V_CALLDATASIZE ] - LT [ ] - [ 4 | V_CALLDATASIZE ] + [ V_LT ] - PUSH [tag] 2 [ V_LT ] + [ T_2 ] - JUMPI [ ] - [ V_LT | T_2 ] - PUSH 0 [ ] + [ 0 ] - CALLDATALOAD [ ] - [ 0 ] + [ V_CALLDATALOAD ] - PUSH E0 [ V_CALLDATALOAD ] + [ E0 ] - SHR [ ] - [ V_CALLDATALOAD | E0 ] + [ V_SHR ] - DUP1 [ V_SHR ] + [ V_SHR ] - PUSH 5A8AC02D [ V_SHR | V_SHR ] + [ 5A8AC02D ] - EQ [ V_SHR ] - [ V_SHR | 5A8AC02D ] + [ V_EQ ] - PUSH [tag] 3 [ V_SHR | V_EQ ] + [ T_3 ] - JUMPI [ V_SHR ] - [ V_EQ | T_3 ] - Tag 2 [ V_SHR ] -// This instance is called with a different stack state using the JUMPI above. -block_rt_2/0: (predecessors: rt_1/0) // Runtime Code Tag 2, Instance 0. - JUMPDEST [ ] - PUSH 0 [ ] + [ 0 ] - DUP1 [ 0 ] + [ 0 ] - REVERT [ ] - [ 0 | 0 ] -// This instance is also called from rt_1/0, but using a fallthrough 'Tag 2'. -// Given different stack states, we create a new instance of the block operating on different data -// and potentially different tag destinations, although usually such blocks are merged back by LLVM. -block_rt_2/1: (predecessors: rt_1/0) // Runtime Code Tag 2, Instance 1. - JUMPDEST [ V_SHR ] - PUSH 0 [ V_SHR ] + [ 0 ] - DUP1 [ V_SHR | 0 ] + [ 0 ] - REVERT [ V_SHR ] - [ 0 | 0 ] -block_rt_3/0: (predecessors: rt_1/0) // Runtime Code Tag 3, Instance 0. - JUMPDEST [ V_SHR ] - PUSH [tag] 4 [ V_SHR ] + [ T_4 ] - PUSH [tag] 5 [ V_SHR | T_4 ] + [ T_5 ] - JUMP [in] [ V_SHR | T_4 ] - [ T_5 ] -block_rt_4/0: (predecessors: rt_5/0) // Runtime Code Tag 4, Instance 0. - JUMPDEST [ V_SHR | 2A ] - PUSH 40 [ V_SHR | 2A ] + [ 40 ] - DUP1 [ V_SHR | 2A | 40 ] + [ 40 ] - MLOAD [ V_SHR | 2A | 40 ] - [ 40 ] + [ V_MLOAD ] - SWAP2 [ V_SHR | V_MLOAD | 40 | 2A ] - DUP3 [ V_SHR | V_MLOAD | 40 | 2A ] + [ V_MLOAD ] - MSTORE [ V_SHR | V_MLOAD | 40 ] - [ 2A | V_MLOAD ] - MLOAD [ V_SHR | V_MLOAD ] - [ 40 ] + [ V_MLOAD ] - SWAP1 [ V_SHR | V_MLOAD | V_MLOAD ] - DUP2 [ V_SHR | V_MLOAD | V_MLOAD ] + [ V_MLOAD ] - SWAP1 [ V_SHR | V_MLOAD | V_MLOAD | V_MLOAD ] - SUB [ V_SHR | V_MLOAD ] - [ V_MLOAD | V_MLOAD ] + [ V_SUB ] - PUSH 20 [ V_SHR | V_MLOAD | V_SUB ] + [ 20 ] - ADD [ V_SHR | V_MLOAD ] - [ V_SUB | 20 ] + [ V_ADD ] - SWAP1 [ V_SHR | V_ADD | V_MLOAD ] - RETURN [ V_SHR ] - [ V_ADD | V_MLOAD ] -block_rt_5/0: (predecessors: rt_3/0) // Runtime Code Tag 5, Instance 0. - JUMPDEST [ V_SHR | T_4 ] - PUSH 2A [ V_SHR | T_4 ] + [ 2A ] - SWAP1 [ V_SHR | 2A | T_4 ] -// JUMP [out] is usually a return statement - JUMP [out] [ V_SHR | 2A ] - [ T_4 ] -``` - -### Unoptimized LLVM IR - -In LLVM IR, the necessary stack space is allocated at the beginning of the function. - -Every stack operation interacts with a statically known stack pointer with an offset from EthIR. - -```txt -; Function Attrs: nofree null_pointer_is_valid -define i256 @__entry(ptr addrspace(3) %0, i256 %1, i256 %2, i256 %3, i256 %4, i256 %5, i256 %6, i256 %7, i256 %8, i256 %9, i256 %10, i256 %11) #8 personality ptr @__personality { -entry: - store i256 0, ptr @memory_pointer, align 32 - store i256 0, ptr @calldatasize, align 32 - store i256 0, ptr @returndatasize, align 32 - store i256 0, ptr @call_flags, align 32 - store [10 x i256] zeroinitializer, ptr @extra_abi_data, align 32 - store ptr addrspace(3) %0, ptr @ptr_calldata, align 32 - %abi_pointer_value = ptrtoint ptr addrspace(3) %0 to i256 - %abi_pointer_value_shifted = lshr i256 %abi_pointer_value, 96 - %abi_length_value = and i256 %abi_pointer_value_shifted, 4294967295 - store i256 %abi_length_value, ptr @calldatasize, align 32 - %calldatasize = load i256, ptr @calldatasize, align 32 - %return_data_abi_initializer = getelementptr i8, ptr addrspace(3) %0, i256 %calldatasize - store ptr addrspace(3) %return_data_abi_initializer, ptr @ptr_return_data, align 32 - store ptr addrspace(3) %return_data_abi_initializer, ptr @ptr_active, align 32 - store i256 %1, ptr @call_flags, align 32 - store i256 %2, ptr @extra_abi_data, align 32 - store i256 %3, ptr getelementptr inbounds ([10 x i256], ptr @extra_abi_data, i256 0, i32 1), align 32 - store i256 %4, ptr getelementptr inbounds ([10 x i256], ptr @extra_abi_data, i256 0, i32 2), align 32 - store i256 %5, ptr getelementptr inbounds ([10 x i256], ptr @extra_abi_data, i256 0, i32 3), align 32 - store i256 %6, ptr getelementptr inbounds ([10 x i256], ptr @extra_abi_data, i256 0, i32 4), align 32 - store i256 %7, ptr getelementptr inbounds ([10 x i256], ptr @extra_abi_data, i256 0, i32 5), align 32 - store i256 %8, ptr getelementptr inbounds ([10 x i256], ptr @extra_abi_data, i256 0, i32 6), align 32 - store i256 %9, ptr getelementptr inbounds ([10 x i256], ptr @extra_abi_data, i256 0, i32 7), align 32 - store i256 %10, ptr getelementptr inbounds ([10 x i256], ptr @extra_abi_data, i256 0, i32 8), align 32 - store i256 %11, ptr getelementptr inbounds ([10 x i256], ptr @extra_abi_data, i256 0, i32 9), align 32 - %is_deploy_code_call_flag_truncated = and i256 %1, 1 - %is_deploy_code_call_flag = icmp eq i256 %is_deploy_code_call_flag_truncated, 1 - br i1 %is_deploy_code_call_flag, label %deploy_code_call_block, label %runtime_code_call_block - -return: ; preds = %runtime_code_call_block, %deploy_code_call_block - ret i256 0 - -deploy_code_call_block: ; preds = %entry - call void @__deploy() - br label %return - -runtime_code_call_block: ; preds = %entry - call void @__runtime() - br label %return -} - -; Function Attrs: nofree null_pointer_is_valid -define private void @__deploy() #8 personality ptr @__personality { -entry: - call void @main(i1 true) - br label %return - -return: ; preds = %entry - ret void -} - -; Function Attrs: nofree null_pointer_is_valid -define private void @__runtime() #8 personality ptr @__personality { -entry: - call void @main(i1 false) - br label %return - -return: ; preds = %entry - ret void -} - -; Function Attrs: nofree null_pointer_is_valid -define private void @main(i1 %0) #8 personality ptr @__personality { ; 6 cells are allocated at the beginning of the function. -entry: - %stack_var_000 = alloca i256, align 32 - store i256 0, ptr %stack_var_000, align 32 - %stack_var_001 = alloca i256, align 32 - store i256 0, ptr %stack_var_001, align 32 - %stack_var_002 = alloca i256, align 32 - store i256 0, ptr %stack_var_002, align 32 - %stack_var_003 = alloca i256, align 32 - store i256 0, ptr %stack_var_003, align 32 - %stack_var_004 = alloca i256, align 32 - store i256 0, ptr %stack_var_004, align 32 - %stack_var_005 = alloca i256, align 32 - store i256 0, ptr %stack_var_005, align 32 - br i1 %0, label %"block_dt_0/0", label %"block_rt_0/0" - -return: ; No predecessors! - ret void - -"block_dt_0/0": ; preds = %entry - store i256 128, ptr %stack_var_000, align 32 - store i256 64, ptr %stack_var_001, align 32 - %argument_0 = load i256, ptr %stack_var_001, align 32 - %argument_1 = load i256, ptr %stack_var_000, align 32 - %memory_store_pointer = inttoptr i256 %argument_0 to ptr addrspace(1) - store i256 %argument_1, ptr addrspace(1) %memory_store_pointer, align 1 - %get_u128_value = call i256 @llvm.syncvm.getu128() - store i256 %get_u128_value, ptr %stack_var_000, align 32 - %dup1 = load i256, ptr %stack_var_000, align 32 - store i256 %dup1, ptr %stack_var_001, align 32 - %argument_01 = load i256, ptr %stack_var_001, align 32 - %comparison_result = icmp eq i256 %argument_01, 0 - %comparison_result_extended = zext i1 %comparison_result to i256 - store i256 %comparison_result_extended, ptr %stack_var_001, align 32 - store i256 1, ptr %stack_var_002, align 32 - %conditional_dt_1_condition = load i256, ptr %stack_var_001, align 32 - %conditional_dt_1_condition_compared = icmp ne i256 %conditional_dt_1_condition, 0 - br i1 %conditional_dt_1_condition_compared, label %"block_dt_1/0", label %conditional_dt_1_join_block - -"block_dt_1/0": ; preds = %"block_dt_0/0" - store i256 0, ptr %stack_var_000, align 32 - %dup15 = load i256, ptr %stack_var_000, align 32 - store i256 %dup15, ptr %stack_var_001, align 32 - store i256 0, ptr %stack_var_002, align 32 - store i256 0, ptr %stack_var_003, align 32 - %argument_06 = load i256, ptr %stack_var_003, align 32 - %argument_17 = load i256, ptr %stack_var_002, align 32 - %argument_2 = load i256, ptr %stack_var_001, align 32 - %calldata_copy_destination_pointer = inttoptr i256 %argument_06 to ptr addrspace(1) - %calldata_pointer = load ptr addrspace(3), ptr @ptr_calldata, align 32 - %calldata_source_pointer = getelementptr i8, ptr addrspace(3) %calldata_pointer, i256 %argument_17 - call void @llvm.memcpy.p1.p3.i256(ptr addrspace(1) align 1 %calldata_copy_destination_pointer, ptr addrspace(3) align 1 %calldata_source_pointer, i256 %argument_2, i1 false) - store i256 0, ptr %stack_var_001, align 32 - %argument_08 = load i256, ptr %stack_var_001, align 32 - %argument_19 = load i256, ptr %stack_var_000, align 32 - store i256 32, ptr addrspace(2) inttoptr (i256 256 to ptr addrspace(2)), align 1 - store i256 0, ptr addrspace(2) inttoptr (i256 288 to ptr addrspace(2)), align 1 - call void @__return(i256 256, i256 64, i256 2) - unreachable - -"block_rt_0/0": ; preds = %entry - store i256 128, ptr %stack_var_000, align 32 - store i256 64, ptr %stack_var_001, align 32 - %argument_010 = load i256, ptr %stack_var_001, align 32 - %argument_111 = load i256, ptr %stack_var_000, align 32 - %memory_store_pointer12 = inttoptr i256 %argument_010 to ptr addrspace(1) - store i256 %argument_111, ptr addrspace(1) %memory_store_pointer12, align 1 - %get_u128_value13 = call i256 @llvm.syncvm.getu128() - store i256 %get_u128_value13, ptr %stack_var_000, align 32 - %dup114 = load i256, ptr %stack_var_000, align 32 - store i256 %dup114, ptr %stack_var_001, align 32 - %argument_015 = load i256, ptr %stack_var_001, align 32 - %comparison_result16 = icmp eq i256 %argument_015, 0 - %comparison_result_extended17 = zext i1 %comparison_result16 to i256 - store i256 %comparison_result_extended17, ptr %stack_var_001, align 32 - store i256 1, ptr %stack_var_002, align 32 - %conditional_rt_1_condition = load i256, ptr %stack_var_001, align 32 - %conditional_rt_1_condition_compared = icmp ne i256 %conditional_rt_1_condition, 0 - br i1 %conditional_rt_1_condition_compared, label %"block_rt_1/0", label %conditional_rt_1_join_block - -"block_rt_1/0": ; preds = %"block_rt_0/0" - store i256 4, ptr %stack_var_000, align 32 - %calldatasize = load i256, ptr @calldatasize, align 32 - store i256 %calldatasize, ptr %stack_var_001, align 32 - %argument_021 = load i256, ptr %stack_var_001, align 32 - %argument_122 = load i256, ptr %stack_var_000, align 32 - %comparison_result23 = icmp ult i256 %argument_021, %argument_122 - %comparison_result_extended24 = zext i1 %comparison_result23 to i256 - store i256 %comparison_result_extended24, ptr %stack_var_000, align 32 - store i256 2, ptr %stack_var_001, align 32 - %conditional_rt_2_condition = load i256, ptr %stack_var_000, align 32 - %conditional_rt_2_condition_compared = icmp ne i256 %conditional_rt_2_condition, 0 - br i1 %conditional_rt_2_condition_compared, label %"block_rt_2/0", label %conditional_rt_2_join_block - -"block_rt_2/0": ; preds = %"block_rt_1/0" - store i256 0, ptr %stack_var_000, align 32 - %dup134 = load i256, ptr %stack_var_000, align 32 - store i256 %dup134, ptr %stack_var_001, align 32 - %argument_035 = load i256, ptr %stack_var_001, align 32 - %argument_136 = load i256, ptr %stack_var_000, align 32 - call void @__revert(i256 %argument_035, i256 %argument_136, i256 0) - unreachable - -"block_rt_2/1": ; preds = %conditional_rt_3_join_block - store i256 0, ptr %stack_var_001, align 32 - %dup137 = load i256, ptr %stack_var_001, align 32 - store i256 %dup137, ptr %stack_var_002, align 32 - %argument_038 = load i256, ptr %stack_var_002, align 32 - %argument_139 = load i256, ptr %stack_var_001, align 32 - call void @__revert(i256 %argument_038, i256 %argument_139, i256 0) - unreachable - -"block_rt_3/0": ; preds = %conditional_rt_2_join_block - store i256 4, ptr %stack_var_001, align 32 - store i256 5, ptr %stack_var_002, align 32 - br label %"block_rt_5/0" - -"block_rt_4/0": ; preds = %"block_rt_5/0" - store i256 64, ptr %stack_var_002, align 32 - %dup140 = load i256, ptr %stack_var_002, align 32 - store i256 %dup140, ptr %stack_var_003, align 32 - %argument_041 = load i256, ptr %stack_var_003, align 32 - %memory_load_pointer = inttoptr i256 %argument_041 to ptr addrspace(1) - %memory_load_result = load i256, ptr addrspace(1) %memory_load_pointer, align 1 - store i256 %memory_load_result, ptr %stack_var_003, align 32 - %swap2_top_value = load i256, ptr %stack_var_003, align 32 - %swap2_swap_value = load i256, ptr %stack_var_001, align 32 - store i256 %swap2_swap_value, ptr %stack_var_003, align 32 - store i256 %swap2_top_value, ptr %stack_var_001, align 32 - %dup3 = load i256, ptr %stack_var_001, align 32 - store i256 %dup3, ptr %stack_var_004, align 32 - %argument_042 = load i256, ptr %stack_var_004, align 32 - %argument_143 = load i256, ptr %stack_var_003, align 32 - %memory_store_pointer44 = inttoptr i256 %argument_042 to ptr addrspace(1) - store i256 %argument_143, ptr addrspace(1) %memory_store_pointer44, align 1 - %argument_045 = load i256, ptr %stack_var_002, align 32 - %memory_load_pointer46 = inttoptr i256 %argument_045 to ptr addrspace(1) - %memory_load_result47 = load i256, ptr addrspace(1) %memory_load_pointer46, align 1 - store i256 %memory_load_result47, ptr %stack_var_002, align 32 - %swap1_top_value = load i256, ptr %stack_var_002, align 32 - %swap1_swap_value = load i256, ptr %stack_var_001, align 32 - store i256 %swap1_swap_value, ptr %stack_var_002, align 32 - store i256 %swap1_top_value, ptr %stack_var_001, align 32 - %dup2 = load i256, ptr %stack_var_001, align 32 - store i256 %dup2, ptr %stack_var_003, align 32 - %swap1_top_value48 = load i256, ptr %stack_var_003, align 32 - %swap1_swap_value49 = load i256, ptr %stack_var_002, align 32 - store i256 %swap1_swap_value49, ptr %stack_var_003, align 32 - store i256 %swap1_top_value48, ptr %stack_var_002, align 32 - %argument_050 = load i256, ptr %stack_var_003, align 32 - %argument_151 = load i256, ptr %stack_var_002, align 32 - %subtraction_result = sub i256 %argument_050, %argument_151 - store i256 %subtraction_result, ptr %stack_var_002, align 32 - store i256 32, ptr %stack_var_003, align 32 - %argument_052 = load i256, ptr %stack_var_003, align 32 - %argument_153 = load i256, ptr %stack_var_002, align 32 - %addition_result = add i256 %argument_052, %argument_153 - store i256 %addition_result, ptr %stack_var_002, align 32 - %swap1_top_value54 = load i256, ptr %stack_var_002, align 32 - %swap1_swap_value55 = load i256, ptr %stack_var_001, align 32 - store i256 %swap1_swap_value55, ptr %stack_var_002, align 32 - store i256 %swap1_top_value54, ptr %stack_var_001, align 32 - %argument_056 = load i256, ptr %stack_var_002, align 32 - %argument_157 = load i256, ptr %stack_var_001, align 32 - call void @__return(i256 %argument_056, i256 %argument_157, i256 0) - unreachable - -"block_rt_5/0": ; preds = %"block_rt_3/0" - store i256 42, ptr %stack_var_002, align 32 - %swap1_top_value58 = load i256, ptr %stack_var_002, align 32 - %swap1_swap_value59 = load i256, ptr %stack_var_001, align 32 - store i256 %swap1_swap_value59, ptr %stack_var_002, align 32 - store i256 %swap1_top_value58, ptr %stack_var_001, align 32 - br label %"block_rt_4/0" - -conditional_dt_1_join_block: ; preds = %"block_dt_0/0" - store i256 0, ptr %stack_var_001, align 32 - %dup12 = load i256, ptr %stack_var_001, align 32 - store i256 %dup12, ptr %stack_var_002, align 32 - %argument_03 = load i256, ptr %stack_var_002, align 32 - %argument_14 = load i256, ptr %stack_var_001, align 32 - call void @__revert(i256 %argument_03, i256 %argument_14, i256 0) - unreachable - -conditional_rt_1_join_block: ; preds = %"block_rt_0/0" - store i256 0, ptr %stack_var_001, align 32 - %dup118 = load i256, ptr %stack_var_001, align 32 - store i256 %dup118, ptr %stack_var_002, align 32 - %argument_019 = load i256, ptr %stack_var_002, align 32 - %argument_120 = load i256, ptr %stack_var_001, align 32 - call void @__revert(i256 %argument_019, i256 %argument_120, i256 0) - unreachable - -conditional_rt_2_join_block: ; preds = %"block_rt_1/0" - store i256 0, ptr %stack_var_000, align 32 - %argument_025 = load i256, ptr %stack_var_000, align 32 - %calldata_pointer26 = load ptr addrspace(3), ptr @ptr_calldata, align 32 - %calldata_pointer_with_offset = getelementptr i8, ptr addrspace(3) %calldata_pointer26, i256 %argument_025 - %calldata_value = load i256, ptr addrspace(3) %calldata_pointer_with_offset, align 32 - store i256 %calldata_value, ptr %stack_var_000, align 32 - store i256 224, ptr %stack_var_001, align 32 - %argument_027 = load i256, ptr %stack_var_001, align 32 - %argument_128 = load i256, ptr %stack_var_000, align 32 - %shr_call = call i256 @__shr(i256 %argument_027, i256 %argument_128) - store i256 %shr_call, ptr %stack_var_000, align 32 - %dup129 = load i256, ptr %stack_var_000, align 32 - store i256 %dup129, ptr %stack_var_001, align 32 - store i256 1519042605, ptr %stack_var_002, align 32 - %argument_030 = load i256, ptr %stack_var_002, align 32 - %argument_131 = load i256, ptr %stack_var_001, align 32 - %comparison_result32 = icmp eq i256 %argument_030, %argument_131 - %comparison_result_extended33 = zext i1 %comparison_result32 to i256 - store i256 %comparison_result_extended33, ptr %stack_var_001, align 32 - store i256 3, ptr %stack_var_002, align 32 - %conditional_rt_3_condition = load i256, ptr %stack_var_001, align 32 - %conditional_rt_3_condition_compared = icmp ne i256 %conditional_rt_3_condition, 0 - br i1 %conditional_rt_3_condition_compared, label %"block_rt_3/0", label %conditional_rt_3_join_block - -conditional_rt_3_join_block: ; preds = %conditional_rt_2_join_block - br label %"block_rt_2/1" -} - -attributes #0 = { nounwind } -attributes #1 = { nounwind readnone } -attributes #2 = { nounwind readonly } -attributes #3 = { writeonly } -attributes #4 = { argmemonly nocallback nofree nounwind willreturn } -attributes #5 = { noprofile } -attributes #6 = { mustprogress nofree nounwind null_pointer_is_valid readnone willreturn } -attributes #7 = { mustprogress nofree nounwind null_pointer_is_valid willreturn } -attributes #8 = { nofree null_pointer_is_valid } -``` - -### Optimized LLVM IR - -The redundancy is optimized by LLVM, resulting in the optimized LLVM IR below. - -```txt -; Function Attrs: nofree noreturn null_pointer_is_valid -define i256 @__entry(ptr addrspace(3) %0, i256 %1, i256 %2, i256 %3, i256 %4, i256 %5, i256 %6, i256 %7, i256 %8, i256 %9, i256 %10, i256 %11) local_unnamed_addr #1 personality ptr @__personality { -entry: - store ptr addrspace(3) %0, ptr @ptr_calldata, align 32 - %abi_pointer_value = ptrtoint ptr addrspace(3) %0 to i256 - %abi_pointer_value_shifted = lshr i256 %abi_pointer_value, 96 - %abi_length_value = and i256 %abi_pointer_value_shifted, 4294967295 - store i256 %abi_length_value, ptr @calldatasize, align 32 - %is_deploy_code_call_flag_truncated = and i256 %1, 1 - %is_deploy_code_call_flag.not = icmp eq i256 %is_deploy_code_call_flag_truncated, 0 - store i256 128, ptr addrspace(1) inttoptr (i256 64 to ptr addrspace(1)), align 64 - %get_u128_value.i.i1 = tail call i256 @llvm.syncvm.getu128() - br i1 %is_deploy_code_call_flag.not, label %runtime_code_call_block, label %deploy_code_call_block - -deploy_code_call_block: ; preds = %entry - %comparison_result.i.i = icmp eq i256 %get_u128_value.i.i1, 0 - br i1 %comparison_result.i.i, label %"block_dt_1/0.i.i", label %"block_rt_2/0.i.i" - -"block_dt_1/0.i.i": ; preds = %deploy_code_call_block - store i256 32, ptr addrspace(2) inttoptr (i256 256 to ptr addrspace(2)), align 256 - store i256 0, ptr addrspace(2) inttoptr (i256 288 to ptr addrspace(2)), align 32 - tail call void @llvm.syncvm.return(i256 53919893334301279589334030174039261352344891250716429051063678533632) - unreachable - -"block_rt_2/0.i.i": ; preds = %runtime_code_call_block, %conditional_rt_2_join_block.i.i, %deploy_code_call_block - tail call void @llvm.syncvm.revert(i256 0) - unreachable - -runtime_code_call_block: ; preds = %entry - %comparison_result.i.i2 = icmp ne i256 %get_u128_value.i.i1, 0 - %calldatasize.i.i = load i256, ptr @calldatasize, align 32 - %comparison_result23.i.i = icmp ult i256 %calldatasize.i.i, 4 - %or.cond.i.i = select i1 %comparison_result.i.i2, i1 true, i1 %comparison_result23.i.i - br i1 %or.cond.i.i, label %"block_rt_2/0.i.i", label %conditional_rt_2_join_block.i.i - -"block_rt_3/0.i.i": ; preds = %conditional_rt_2_join_block.i.i - %memory_load_result.i.i = load i256, ptr addrspace(1) inttoptr (i256 64 to ptr addrspace(1)), align 64 - %memory_store_pointer44.i.i = inttoptr i256 %memory_load_result.i.i to ptr addrspace(1) - store i256 42, ptr addrspace(1) %memory_store_pointer44.i.i, align 1 - %memory_load_result47.i.i = load i256, ptr addrspace(1) inttoptr (i256 64 to ptr addrspace(1)), align 64 - %subtraction_result.i.i = add i256 %memory_load_result.i.i, 32 - %addition_result.i.i = sub i256 %subtraction_result.i.i, %memory_load_result47.i.i - %12 = tail call i256 @llvm.umin.i256(i256 %memory_load_result47.i.i, i256 4294967295) - %13 = tail call i256 @llvm.umin.i256(i256 %addition_result.i.i, i256 4294967295) - %offset_shifted.i.i.i.i = shl nuw nsw i256 %12, 64 - %length_shifted.i.i.i.i = shl nuw nsw i256 %13, 96 - %tmp.i.i.i.i = or i256 %length_shifted.i.i.i.i, %offset_shifted.i.i.i.i - tail call void @llvm.syncvm.return(i256 %tmp.i.i.i.i) - unreachable - -conditional_rt_2_join_block.i.i: ; preds = %runtime_code_call_block - %calldata_pointer26.i.i = load ptr addrspace(3), ptr @ptr_calldata, align 32 - %calldata_value.i.i = load i256, ptr addrspace(3) %calldata_pointer26.i.i, align 32 - %shift_res.i.mask.i.i = and i256 %calldata_value.i.i, -26959946667150639794667015087019630673637144422540572481103610249216 - %comparison_result32.i.i = icmp eq i256 %shift_res.i.mask.i.i, 40953307615929575801107647705360601464619672688377251939886941387873771847680 - br i1 %comparison_result32.i.i, label %"block_rt_3/0.i.i", label %"block_rt_2/0.i.i" -} - -attributes #0 = { nounwind } -attributes #1 = { nofree noreturn null_pointer_is_valid } -attributes #2 = { noreturn nounwind } -attributes #3 = { nocallback nofree nosync nounwind readnone speculatable willreturn } -``` - -### EraVM Assembly - -The optimized LLVM IR is translated into EraVM assembly below, allowing the size comparable to the Yul pipeline. - -```asm - .text - .file "default.sol:Test" - .globl __entry -__entry: -.func_begin0: - ptr.add r1, r0, stack[@ptr_calldata] - shr.s 96, r1, r1 - and @CPI0_0[0], r1, stack[@calldatasize] - add 128, r0, r1 - st.1 64, r1 - context.get_context_u128 r1 - and! 1, r2, r2 - jump.ne @.BB0_1 - sub! r1, r0, r1 - jump.ne @.BB0_3 - add stack[@calldatasize], r0, r1 - sub.s! 4, r1, r1 - jump.lt @.BB0_3 - ptr.add stack[@ptr_calldata], r0, r1 - ld r1, r1 - and @CPI0_2[0], r1, r1 - sub.s! @CPI0_3[0], r1, r1 - jump.ne @.BB0_3 - ld.1 64, r1 - add 42, r0, r2 - st.1 r1, r2 - ld.1 64, r2 - sub r1, r2, r1 - add 32, r1, r1 - add @CPI0_0[0], r0, r3 - sub.s! @CPI0_0[0], r1, r4 - add.ge r3, r0, r1 - sub.s! @CPI0_0[0], r2, r4 - add.ge r3, r0, r2 - shl.s 64, r2, r2 - shl.s 96, r1, r1 - or r1, r2, r1 - ret.ok.to_label r1, @DEFAULT_FAR_RETURN -.BB0_1: - sub! r1, r0, r1 - jump.ne @.BB0_3 - add 32, r0, r1 - st.2 256, r1 - st.2 288, r0 - add @CPI0_1[0], r0, r1 - ret.ok.to_label r1, @DEFAULT_FAR_RETURN -.BB0_3: - add r0, r0, r1 - ret.revert.to_label r1, @DEFAULT_FAR_REVERT -.func_end0: - - .data - .p2align 5 -calldatasize: - .cell 0 - - .p2align 5 -ptr_calldata: -.cell 0 - - .note.GNU-stack - .rodata -CPI0_0: - .cell 4294967295 -CPI0_1: - .cell 53919893334301279589334030174039261352344891250716429051063678533632 -CPI0_2: - .cell -26959946667150639794667015087019630673637144422540572481103610249216 -CPI0_3: - .cell 40953307615929575801107647705360601464619672688377251939886941387873771847680 -``` - -For comparison, the Yul pipeline of solc v0.8.21 produces the following EraVM assembly: - -```asm - .text - .file "default.sol:Test" - .globl __entry -__entry: -.func_begin0: - ptr.add r1, r0, stack[@ptr_calldata] - shr.s 96, r1, r1 - and @CPI0_0[0], r1, stack[@calldatasize] - add 128, r0, r1 - st.1 64, r1 - and! 1, r2, r1 - jump.ne @.BB0_1 - add stack[@calldatasize], r0, r1 - sub.s! 4, r1, r1 - jump.lt @.BB0_2 - ptr.add stack[@ptr_calldata], r0, r1 - ld r1, r1 - and @CPI0_2[0], r1, r1 - sub.s! @CPI0_3[0], r1, r1 - jump.ne @.BB0_2 - context.get_context_u128 r1 - sub! r1, r0, r1 - jump.ne @.BB0_2 - sub.s 4, r0, r1 - add stack[@calldatasize], r1, r1 - add @CPI0_4[0], r0, r2 - sub! r1, r0, r3 - add r0, r0, r3 - add.lt r2, r0, r3 - and @CPI0_4[0], r1, r1 - sub! r1, r0, r4 - add.le r0, r0, r2 - sub.s! @CPI0_4[0], r1, r1 - add r3, r0, r1 - add.eq r2, r0, r1 - sub! r1, r0, r1 - jump.ne @.BB0_2 - add 42, r0, r1 - st.1 128, r1 - add @CPI0_5[0], r0, r1 - ret.ok.to_label r1, @DEFAULT_FAR_RETURN -.BB0_1: - context.get_context_u128 r1 - sub! r1, r0, r1 - jump.ne @.BB0_2 - add 32, r0, r1 - st.2 256, r1 - st.2 288, r0 - add @CPI0_1[0], r0, r1 - ret.ok.to_label r1, @DEFAULT_FAR_RETURN -.BB0_2: - add r0, r0, r1 - ret.revert.to_label r1, @DEFAULT_FAR_REVERT -.func_end0: - - .data - .p2align 5 -calldatasize: - .cell 0 - - .p2align 5 -ptr_calldata: -.cell 0 - - .note.GNU-stack - .rodata -CPI0_0: - .cell 4294967295 -CPI0_1: - .cell 53919893334301279589334030174039261352344891250716429051063678533632 -CPI0_2: - .cell -26959946667150639794667015087019630673637144422540572481103610249216 -CPI0_3: - .cell 40953307615929575801107647705360601464619672688377251939886941387873771847680 -CPI0_4: - .cell -57896044618658097711785492504343953926634992332820282019728792003956564819968 -CPI0_5: - .cell 2535301202817642044428229017600 -``` diff --git a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/10.index.md b/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/10.index.md deleted file mode 100644 index 323d4efe..00000000 --- a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/10.index.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -title: Instruction Reference -description: ---- - -In this specification, instructions are grouped by their relevance to the EVM instruction set: - -- [Native EVM instructions](instructions/evm). -- [Yul auxiliary instructions](instructions/yul). -- [EVM legacy assembly auxiliary instructions](instructions/evmla). - -Most of the EVM native instructions are represented in both Yul and EVM legacy assembly IRs. If they are not, it is -stated explicitly in the description of each instruction. - -## Addressing modes - -EraVM is a register-based virtual machine with different addressing modes. -It overrides all stack mechanics described in [the official documentation of EVM opcodes](https://www.evm.codes/) including -errors they produce on EVM. - -## Solidity Intermediate Representations (IRs) - -Every instruction is translated via two IRs available in the Solidity compiler unless stated otherwise: - -1. Yul -2. EVM legacy assembly - -## Yul Extensions - -ZKsync EraVM introduced a set of EraVM-specific instructions. The set is documented at [the official *zksolc* documentation](https://matter-labs.github.io/era-compiler-solidity/latest/). diff --git a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/10.index.md b/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/10.index.md deleted file mode 100644 index bc6bd15d..00000000 --- a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/10.index.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -title: Native EVM Instructions -description: ---- - -Such instructions are grouped into the following categories according to [the original reference](https://www.evm.codes/): - -- [Arithmetic](evm/arithmetic) -- [Bitwise](evm/bitwise) -- [Block](evm/block) -- [Call](evm/call) -- [Create](evm/create) -- [Environment](evm/environment) -- [Logging](evm/logging) -- [Logical](evm/logical) -- [Memory](evm/memory) -- [Return](evm/return) -- [SHA3](evm/sha3) -- [Stack](evm/stack) - -### EraVM Assembly - -Assembly emitted for LLVM standard library functions depends on available optimizations which differ between versions. If there is no -assembly example under an instruction, compile a reproducing contract with the latest version of `zksolc`. - -EraVM specification contains a list of [all EraVM instructions (see the table of contents)](https://matter-labs.github.io/eravm-spec/spec.html). diff --git a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/100.memory.md b/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/100.memory.md deleted file mode 100644 index 1642fc5d..00000000 --- a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/100.memory.md +++ /dev/null @@ -1,76 +0,0 @@ ---- -title: Memory -description: ---- - -## MLOAD - -Original [EVM](https://www.evm.codes/#51?fork=shanghai) instruction. - -Heap memory load operation is modeled with a native EraVM instruction. - -### LLVM IR - -```txt -%value = load i256, ptr addrspace(1) %pointer, align 1 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/memory.rs#L15) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#load-instruction) - -### EraVM Assembly - -```asm -ld.1 r1, r2 -``` - -See [EraVM instruction: `st.1`](https://matter-labs.github.io/eravm-spec/spec.html#LoadDefinition) - -## MSTORE - -Original [EVM](https://www.evm.codes/#52?fork=shanghai) instruction. - -Heap memory load operation is modeled with a native EraVM instruction. - -### LLVM IR - -```txt -store i256 128, ptr addrspace(1) inttoptr (i256 64 to ptr addrspace(1)), align 1 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/memory.rs#L38) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#store-instruction) - -### EraVM Assembly - -```asm -st.1 r1, r2 -``` - -See [EraVM instruction: `st.1`](https://matter-labs.github.io/eravm-spec/spec.html#StoreDefinition) - -## MSTORE8 - -Original [EVM](https://www.evm.codes/#53?fork=shanghai) instruction. - -### LLVM IR - -```txt -define void @__mstore8(i256 addrspace(1)* nocapture nofree noundef dereferenceable(32) %addr, i256 %val) #2 { -entry: - %orig_value = load i256, i256 addrspace(1)* %addr, align 1 - %orig_value_shifted_left = shl i256 %orig_value, 8 - %orig_value_shifted_right = lshr i256 %orig_value_shifted_left, 8 - %byte_value_shifted = shl i256 %val, 248 - %store_result = or i256 %orig_value_shifted_right, %byte_value_shifted - store i256 %store_result, i256 addrspace(1)* %addr, align 1 - ret void -} -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/memory.rs#L62) -is common for Yul and EVMLA representations. diff --git a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/110.return.md b/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/110.return.md deleted file mode 100644 index 2056e214..00000000 --- a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/110.return.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: Return -description: ---- - -## STOP - -Original [EVM](https://www.evm.codes/#00?fork=shanghai) instruction. - -This instruction is a [RETURN](#return) with an empty data payload. - -### LLVM IR - -The same as for [RETURN](#return). - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/return.rs#L103) -is common for Yul and EVMLA representations. - -## RETURN - -Original [EVM](https://www.evm.codes/#f3?fork=shanghai) instruction. - -This instruction works differently in deploy code. For more information, see [the ZKsync Era documentation](/zksync-protocol/differences/evm-instructions#return-stop). - -### LLVM IR - -```txt -define void @__return(i256 %0, i256 %1, i256 %2) "noinline-oz" #5 personality i32()* @__personality { -entry: - %abi = call i256@__aux_pack_abi(i256 %0, i256 %1, i256 %2) - tail call void @llvm.syncvm.return(i256 %abi) - unreachable -} -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/return.rs#L16) -is common for Yul and EVMLA representations. - -## REVERT - -Original [EVM](https://www.evm.codes/#fd?fork=shanghai) instruction. - -### LLVM IR - -```txt -define void @__revert(i256 %0, i256 %1, i256 %2) "noinline-oz" #5 personality i32()* @__personality { -entry: - %abi = call i256@__aux_pack_abi(i256 %0, i256 %1, i256 %2) - tail call void @llvm.syncvm.revert(i256 %abi) - unreachable -} -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/return.rs#L86) -is common for Yul and EVMLA representations. - -### EraVM - -See also EraVM instruction `revert`: [when returning from near calls](https://matter-labs.github.io/eravm-spec/spec.html#NearRevertDefinition) -and [when returning from far calls](https://matter-labs.github.io/eravm-spec/spec.html#FarRevertDefinition). - -## INVALID - -Original [EVM](https://www.evm.codes/#fe?fork=shanghai) instruction. - -This instruction is a [REVERT](#revert) with an empty data payload, but it also burns all the available gas. - -### LLVM IR - -The same as for [REVERT](#revert). - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/return.rs#L115) -is common for Yul and EVMLA representations. - -### EraVM - -See also EraVM instruction `revert`: [when returning from near calls](https://matter-labs.github.io/eravm-spec/spec.html#NearRevertDefinition) -and [when returning from far calls](https://matter-labs.github.io/eravm-spec/spec.html#FarRevertDefinition). diff --git a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/120.sha3.md b/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/120.sha3.md deleted file mode 100644 index 559c9063..00000000 --- a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/120.sha3.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -title: Sha3 -description: ---- - -Original [EVM instruction](https://www.evm.codes/#20?fork=shanghai). - -## System Contract - -This instruction is handled by a System Contract called [Keccak256](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/precompiles/Keccak256.yul), -which is a wrapper around the EraVM precompile. - -On how the System Contract is called, see [this section](https://github.com/code-423n4/2024-03-zksync/blob/main/docs/VM%20Section/How%20compiler%20works/system_contracts.md). - -## LLVM IR - -```text -define i256 @__sha3(i8 addrspace(1)* nocapture nofree noundef %0, i256 %1, i1 %throw_at_failure) "noinline-oz" #1 personality i32()* @__personality { -entry: - %addr_int = ptrtoint i8 addrspace(1)* %0 to i256 - %2 = tail call i256 @llvm.umin.i256(i256 %addr_int, i256 4294967295) - %3 = tail call i256 @llvm.umin.i256(i256 %1, i256 4294967295) - %gas_left = tail call i256 @llvm.syncvm.gasleft() - %4 = tail call i256 @llvm.umin.i256(i256 %gas_left, i256 4294967295) - %abi_data_input_offset_shifted = shl nuw nsw i256 %2, 64 - %abi_data_input_length_shifted = shl nuw nsw i256 %3, 96 - %abi_data_gas_shifted = shl nuw nsw i256 %4, 192 - %abi_data_offset_and_length = add i256 %abi_data_input_length_shifted, %abi_data_input_offset_shifted - %abi_data_add_gas = add i256 %abi_data_gas_shifted, %abi_data_offset_and_length - %abi_data_add_system_call_marker = add i256 %abi_data_add_gas, 904625697166532776746648320380374280103671755200316906558262375061821325312 - %call_external = tail call { i8 addrspace(3)*, i1 } @__staticcall(i256 %abi_data_add_system_call_marker, i256 32784, i256 undef, i256 undef, i256 undef, i256 undef, i256 undef, i256 undef, i256 undef, i256 undef, i256 undef, i256 undef) - %status_code = extractvalue { i8 addrspace(3)*, i1 } %call_external, 1 - br i1 %status_code, label %success_block, label %failure_block - -success_block: - %abi_data_pointer = extractvalue { i8 addrspace(3)*, i1 } %call_external, 0 - %data_pointer = bitcast i8 addrspace(3)* %abi_data_pointer to i256 addrspace(3)* - %keccak256_child_data = load i256, i256 addrspace(3)* %data_pointer, align 1 - ret i256 %keccak256_child_data - -failure_block: - br i1 %throw_at_failure, label %throw_block, label %revert_block - -revert_block: - call void @__revert(i256 0, i256 0, i256 0) - unreachable - -throw_block: - call void @__cxa_throw(i8* noalias nocapture nofree align 32 null, i8* noalias nocapture nofree align 32 undef, i8* noalias nocapture nofree align 32 undef) - unreachable -} -``` diff --git a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/130.stack.md b/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/130.stack.md deleted file mode 100644 index ebac9b04..00000000 --- a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/130.stack.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -title: Stack -description: ---- - -## POP - -Original [EVM](https://www.evm.codes/#50?fork=shanghai) instruction. - -In Yul, only used to mark unused values, and is not translated to LLVM IR. - -```solidity -pop(staticcall(gas(), address(), 0, 64, 0, 32)) -``` - -For EVMLA, see [EVM Legacy Assembly Translator](/zksync-protocol/compiler/specification/evmla-translator). - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/evmla/assembly/instruction/stack.rs#L108). - -## JUMPDEST - -Original [EVM](https://www.evm.codes/#5b?fork=shanghai) instruction. - -Is not available in Yul. - -Ignored in EVMLA. See [EVM Legacy Assembly Translator](/zksync-protocol/compiler/specification/evmla-translator) for more information. - -## PUSH - PUSH32 - -Original [EVM](https://www.evm.codes/#5f?fork=shanghai) instructions. - -Is not available in Yul. - -For EVMLA, see [EVM Legacy Assembly Translator](/zksync-protocol/compiler/specification/evmla-translator). - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/evmla/assembly/instruction/stack.rs#L10). - -## DUP1 - DUP16 - -Original [EVM](https://www.evm.codes/#80?fork=shanghai) instructions. - -Is not available in Yul. - -For EVMLA, see [EVM Legacy Assembly Translator](/zksync-protocol/compiler/specification/evmla-translator). - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/evmla/assembly/instruction/stack.rs#L48). - -## SWAP1 - SWAP16 - -Original [EVM](https://www.evm.codes/#90?fork=shanghai) instructions. - -Is not available in Yul. - -For EVMLA, see [EVM Legacy Assembly Translator](/zksync-protocol/compiler/specification/evmla-translator). - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/evmla/assembly/instruction/stack.rs#L74). diff --git a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/20.arithmetic.md b/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/20.arithmetic.md deleted file mode 100644 index 28bfedf9..00000000 --- a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/20.arithmetic.md +++ /dev/null @@ -1,369 +0,0 @@ ---- -title: Arithmetic -description: ---- - -## ADD - -Original [EVM](https://www.evm.codes/#01?fork=shanghai) instruction. - -### LLVM IR - -```txt -%addition_result = add i256 %value1, %value2 -``` - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/evm/arithmetic.rs#L15) is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#add-instruction) - -### EraVM Assembly - -```asm -add r1, r2, r1 -``` - -For more detail, see the [EraVM specification reference](%%zk_git_repo_eravm-spec%%/spec.html#AddDefinition) - -## MUL - -Original [EVM](https://www.evm.codes/#02?fork=shanghai) instruction. - -### Differences from EVM - -1. The carry is written to the 2nd output register - -### LLVM IR - -```txt -%multiplication_result = mul i256 %value1, %value2 -``` - -EraVM can output the carry of the multiplication operation. -In this case, the result is a tuple of two values: the multiplication result and the carry. -The carry is written to the 2nd output register. -The snippet below returns the carry value. - -```txt -%value1_extended = zext i256 %value1 to i512 -%value2_extended = zext i256 %value2 to i512 -%result_extended = mul nuw i512 %value1_extended, %value2_extended -%result_shifted = lshr i512 %result_extended, 256 -%result = trunc i512 %result_shifted to i256 -``` - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/evm/arithmetic.rs#L53) is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#mul-instruction) - -### EraVM Assembly - -```asm -mul r1, r2, r1, r2 -``` - -For more detail, see the [EraVM specification reference](%%zk_git_repo_eravm-spec%%/spec.html#MulDefinition) - -## SUB - -Original [EVM](https://www.evm.codes/#03?fork=shanghai) instruction. - -### LLVM IR - -```txt -%subtraction_result = sub i256 %value1, %value2 -``` - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/evm/arithmetic.rs#L34) is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#sub-instruction) - -### EraVM Assembly - -```asm -sub r1, r2, r1 -``` - -For more detail, see the [EraVM specification reference](%%zk_git_repo_eravm-spec%%/spec.html#SubDefinition) - -## DIV - -Original [EVM](https://www.evm.codes/#04?fork=shanghai) instruction. - -### Differences from EVM - -1. The remainder is written to the 2nd output register - -### LLVM IR - -```text -define i256 @__div(i256 %arg1, i256 %arg2) #0 { -entry: - %is_divider_zero = icmp eq i256 %arg2, 0 - br i1 %is_divider_zero, label %return, label %division - -division: - %div_res = udiv i256 %arg1, %arg2 - br label %return - -return: - %res = phi i256 [ 0, %entry ], [ %div_res, %division ] - ret i256 %res -} -``` - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/evm/arithmetic.rs#L73) is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#udiv-instruction) - -For more detail, see the [EraVM specification reference](%%zk_git_repo_eravm-spec%%/spec.html#DivDefinition) - -## SDIV - -Original [EVM](https://www.evm.codes/#05?fork=shanghai) instruction. - -### LLVM IR - -```txt -define i256 @__sdiv(i256 %arg1, i256 %arg2) #0 { -entry: - %is_divider_zero = icmp eq i256 %arg2, 0 - br i1 %is_divider_zero, label %return, label %division_overflow - -division_overflow: - %is_divided_int_min = icmp eq i256 %arg1, -57896044618658097711785492504343953926634992332820282019728792003956564819968 - %is_minus_one = icmp eq i256 %arg2, -1 - %is_overflow = and i1 %is_divided_int_min, %is_minus_one - br i1 %is_overflow, label %return, label %division - -division: - %div_res = sdiv i256 %arg1, %arg2 - br label %return - -return: - %res = phi i256 [ 0, %entry ], [ %arg1, %division_overflow ], [ %div_res, %division ] - ret i256 %res -} -``` - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/evm/arithmetic.rs#L162) is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#sdiv-instruction) - -EraVM does not have a similar instruction. - -## MOD - -Original [EVM](https://www.evm.codes/#06?fork=shanghai) instruction. - -### Differences from EVM - -1. The remainder is written to the 2nd output register - -### LLVM IR - -```txt -define i256 @__mod(i256 %arg1, i256 %arg2) #0 { -entry: - %is_divider_zero = icmp eq i256 %arg2, 0 - br i1 %is_divider_zero, label %return, label %remainder - -remainder: - %rem_res = urem i256 %arg1, %arg2 - br label %return - -return: - %res = phi i256 [ 0, %entry ], [ %rem_res, %remainder ] - ret i256 %res -} -``` - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/evm/arithmetic.rs#L117) is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#urem-instruction) - -For more detail, see the [EraVM specification reference](%%zk_git_repo_eravm-spec%%/spec.html#DivDefinition) - -## SMOD - -Original [EVM](https://www.evm.codes/#07?fork=shanghai) instruction. - -### LLVM IR - -```txt -define i256 @__smod(i256 %arg1, i256 %arg2) #0 { -entry: - %is_divider_zero = icmp eq i256 %arg2, 0 - br i1 %is_divider_zero, label %return, label %division_overflow - -division_overflow: - %is_divided_int_min = icmp eq i256 %arg1, -57896044618658097711785492504343953926634992332820282019728792003956564819968 - %is_minus_one = icmp eq i256 %arg2, -1 - %is_overflow = and i1 %is_divided_int_min, %is_minus_one - br i1 %is_overflow, label %return, label %remainder - -remainder: - %rem_res = srem i256 %arg1, %arg2 - br label %return - -return: - %res = phi i256 [ 0, %entry ], [ 0, %division_overflow ], [ %rem_res, %remainder ] - ret i256 %res -} -``` - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/evm/arithmetic.rs#L236) is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#srem-instruction) - -EraVM does not have a similar instruction. - -## ADDMOD - -Original [EVM](https://www.evm.codes/#08?fork=shanghai) instruction. - -### LLVM IR - -```txt -define i256 @__addmod(i256 %arg1, i256 %arg2, i256 %modulo) #0 { -entry: - %is_zero = icmp eq i256 %modulo, 0 - br i1 %is_zero, label %return, label %addmod - -addmod: - %arg1m = urem i256 %arg1, %modulo - %arg2m = urem i256 %arg2, %modulo - %res = call {i256, i1} @llvm.uadd.with.overflow.i256(i256 %arg1m, i256 %arg2m) - %sum = extractvalue {i256, i1} %res, 0 - %obit = extractvalue {i256, i1} %res, 1 - %sum.mod = urem i256 %sum, %modulo - br i1 %obit, label %overflow, label %return - -overflow: - %mod.inv = xor i256 %modulo, -1 - %sum1 = add i256 %sum, %mod.inv - %sum.ovf = add i256 %sum1, 1 - br label %return - -return: - %value = phi i256 [0, %entry], [%sum.mod, %addmod], [%sum.ovf, %overflow] - ret i256 %value -} -``` - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/evm/math.rs#L16) is common for Yul and EVMLA representations. - -EraVM does not have a similar instruction. - -## MULMOD - -Original [EVM](https://www.evm.codes/#09?fork=shanghai) instruction. - -### LLVM IR - -```txt -define i256 @__mulmod(i256 %arg1, i256 %arg2, i256 %modulo) #0 { -entry: - %cccond = icmp eq i256 %modulo, 0 - br i1 %cccond, label %ccret, label %entrycont - -ccret: - ret i256 0 - -entrycont: - %arg1m = urem i256 %arg1, %modulo - %arg2m = urem i256 %arg2, %modulo - %less_then_2_128 = icmp ult i256 %modulo, 340282366920938463463374607431768211456 - br i1 %less_then_2_128, label %fast, label %slow - -fast: - %prod = mul i256 %arg1m, %arg2m - %prodm = urem i256 %prod, %modulo - ret i256 %prodm - -slow: - %arg1e = zext i256 %arg1m to i512 - %arg2e = zext i256 %arg2m to i512 - %prode = mul i512 %arg1e, %arg2e - %prodl = trunc i512 %prode to i256 - %prodeh = lshr i512 %prode, 256 - %prodh = trunc i512 %prodeh to i256 - %res = call i256 @__ulongrem(i256 %prodl, i256 %prodh, i256 %modulo) - ret i256 %res -} -``` - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/evm/math.rs#L43) is common for Yul and EVMLA representations. - -EraVM does not have a similar instruction. - -## EXP - -Original [EVM](https://www.evm.codes/#0a?fork=shanghai) instruction. - -### LLVM IR - -```txt -define i256 @__exp(i256 %value, i256 %exp) "noinline-oz" #0 { -entry: - %exp_is_non_zero = icmp eq i256 %exp, 0 - br i1 %exp_is_non_zero, label %return, label %exponent_loop_body - -return: - %exp_res = phi i256 [ 1, %entry ], [ %exp_res.1, %exponent_loop_body ] - ret i256 %exp_res - -exponent_loop_body: - %exp_res.2 = phi i256 [ %exp_res.1, %exponent_loop_body ], [ 1, %entry ] - %exp_val = phi i256 [ %exp_val_halved, %exponent_loop_body ], [ %exp, %entry ] - %val_squared.1 = phi i256 [ %val_squared, %exponent_loop_body ], [ %value, %entry ] - %odd_test = and i256 %exp_val, 1 - %is_exp_odd = icmp eq i256 %odd_test, 0 - %exp_res.1.interm = select i1 %is_exp_odd, i256 1, i256 %val_squared.1 - %exp_res.1 = mul i256 %exp_res.1.interm, %exp_res.2 - %val_squared = mul i256 %val_squared.1, %val_squared.1 - %exp_val_halved = lshr i256 %exp_val, 1 - %exp_val_is_less_2 = icmp ult i256 %exp_val, 2 - br i1 %exp_val_is_less_2, label %return, label %exponent_loop_body -} -``` - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/evm/math.rs#L70) is common for Yul and EVMLA representations. - -EraVM does not have a similar instruction. - -## SIGNEXTEND - -Original [EVM](https://www.evm.codes/#0b?fork=shanghai) instruction. - -### LLVM IR - -```txt -define i256 @__signextend(i256 %numbyte, i256 %value) #0 { -entry: - %is_overflow = icmp uge i256 %numbyte, 31 - br i1 %is_overflow, label %return, label %signextend - -signextend: - %numbit_byte = mul nuw nsw i256 %numbyte, 8 - %numbit = add nsw nuw i256 %numbit_byte, 7 - %numbit_inv = sub i256 256, %numbit - %signmask = shl i256 1, %numbit - %valmask = lshr i256 -1, %numbit_inv - %ext1 = shl i256 -1, %numbit - %signv = and i256 %signmask, %value - %sign = icmp ne i256 %signv, 0 - %valclean = and i256 %value, %valmask - %sext = select i1 %sign, i256 %ext1, i256 0 - %result = or i256 %sext, %valclean - br label %return - -return: - %signext_res = phi i256 [%value, %entry], [%result, %signextend] - ret i256 %signext_res -} -``` - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/evm/math.rs#L93) is common for Yul and EVMLA representations. - -EraVM does not have a similar instruction. diff --git a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/30.bitwise.md b/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/30.bitwise.md deleted file mode 100644 index fa533b4f..00000000 --- a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/30.bitwise.md +++ /dev/null @@ -1,218 +0,0 @@ ---- -title: Bitwise -description: ---- - -## AND - -Original [EVM](https://www.evm.codes/#16?fork=shanghai) instruction. - -### LLVM IR - -```txt -%and_result = and i256 %value1, %value2 -``` - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/evm/bitwise.rs#L47) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#and-instruction) - -### EraVM Assembly - -```asm -ptr.add stack[@ptr_calldata], r0, r1 -ptr.add.s 36, r1, r2 -ld r2, r2 -ptr.add.s 4, r1, r1 -ld r1, r1 -and r1, r2, r1 -st.1 128, r1 -``` - -[EraVM instruction: `and`](%%zk_git_repo_eravm-spec%%/spec.html#AndDefinition) - -## OR - -Original [EVM](https://www.evm.codes/#17?fork=shanghai) instruction. - -### LLVM IR - -```txt -%or_result = or i256 %value1, %value2 -``` - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/evm/bitwise.rs#L13) is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#or-instruction) - -### EraVM Assembly - -```asm -ptr.add stack[@ptr_calldata], r0, r1 -ptr.add.s 36, r1, r2 -ld r2, r2 -ptr.add.s 4, r1, r1 -ld r1, r1 -or r1, r2, r1 -st.1 128, r1 -``` - -[EraVM instruction: `or`](%%zk_git_repo_eravm-spec%%/spec.html#AndDefinition) - -## XOR - -Original [EVM](https://www.evm.codes/#18?fork=shanghai) instruction. - -### LLVM IR - -```txt -%xor_result = or i256 %value1, %value2 -``` - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/evm/bitwise.rs#L30) is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#xor-instruction) - -### EraVM Assembly - -```asm -ptr.add stack[@ptr_calldata], r0, r1 -ptr.add.s 36, r1, r2 -ld r2, r2 -ptr.add.s 4, r1, r1 -ld r1, r1 -xor r1, r2, r1 -st.1 128, r1 -``` - -[EraVM instruction: `xor`](%%zk_git_repo_eravm-spec%%/spec.html#XorDefinition) - -## NOT - -Original [EVM](https://www.evm.codes/#19?fork=shanghai) instruction. - -### LLVM IR - -```txt -%xor_result = xor i256 %value, -1 -``` - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/evm/bitwise.rs#L30) is common for Yul and EVMLA representations. - -### EraVM Assembly - -```asm -ptr.add stack[@ptr_calldata], r1, r1 -ld r1, r1 -sub.s 1, r0, r2 -xor r1, r2, r1 -st.1 128, r1 -``` - -[EraVM instruction: `xor`](%%zk_git_repo_eravm-spec%%/spec.html#XorDefinition) - -## BYTE - -Original [EVM](https://www.evm.codes/#1a?fork=shanghai) instruction. - -### LLVM IR - -```txt -define i256 @__byte(i256 %index, i256 %value) #0 { -entry: - %is_overflow = icmp ugt i256 %index, 31 - br i1 %is_overflow, label %return, label %extract_byte - -extract_byte: - %bits_offset = shl i256 %index, 3 - %value_shifted_left = shl i256 %value, %bits_offset - %value_shifted_right = lshr i256 %value_shifted_left, 248 - br label %return - -return: - %res = phi i256 [ 0, %entry ], [ %value_shifted_right, %extract_byte ] - ret i256 %res -} -``` - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/evm/bitwise.rs#L229) is common for Yul and EVMLA representations. - -## SHL - -Original [EVM](https://www.evm.codes/#1b?fork=shanghai) instruction. - -### LLVM IR - -```txt -define i256 @__shl(i256 %shift, i256 %value) #0 { -entry: - %is_overflow = icmp ugt i256 %shift, 255 - br i1 %is_overflow, label %return, label %shift_value - -shift_value: - %shift_res = shl i256 %value, %shift - br label %return - -return: - %res = phi i256 [ 0, %entry ], [ %shift_res, %shift_value ] - ret i256 %res -} -``` - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/evm/bitwise.rs#L67) is common for Yul and EVMLA representations. - -## SHR - -Original [EVM](https://www.evm.codes/#1c?fork=shanghai) instruction. - -### LLVM IR - -```txt -define i256 @__shr(i256 %shift, i256 %value) #0 { -entry: - %is_overflow = icmp ugt i256 %shift, 255 - br i1 %is_overflow, label %return, label %shift_value - -shift_value: - %shift_res = lshr i256 %value, %shift - br label %return - -return: - %res = phi i256 [ 0, %entry ], [ %shift_res, %shift_value ] - ret i256 %res -} -``` - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/evm/bitwise.rs#L111) is common for Yul and EVMLA representations. - -[EraVM instruction: `xor`](%%zk_git_repo_eravm-spec%%/spec.html#XorDefinition) - -## SAR - -Original [EVM](https://www.evm.codes/#1d?fork=shanghai) instruction. - -### LLVM IR - -```txt -define i256 @__sar(i256 %shift, i256 %value) #0 { -entry: - %is_overflow = icmp ugt i256 %shift, 255 - br i1 %is_overflow, label %arith_overflow, label %shift_value - -arith_overflow: - %is_val_positive = icmp sge i256 %value, 0 - %res_overflow = select i1 %is_val_positive, i256 0, i256 -1 - br label %return - -shift_value: - %shift_res = ashr i256 %value, %shift - br label %return - -return: - %res = phi i256 [ %res_overflow, %arith_overflow ], [ %shift_res, %shift_value ] - ret i256 %res -} -``` - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/evm/bitwise.rs#L157) is common for Yul and EVMLA representations. diff --git a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/40.block.md b/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/40.block.md deleted file mode 100644 index 332cd153..00000000 --- a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/40.block.md +++ /dev/null @@ -1,156 +0,0 @@ ---- -title: Block -description: ---- - -## BLOCKHASH - -Original [EVM](https://www.evm.codes/#40?fork=shanghai) instruction. - -### System Contract - -This information is requested a System Contract called [SystemContext](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/SystemContext.sol). - -On how the System Contract is called, see [this section](/zksync-protocol/compiler/specification/system-contracts#environmental-data-storage). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/context.rs#L47) -is common for Yul and EVMLA representations. - -The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) runtime function. - -## COINBASE - -Original [EVM](https://www.evm.codes/#41?fork=shanghai) instruction. - -### System Contract - -This information is requested a System Contract called [SystemContext](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/SystemContext.sol). - -On how the System Contract is called, see [this section](/zksync-protocol/compiler/specification/system-contracts#environmental-data-storage). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/context.rs#L150) -is common for Yul and EVMLA representations. - -The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) runtime function. - -## TIMESTAMP - -Original [EVM](https://www.evm.codes/#42?fork=shanghai) instruction. - -### System Contract - -This information is requested a System Contract called [SystemContext](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/SystemContext.sol). - -On how the System Contract is called, see [this section](/zksync-protocol/compiler/specification/system-contracts#environmental-data-storage). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/context.rs#L98) -is common for Yul and EVMLA representations. - -The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) runtime function. - -## NUMBER - -Original [EVM](https://www.evm.codes/#43?fork=shanghai) instruction. - -### System Contract - -This information is requested a System Contract called [SystemContext](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/SystemContext.sol). - -On how the System Contract is called, see [this section](/zksync-protocol/compiler/specification/system-contracts#environmental-data-storage). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/context.rs#L81) -is common for Yul and EVMLA representations. - -The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) runtime function. - -## PREVRANDAO - -Original [EVM](https://www.evm.codes/#44?fork=shanghai) instruction. | DIFFICULTY - -Original [EVM](https://www.evm.codes/#44?fork=grayGlacier) - -### System Contract - -This information is requested a System Contract called [SystemContext](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/SystemContext.sol). - -On how the System Contract is called, see [this section](/zksync-protocol/compiler/specification/system-contracts#environmental-data-storage). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/context.rs#L133) -is common for Yul and EVMLA representations. - -The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) runtime function. - -## GASLIMIT - -Original [EVM](https://www.evm.codes/#45?fork=shanghai) instruction. - -### System Contract - -This information is requested a System Contract called [SystemContext](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/SystemContext.sol). - -On how the System Contract is called, see [this section](/zksync-protocol/compiler/specification/system-contracts#environmental-data-storage). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/context.rs#L13) -is common for Yul and EVMLA representations. - -The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) runtime function. - -## CHAINID - -Original [EVM](https://www.evm.codes/#46?fork=shanghai) instruction. - -### System Contract - -This information is requested a System Contract called [SystemContext](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/SystemContext.sol). - -On how the System Contract is called, see [this section](/zksync-protocol/compiler/specification/system-contracts#environmental-data-storage). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/context.rs#L64) -is common for Yul and EVMLA representations. - -The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) runtime function. - -## SELFBALANCE - -Original [EVM](https://www.evm.codes/#47?fork=shanghai) instruction. - -Implemented as [BALANCE](environment#balance) with an [ADDRESS](environment#address) as its argument. - -## BASEFEE - -Original [EVM](https://www.evm.codes/#48?fork=shanghai) instruction. - -### System Contract - -This information is requested a System Contract called [SystemContext](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/SystemContext.sol). - -On how the System Contract is called, see [this section](/zksync-protocol/compiler/specification/system-contracts#environmental-data-storage). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/context.rs#L167) -is common for Yul and EVMLA representations. - -The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) runtime function. diff --git a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/50.call.md b/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/50.call.md deleted file mode 100644 index 92b123a8..00000000 --- a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/50.call.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -title: Call -description: ---- - -All EVM call instructions are handled similarly. - -The call type is encoded on the assembly level, so we will describe the common handling workflow, mentioning distinctions if there are any. - -For more information, see the -[ZKsync Era documentation](/zksync-protocol/differences/evm-instructions). - -## CALL - -Original [EVM](https://www.evm.codes/#f1?fork=shanghai) instruction. - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/call.rs#L530) -is common for Yul and EVMLA representations. - -The code checks if the call is non-static and the Ether value is non-zero. If so, the call is redirected to the [MsgValueSimulator](/zksync-protocol/compiler/specification/system-contracts#ether-value-simulator). - -- [EraVM instruction: `call` (near call)](https://matter-labs.github.io/eravm-spec/spec.html#NearCallDefinition) -- [EraVM instruction: `far_call`](https://matter-labs.github.io/eravm-spec/spec.html#FarCalls) - -## DELEGATECALL - -Original [EVM](https://www.evm.codes/#f4?fork=shanghai) instruction. - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/call.rs#L530) -is common for Yul and EVMLA representations. - -[EraVM instruction: `far_call`](https://matter-labs.github.io/eravm-spec/spec.html#FarCalls) - -## STATICCALL - -Original [EVM](https://www.evm.codes/#fa?fork=shanghai) instruction. - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/call.rs#L530) -is common for Yul and EVMLA representations. - -[EraVM instruction: `far_call`](https://matter-labs.github.io/eravm-spec/spec.html#FarCalls) diff --git a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/60.create.md b/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/60.create.md deleted file mode 100644 index 173a950e..00000000 --- a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/60.create.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -title: Create -description: ---- - -The EVM CREATE instructions are handled similarly. - -For more information, see the [ZKsync Era documentation](/zksync-protocol/differences/evm-instructions#create-create2). - -## CREATE - -Original [EVM](https://www.evm.codes/#f0?fork=shanghai) instruction. - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/create.rs#L19) -is common for Yul and EVMLA representations. - -## CREATE2 - -Original [EVM](https://www.evm.codes/#f5?fork=shanghai) instruction. - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/create.rs#L57) -is common for Yul and EVMLA representations. diff --git a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/70.environment.md b/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/70.environment.md deleted file mode 100644 index 87a65fdd..00000000 --- a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/70.environment.md +++ /dev/null @@ -1,332 +0,0 @@ ---- -title: Environment ---- - -## ADDRESS - -Original [EVM](https://www.evm.codes/#30?fork=shanghai) instruction. - -This value is fetched with a native [EraVM instruction: `context.this`](https://matter-labs.github.io/eravm-spec/spec.html#ContextDefinitions). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/yul/parser/statement/expression/function_call/mod.rs#L973) -is common for Yul and EVMLA representations. - -## BALANCE - -Original [EVM](https://www.evm.codes/#31?fork=shanghai) instruction. - -### System Contract - -This information is requested a System Contract called [L2BaseToken](https://github.com/code-423n4/2024-03-zksync/blob/main/code/system-contracts/contracts/L2BaseToken.sol). - -On how the System Contract is called, see [this section](/zksync-protocol/compiler/specification/system-contracts#environmental-data-storage). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/ether_gas.rs#L39) -is common for Yul and EVMLA representations. - -The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) runtime function. - -## ORIGIN - -Original [EVM](https://www.evm.codes/#32?fork=shanghai) instruction. - -### System Contract - -This information is requested a System Contract called [SystemContext](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/SystemContext.sol). - -On how the System Contract is called, see [this section](/zksync-protocol/compiler/specification/system-contracts#environmental-data-storage). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/context.rs#L47) -is common for Yul and EVMLA representations. - -The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) runtime function. - -## CALLER - -Original [EVM](https://www.evm.codes/#33?fork=shanghai) instruction. - -This value is fetched with a native [EraVM instruction: `context.caller`](https://matter-labs.github.io/eravm-spec/spec.html#ContextDefinitions). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/yul/parser/statement/expression/function_call/mod.rs#L974) -is common for Yul and EVMLA representations. - -## CALLVALUE - -Original [EVM](https://www.evm.codes/#34?fork=shanghai) instruction. - -This value is fetched with a native [EraVM instruction: `context.get_context_u128`](https://matter-labs.github.io/eravm-spec/spec.html#ContextDefinitions). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/ether_gas.rs#L25) -is common for Yul and EVMLA representations. - -## CALLDATALOAD - -Original [EVM](https://www.evm.codes/#35?fork=shanghai) instruction. - -Calldata is accessed with a generic memory access instruction, but the memory chunk itself is a reference -to the calling contract's heap. -A fat pointer to the parent contract is passed via ABI using registers. - -Then, the pointer [is saved to a global stack variable](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/entry.rs#L129) -accessible from anywhere in the contract. - -### LLVM IR - -```txt -@ptr_calldata = private unnamed_addr global ptr addrspace(3) null ; global variable declaration -... -store ptr addrspace(3) %0, ptr @ptr_calldata, align 32 ; saving the pointer from `r1` to the global variable -... -%calldata_pointer = load ptr addrspace(3), ptr @ptr_calldata, align 32 ; loading the pointer from the global variable to `calldata_pointer` -%calldata_value = load i256, ptr addrspace(3) %calldata_pointer, align 32 ; loading the value from the calldata pointer -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/calldata.rs#L14) -is common for Yul and EVMLA representations. - -### EraVM Assembly - -```asm -ptr.add r1, r0, stack[@ptr_calldata] ; saving the pointer from `r1` to the global variable -... -ptr.add stack[@ptr_calldata], r0, r1 ; loading the pointer from the global variable to `r1` -ld r1, r1 ; loading the value to `r1` -``` - -- [EraVM instruction: `ptr.add`](https://matter-labs.github.io/eravm-spec/spec.html#PtrAddDefinition) -- [EraVM fat pointers](https://matter-labs.github.io/eravm-spec/spec.html#PointerDefinitions) -- [EraVM memory forwarding mechanism](https://matter-labs.github.io/eravm-spec/spec.html#MemoryForwarding) - -## CALLDATASIZE - -Original [EVM](https://www.evm.codes/#36?fork=shanghai) instruction. - -Calldata size is stored in the fat pointer passed from the parent contract (see [CALLDATALOAD](#calldataload)). - -The size value can be extracted with bitwise operations as illustrated below. - -### LLVM IR - -```txt -@calldatasize = private unnamed_addr global i256 0 ; global variable declaration -... -%abi_pointer_value = ptrtoint ptr addrspace(3) %0 to i256 ; converting the pointer to an integer -%abi_pointer_value_shifted = lshr i256 %abi_pointer_value, 96 ; shifting the integer right 96 bits -%abi_length_value = and i256 %abi_pointer_value_shifted, 4294967295 ; keeping the lowest 32 bits of the integer -store i256 %abi_length_value, ptr @calldatasize, align 32 ; saving the value to the global variable -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/calldata.rs#L40) -is common for Yul and EVMLA representations. - -### EraVM Assembly - -```asm -ptr.add r1, r0, stack[@ptr_calldata] ; saving the pointer from `r1` to the global variable -shr.s 96, r1, r1 ; shifting the integer right 96 bits -and @CPI0_0[0], r1, stack[@calldatasize] ; keeping the lowest 32 bits of the integer, saving the value to the global variable -... -CPI0_0: - .cell 4294967295 -``` - -- [EraVM instruction: `ptr.add`](https://matter-labs.github.io/eravm-spec/spec.html#PtrAddDefinition) -- [EraVM fat pointers](https://matter-labs.github.io/eravm-spec/spec.html#PointerDefinitions) -- [EraVM memory forwarding mechanism](https://matter-labs.github.io/eravm-spec/spec.html#MemoryForwarding) - -## CALLDATACOPY - -Original [EVM](https://www.evm.codes/#37?fork=shanghai) instruction. - -Unlike on EVM, on EraVM it is a simple loop over [CALLDATALOAD](#calldataload)). - -### LLVM IR - -```txt -; loading the pointer from the global variable to `calldata_pointer` -%calldata_pointer = load ptr addrspace(3), ptr @ptr_calldata, align 32 -; shifting the pointer by 122 bytes -%calldata_source_pointer = getelementptr i8, ptr addrspace(3) %calldata_pointer, i256 122 -; copying 64 bytes from calldata at offset 122 to the heap at offset 128 -call void @llvm.memcpy.p1.p3.i256(ptr addrspace(1) align 1 inttoptr (i256 128 to ptr addrspace(1)), ptr addrspace(3) align 1 %calldata_source_pointer, i256 64, i1 false) -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/calldata.rs#L54) -is common for Yul and EVMLA representations. - -### EraVM Assembly - -```asm -.BB0_3: - shl.s 5, r2, r3 ; shifting the offset by 32 - ptr.add r1, r3, r4 ; adding the offset to the calldata pointer - ld r4, r4 ; reading the calldata value - add 128, r3, r3 ; adding the offset to the heap pointer - st.1 r3, r4 ; writing the calldata value to the heap - add 1, r2, r2 ; incrementing the offset - sub.s! 2, r2, r3 ; checking the bounds - jump.lt @.BB0_3 ; loop continuation branching -``` - -- [EraVM instruction: `ptr.add`](https://matter-labs.github.io/eravm-spec/spec.html#PtrAddDefinition) -- [EraVM fat pointers](https://matter-labs.github.io/eravm-spec/spec.html#PointerDefinitions) -- [EraVM memory forwarding mechanism](https://matter-labs.github.io/eravm-spec/spec.html#MemoryForwarding) - -## CODECOPY - -Original [EVM](https://www.evm.codes/#38?fork=shanghai) instruction. - -See [the EraVM docs](/zksync-protocol/differences/evm-instructions#codecopy). - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/evmla/ethereal_ir/function/block/element/mod.rs#L856). - -## CODESIZE - -Original [EVM](https://www.evm.codes/#39?fork=shanghai) instruction. - -See [the EraVM docs](/zksync-protocol/differences/evm-instructions#codesize). - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-solidity/blob/main/src/evmla/ethereal_ir/function/block/element/mod.rs#L837). - -## GASPRICE - -Original [EVM](https://www.evm.codes/#3a?fork=shanghai) instruction. - -### System Contract - -This information is requested a System Contract called [SystemContext](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/SystemContext.sol). - -On how the System Contract is called, see [this section](/zksync-protocol/compiler/specification/system-contracts#environmental-data-storage). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/context.rs#L30) -is common for Yul and EVMLA representations. - -The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) runtime function. - -## EXTCODESIZE - -Original [EVM](https://www.evm.codes/#3b?fork=shanghai) instruction. - -### System Contract - -This information is requested a System Contract called [AccountCodeStorage](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/AccountCodeStorage.sol). - -On how the System Contract is called, see [this section](/zksync-protocol/compiler/specification/system-contracts#environmental-data-storage). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/ext_code.rs#L11) -is common for Yul and EVMLA representations. - -The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) runtime function. - -## EXTCODECOPY - -Original [EVM](https://www.evm.codes/#3c?fork=shanghai) instruction. - -Not supported. Triggers a compile-time error. - -## RETURNDATASIZE - -Original [EVM](https://www.evm.codes/#3d?fork=shanghai) instruction. - -Return data size is read from the fat pointer returned from the child contract. - -The size value can be extracted with bitwise operations as illustrated below. - -### LLVM IR - -```txt -%contract_call_external = tail call { ptr addrspace(3), i1 } @__farcall(i256 0, i256 0, i256 undef, i256 undef, i256 undef, i256 undef, i256 undef, i256 undef, i256 undef, i256 undef, i256 undef, i256 undef) -%contract_call_external_result_abi_data = extractvalue { ptr addrspace(3), i1 } %contract_call_external, 0 -%contract_call_memcpy_from_child_pointer_casted = ptrtoint ptr addrspace(3) %contract_call_external_result_abi_data to i256 -%contract_call_memcpy_from_child_return_data_size_shifted = lshr i256 %contract_call_memcpy_from_child_pointer_casted, 96 -%contract_call_memcpy_from_child_return_data_size_truncated = and i256 %contract_call_memcpy_from_child_return_data_size_shifted, 4294967295 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/return_data.rs#L16) -is common for Yul and EVMLA representations. - -### EraVM Assembly - -```asm -near_call r0, @__farcall, @DEFAULT_UNWIND ; calling a child contract -shr.s 96, r1, r1 ; shifting the pointer value right 96 bits -and @CPI0_1[0], r1, r1 ; keeping the lowest 32 bits of the pointer value -... -CPI0_1: - .cell 4294967295 -``` - -[EraVM instruction: `call`](https://matter-labs.github.io/eravm-spec/spec.html#NearCallDefinition) - -## RETURNDATACOPY - -Original [EVM](https://www.evm.codes/#3e?fork=shanghai) instruction. - -Unlike on EVM, on EraVM it is a simple loop over memory operations on 256-bit values. - -### LLVM IR - -```txt -; loading the pointer from the global variable to `return_data_pointer` -%return_data_pointer = load ptr addrspace(3), ptr @ptr_return_data, align 32 -; shifting the pointer by 122 bytes -%return_data_source_pointer = getelementptr i8, ptr addrspace(3) %return_data_pointer, i256 122 -; copying 64 bytes from return data at offset 122 to the heap at offset 128 -call void @llvm.memcpy.p1.p3.i256(ptr addrspace(1) align 1 inttoptr (i256 128 to ptr addrspace(1)), ptr addrspace(3) align 1 %return_data_source_pointer, i256 64, i1 false) -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/return_data.rs#L31) -is common for Yul and EVMLA representations. - -### EraVM Assembly - -```asm -.BB0_3: - shl.s 5, r2, r3 ; shifting the offset by 32 - ptr.add r1, r3, r4 ; adding the offset to the return data pointer - ld r4, r4 ; reading the return data value - add 128, r3, r3 ; adding the offset to the heap pointer - st.1 r3, r4 ; writing the return data value to the heap - add 1, r2, r2 ; incrementing the offset - sub.s! 2, r2, r3 ; checking the bounds - jump.lt @.BB0_3 ; loop continuation branching -``` - -- [EraVM instruction: `jump`](https://matter-labs.github.io/eravm-spec/spec.html#JumpDefinition) -- [EraVM instruction predication](https://matter-labs.github.io/eravm-spec/spec.html#Predication) - -## EXTCODEHASH - -Original [EVM](https://www.evm.codes/#3f?fork=shanghai) instruction. - -### System Contract - -This information is requested a System Contract called [AccountCodeStorage](https://github.com/matter-labs/era-system-contracts/blob/main/contracts/AccountCodeStorage.sol). - -On how the System Contract is called, see [this section](/zksync-protocol/compiler/specification/system-contracts#environmental-data-storage). - -### LLVM IR - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/ext_code.rs#L29) -is common for Yul and EVMLA representations. - -The request to the System Contract is done via the -[SystemRequest](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/context/function/runtime/system_request.rs) runtime function. diff --git a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/80.logging.md b/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/80.logging.md deleted file mode 100644 index f94b6745..00000000 --- a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/80.logging.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -title: Logging -description: ---- - -## Events - -The EraVM event instructions are more low-level. -Each `LOG`-like instruction is unrolled into a loop, -where each iteration writes two 256-bit words. - -The words must contain data in the following order: - -1. The initializer cell, describing the number of indexed words (e.g. `I`) - and the size of non-indexed data in bytes (e.g. `D`) -2. `I` indexed 32-byte words -3. `D` bytes of data - -Each write operation can contain some subsequent data from its next step. -If only one word remains, the second input is zero. - -See [EraVM instruction: `log.event`](https://matter-labs.github.io/eravm-spec/spec.html#EventDefinition) - -## LOG0 - LOG4 - -[LOG0](https://www.evm.codes/#a0?fork=shanghai) - [LOG4](https://www.evm.codes/#a4?fork=shanghai) - -### System Contract - -This information is requested a System Contract called [EventWriter](https://github.com/code-423n4/2024-03-zksync/blob/main/code/system-contracts/contracts/EventWriter.yul). - -On how the System Contract is called, see [System contraacts](/zksync-protocol/contracts/system-contracts). - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/event.rs#L20) -is common for Yul and EVMLA representations. diff --git a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/90.logical.md b/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/90.logical.md deleted file mode 100644 index a0c3873c..00000000 --- a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/90.logical.md +++ /dev/null @@ -1,205 +0,0 @@ ---- -title: Logical -description: ---- - -## LT - -Original [EVM](https://www.evm.codes/#10?fork=shanghai) instruction. - -### LLVM IR - -```txt -%comparison_result = icmp ult i256 %value1, %value2 -%comparison_result_extended = zext i1 %comparison_result to i256 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/comparison.rs#L15) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#icmp-instruction) - -### EraVM Assembly - -```asm -ptr.add stack[@ptr_calldata], r0, r1 -ptr.add.s 36, r1, r2 -ld r2, r2 -ptr.add.s 4, r1, r1 -ld r1, r1 -sub! r1, r2, r1 -add 0, r0, r1 -add.lt 1, r0, r1 -st.1 128, r1 -``` - -## GT - -Original [EVM](https://www.evm.codes/#11?fork=shanghai) instruction. - -### LLVM IR - -```txt -%comparison_result = icmp ugt i256 %value1, %value2 -%comparison_result_extended = zext i1 %comparison_result to i256 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/comparison.rs#L15) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#icmp-instruction) - -### EraVM Assembly - -```asm -ptr.add stack[@ptr_calldata], r0, r1 -ptr.add.s 36, r1, r2 -ld r2, r2 -ptr.add.s 4, r1, r1 -ld r1, r1 -sub! r1, r2, r1 -add 0, r0, r1 -add.gt 1, r0, r1 -st.1 128, r1 -``` - -## SLT - -Original [EVM](https://www.evm.codes/#12?fork=shanghai) instruction. - -### LLVM IR - -```txt -%comparison_result = icmp slt i256 %value1, %value2 -%comparison_result_extended = zext i1 %comparison_result to i256 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/comparison.rs#L15) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#icmp-instruction) - -### EraVM Assembly - -```asm -ptr.add stack[@ptr_calldata], r0, r1 -ptr.add.s 36, r1, r2 -ld r2, r2 -ptr.add.s 4, r1, r1 -ld r1, r1 -add @CPI0_4[0], r0, r3 -sub! r1, r2, r4 -add r0, r0, r4 -add.lt r3, r0, r4 -and @CPI0_4[0], r2, r2 -and @CPI0_4[0], r1, r1 -sub! r1, r2, r5 -add.le r0, r0, r3 -xor r1, r2, r1 -sub.s! @CPI0_4[0], r1, r1 -add r4, r0, r1 -add.eq r3, r0, r1 -sub! r1, r0, r1 -add 0, r0, r1 -add.ne 1, r0, r1 -st.1 128, r1 -``` - -## SGT - -Original [EVM](https://www.evm.codes/#13?fork=shanghai) instruction. - -### LLVM IR - -```txt -%comparison_result = icmp sgt i256 %value1, %value2 -%comparison_result_extended = zext i1 %comparison_result to i256 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/comparison.rs#L15) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#icmp-instruction) - -### EraVM Assembly - -```asm -ptr.add stack[@ptr_calldata], r0, r1 -ptr.add.s 36, r1, r2 -ld r2, r2 -ptr.add.s 4, r1, r1 -ld r1, r1 -add @CPI0_4[0], r0, r3 -sub! r1, r2, r4 -add r0, r0, r4 -add.gt r3, r0, r4 -and @CPI0_4[0], r2, r2 -and @CPI0_4[0], r1, r1 -sub! r1, r2, r5 -add.ge r0, r0, r3 -xor r1, r2, r1 -sub.s! @CPI0_4[0], r1, r1 -add r4, r0, r1 -add.eq r3, r0, r1 -sub! r1, r0, r1 -add 0, r0, r1 -add.ne 1, r0, r1 -st.1 128, r1 -``` - -## EQ - -Original [EVM](https://www.evm.codes/#14?fork=shanghai) instruction. - -### LLVM IR - -```txt -%comparison_result = icmp eq i256 %value1, %value2 -%comparison_result_extended = zext i1 %comparison_result to i256 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/comparison.rs#L15) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#icmp-instruction) - -### EraVM Assembly - -```asm -ptr.add stack[@ptr_calldata], r0, r1 -ptr.add.s 36, r1, r2 -ld r2, r2 -ptr.add.s 4, r1, r1 -ld r1, r1 -sub! r1, r2, r1 -add 0, r0, r1 -add.eq 1, r0, r1 -st.1 128, r1 -``` - -## ISZERO - -Original [EVM](https://www.evm.codes/#15?fork=shanghai) instruction. - -### LLVM IR - -```txt -%comparison_result = icmp eq i256 %value, 0 -%comparison_result_extended = zext i1 %comparison_result to i256 -``` - -[The LLVM IR generator code](https://github.com/matter-labs/era-compiler-llvm-context/blob/main/src/eravm/evm/comparison.rs#L15) -is common for Yul and EVMLA representations. - -[LLVM IR instruction documentation](https://releases.llvm.org/15.0.0/docs/LangRef.html#icmp-instruction) - -### EraVM Assembly - -```asm -ptr.add stack[@ptr_calldata], r1, r1 -ld r1, r1 -sub! r1, r0, r1 -add 0, r0, r1 -add.eq 1, r0, r1 -st.1 128, r1 -``` diff --git a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/_dir.yml b/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/_dir.yml deleted file mode 100644 index 963f5d49..00000000 --- a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/20.evm/_dir.yml +++ /dev/null @@ -1 +0,0 @@ -title: EVM diff --git a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/30.evmla.md b/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/30.evmla.md deleted file mode 100644 index 1eb6f389..00000000 --- a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/30.evmla.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -title: EVM Legacy Assembly -description: ---- - -These instructions do not have a direct representation in EVM or ZKsync VM. Instead, they perform auxiliary operations -required for generating the target bytecode. - -## PUSH [$] - -The same as [datasize](/zksync-protocol/compiler/specification/instructions/yul#datasize). - -LLVM IR codegen references: - - -1. [zksolc compiler](%%zk_git_repo_era-compiler-solidity%%/blob/main/src/evmla/ethereal_ir/function/block/element/mod.rs#L144) -2. [Shared FE code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/zkevm/evm/create.rs#L149) - -## PUSH #[$] - -The same as [dataoffset](/zksync-protocol/compiler/specification/instructions/yul#dataoffset). - -LLVM IR codegen references: - -1. [zksolc compiler](%%zk_git_repo_era-compiler-solidity%%/blob/main/src/evmla/ethereal_ir/function/block/element/mod.rs#L135) -2. [Shared FE code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/zkevm/evm/create.rs#L97) - -## ASSIGNIMMUTABLE - -The same as [setimmutable](/zksync-protocol/compiler/specification/instructions/yul#setimmutable). - -For more information, see the -[Differences with Ethereum](/zksync-protocol/differences/evm-instructions#setimmutable-loadimmutable). - -LLVM IR codegen references: - -1. [zksolc compiler](%%zk_git_repo_era-compiler-solidity%%/blob/main/src/evmla/ethereal_ir/function/block/element/mod.rs#L760) -2. [Shared FE code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/zkevm/evm/immutable.rs#L79) - -## PUSHIMMUTABLE - -The same as [loadimmutable](/zksync-protocol/compiler/specification/instructions/yul#loadimmutable). - -For more information, see the -[Differences with Ethereum](/zksync-protocol/differences/evm-instructions#setimmutable-loadimmutable). - -LLVM IR codegen references: - -1. [zksolc compiler](%%zk_git_repo_era-compiler-solidity%%/blob/main/src/evmla/ethereal_ir/function/block/element/mod.rs#L747) -2. [Shared FE code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/zkevm/evm/immutable.rs#L17) - -## PUSHLIB - -The same as [linkersymbol](/zksync-protocol/compiler/specification/instructions/yul#linkersymbol). - -For more information, see the -[Differences with Ethereum](/zksync-protocol/differences/libraries). - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-solidity%%/blob/main/src/yul/parser/statement/expression/function_call/mod.rs#L956). - -## PUSHDEPLOYADDRESS - -Returns the address the contract is deployed to. - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-solidity%%/blob/main/src/yul/parser/statement/expression/function_call/mod.rs#L956). - -## PUSHSIZE - -Can be only found in deploy code. On EVM, returns the total size of the runtime code and constructor arguments. - -On ZKsync VM, it is always 0, since ZKsync VM does not operate on runtime code in deploy code. - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-solidity%%/blob/main/src/yul/parser/statement/expression/function_call/mod.rs#L907). - -## PUSH data - -Pushes a data chunk onto the stack. Data chunks are resolved during the processing of input assembly JSON. - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-solidity%%/blob/main/src/evmla/ethereal_ir/function/block/element/mod.rs#L164). - -## PUSH [tag] - -Pushes an EVM Legacy Assembly destination block identifier onto the stack. - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-solidity%%/blob/main/src/evmla/assembly/instruction/stack.rs#L31). - -## Tag - -Starts a new EVM Legacy Assembly block. Tags are processed during the translation of EVM Legacy Assembly into EthIR. diff --git a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/40.yul.md b/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/40.yul.md deleted file mode 100644 index 5491f530..00000000 --- a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/40.yul.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -title: Yul -description: ---- - -These instructions do not have a direct representation in EVM or ZKsync VM. Instead, they perform auxiliary operations -required for generating the target bytecode. - -## datasize - -Original [Yul](https://docs.soliditylang.org/en/latest/yul.html#datasize-dataoffset-datacopy) auxiliary instruction. - -Unlike on EVM, on ZKsync VM target this instruction returns the size of the header part of the calldata sent to the -[ContractDeployer](/zksync-protocol/compiler/specification/system-contracts#contract-deployer). -For more information, see [CREATE](/zksync-protocol/compiler/specification/instructions/evm/create). - -LLVM IR codegen references: - -1. [zksolc compiler](%%zk_git_repo_era-compiler-solidity%%/blob/main/src/yul/parser/statement/expression/function_call/mod.rs#L928) -2. [Shared FE code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/zkevm/evm/create.rs#L149) - -## dataoffset - -Original [Yul](https://docs.soliditylang.org/en/latest/yul.html#datasize-dataoffset-datacopy) auxiliary instruction. - -Unlike on EVM, on ZKsync VM target this instruction has nothing to do with the offset. Instead, it returns the bytecode hash -of the contract referenced by the Yul object identifier. Since our compiler translates instructions without analyzing -the surrounding context, it is not possible to get the bytecode hash from anywhere else in [datacopy](#datacopy). For -more information, see [CREATE](/zksync-protocol/compiler/specification/instructions/evm/create). - -LLVM IR codegen references: - -1. [zksolc compiler](%%zk_git_repo_era-compiler-solidity%%/blob/main/src/yul/parser/statement/expression/function_call/mod.rs#L918) -2. [Shared FE code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/zkevm/evm/create.rs#L97) - -## datacopy - -Original [Yul](https://docs.soliditylang.org/en/latest/yul.html#datasize-dataoffset-datacopy) auxiliary instruction. - -Unlike on EVM, on ZKsync VM target this instruction copies the bytecode hash passed as [dataoffset](#dataoffset) to the -destination. For more information, see [CREATE](/zksync-protocol/compiler/specification/instructions/evm/create). - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-solidity%%/blob/main/src/yul/parser/statement/expression/function_call/mod.rs#L938). - -## setimmutable - -Original [Yul](https://docs.soliditylang.org/en/latest/yul.html#setimmutable-loadimmutable) auxiliary instruction. - -Writes immutables to the auxiliary heap. - -For more information, see the [Differences with Ethereum](/zksync-protocol/differences/evm-instructions#setimmutable-loadimmutable). - -LLVM IR codegen references: - -1. [zksolc compiler](%%zk_git_repo_era-compiler-solidity%%/blob/main/src/yul/parser/statement/expression/function_call/mod.rs#L562) -2. [Shared FE code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/evm/immutable.rs#L79) - -## loadimmutable - -Original [Yul](https://docs.soliditylang.org/en/latest/yul.html#setimmutable-loadimmutable) auxiliary instruction. - -Reads immutables from the [ImmutableSimulator](/zksync-protocol/compiler/specification/system-contracts#simulator-of-immutables). - -For more information, see the -[Differences with Ethereum](/zksync-protocol/differences/evm-instructions#setimmutable-loadimmutable). - -LLVM IR codegen references: - -1. [zksolc compiler](%%zk_git_repo_era-compiler-solidity%%/blob/main/src/yul/parser/statement/expression/function_call/mod.rs#L540) -2. [Shared FE code](%%zk_git_repo_era-compiler-llvm-context%%/blob/main/src/eravm/evm/immutable.rs#L17) - -## linkersymbol - -Original [Yul](https://docs.soliditylang.org/en/latest/yul.html#linkersymbol) auxiliary instruction. - -Returns the address of a deployable library. The address must be passed to `zksolc` with the `--libraries` option, -otherwise a compile-time error will be produced. - -There is a special `zksolc` execution mode that can be enabled with `--missing-libraries` flag. In this mode, the -compiler will return the list of deployable libraries not provided with `--libraries`. This mode allows package managers -like Hardhat to automatically deploy libraries. - -For more information, see the -[Differences with Ethereum](/zksync-protocol/differences/libraries). - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-solidity%%/blob/main/src/yul/parser/statement/expression/function_call/mod.rs#L956). - -## memoryguard - -Original [Yul](https://docs.soliditylang.org/en/latest/yul.html#memoryguard) auxiliary instruction. - -Is a Yul optimizer hint which is not used by our compiler. Instead, its only argument is simply unwrapped and returned. - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-solidity%%/blob/main/src/yul/parser/statement/expression/function_call/mod.rs#L968). - -## verbatim - -Original [Yul](https://docs.soliditylang.org/en/latest/yul.html#verbatim) auxiliary instruction. - -Unlike on EVM, on ZKsync VM target this instruction has nothing to do with inserting of EVM bytecode. Instead, it is used to implement -[ZKsync EraVM Yul Extensions](https://matter-labs.github.io/era-compiler-solidity/latest/06-eravm-extensions.html). -In order to compile a Yul contract with extensions, both Yul mode and EraVM extensions must be enabled (`zksolc --yul --enable-eravm-extensions ...`). - -[The LLVM IR generator code](%%zk_git_repo_era-compiler-solidity%%/blob/main/src/yul/parser/statement/expression/function_call/verbatim.rs). diff --git a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/_dir.yml b/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/_dir.yml deleted file mode 100644 index 1117f7ca..00000000 --- a/content/20.zksync-protocol/50.compiler/20.specification/60.instructions/_dir.yml +++ /dev/null @@ -1 +0,0 @@ -title: Instructions diff --git a/content/20.zksync-protocol/50.compiler/20.specification/70.binary-layout.md b/content/20.zksync-protocol/50.compiler/20.specification/70.binary-layout.md deleted file mode 100644 index f3edf18c..00000000 --- a/content/20.zksync-protocol/50.compiler/20.specification/70.binary-layout.md +++ /dev/null @@ -1,367 +0,0 @@ ---- -title: EraVM binary layout -description: How assembler listing looks like and how it is transformed into a binary file, sent to the chain. ---- - -## Definitions - -- A directive is a command issued to the assembler, which is not translated into -an executable bytecode instruction. -Their names start with a period, for example, `.cell`. -Directives are used to regulate the translation process. -- An instruction constitutes the smallest executable segment of bytecode. -In EraVM, each instruction is exactly eight bytes long. -- A word is a 256-bit unsigned integer in a big-endian format. - -## Structure of assembly file - -This section describes the structure of an EraVM assembly file, a text file -typically with the extension `.zasm`. - -### Data types - -- `U256` – word, a 256-bit unsigned integer number, big-endian. -- `U16` – 16-bit unsigned integer number, big-endian. - -### Sections - -The source code within an EraVM assembly is organized into distinct -sections. The start of a section is denoted by one of the following -directives: - -- `.rodata` – constant, read-only data. -- `.data` – global mutable data. -- `.text` – executable code. - -Additional sections may be implemented in the future. - -The description of any section may be spread across the file: - -```asm -.rodata - .cell 0 -.text - -.rodata - .cell 1 -``` - -In this example, multiple `.rodata` sections appear, but in the resulting binary -file they will be merged into a single contiguous region of memory. -Same principle applies to other sections. - -### Defining data - -The `.cell` directive defines data: - -```asm -.rodata - .cell -1 - .cell 23090 -.data - .cell 1213 -``` - -- Note: using `.cell` in the `.data` section is deprecated and will not be supported in the future versions of assembly. -- The value of cell is provided as a signed 256-bit decimal number. -- Negative numbers will be encoded as 256-bit 2’s complement, e.g. `-1` is encoded as `0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`. -- An optional `+` sign before positive numbers is allowed, e.g. `.cell +123`. -- Hexadecimal integer literals are not supported. -- Symbols (names of labels) are supported, for example: - -```asm -.text - -f: - add r0, r0, r0 - -g: - add r0, r0, r0 - -.rodata - -my_cells: - .cell @lab1 - .cell @lab2 - .cell -1 -``` - - Note the `@` prefixing the label name. - - Each `.cell` is 256-bit wide, even though an address such as `@lab1` or `@lab2` is just 16-bit wide. - Addresses are padded with zeroes to fit in the word. - -### Overall structure - -The structure of an assembly file is described as follows: - -```asm - :=
* - -
:= - | ".rodata" * - | ".data" * - | ".text" * - - :=