EIP-145: EVM 中的按位移位指令
提供与其它算术运算成本相当的原生按位移位。
Authors | Alex Beregszaszi (@axic), Paweł Bylica (@chfast) |
---|---|
Created | 2017-02-13 |
Table of Contents
摘要
引入原生按位移位指令,这在主机上的处理效率更高,并且合约使用起来更便宜。
动机
EVM 缺少按位移位运算符,但支持其他逻辑和算术运算符。移位操作可以通过算术运算符来实现,但这具有更高的成本,并且需要主机花费更多的处理时间。使用算术实现 SHL
和 SHR
各自花费 35 gas,而提议的指令消耗 3 gas。
规范
引入以下指令:
0x1b
: SHL
(左移)
SHL
指令(左移)从堆栈中弹出 2 个值,首先是 arg1
,然后是 arg2
,并将 arg2
左移 arg1
位数后压入堆栈。结果等于
(arg2 * 2^arg1) mod 2^256
注意:
- 该值 (
arg2
) 被解释为无符号数。 - 移位量 (
arg1
) 被解释为无符号数。 - 如果移位量 (
arg1
) 大于或等于 256,则结果为 0。 - 这等效于
PUSH1 2 EXP MUL
。
0x1c
: SHR
(逻辑右移)
SHR
指令(逻辑右移)从堆栈中弹出 2 个值,首先是 arg1
,然后是 arg2
,并将 arg2
右移 arg1
位数,并用零填充后压入堆栈。结果等于
floor(arg2 / 2^arg1)
注意:
- 该值 (
arg2
) 被解释为无符号数。 - 移位量 (
arg1
) 被解释为无符号数。 - 如果移位量 (
arg1
) 大于或等于 256,则结果为 0。 - 这等效于
PUSH1 2 EXP DIV
。
0x1d
: SAR
(算术右移)
SAR
指令(算术右移)从堆栈中弹出 2 个值,首先是 arg1
,然后是 arg2
,并将 arg2
右移 arg1
位数,并进行符号扩展后压入堆栈。结果等于
floor(arg2 / 2^arg1)
注意:
- 该值 (
arg2
) 被解释为有符号数。 - 移位量 (
arg1
) 被解释为无符号数。 - 如果移位量 (
arg1
) 大于或等于 256,则如果arg2
为非负数,则结果为 0,如果arg2
为负数,则结果为 -1。 - 这与
PUSH1 2 EXP SDIV
不等效,因为它采用不同的舍入方式。参见SDIV(-1, 2) == 0
,而SAR(-1, 1) == -1
。
移位指令的成本设置为 verylow
等级(3 gas)。
原理
选择指令操作数是为了适应已经位于堆栈上的值的更自然的移位用例。这意味着与大多数算术指令相比,操作数顺序被交换了。
向后兼容性
新引入的指令对过去创建的字节码没有影响。
测试用例
SHL
(左移)
-
PUSH 0x0000000000000000000000000000000000000000000000000000000000000001 PUSH 0x00 SHL --- 0x0000000000000000000000000000000000000000000000000000000000000001
-
PUSH 0x0000000000000000000000000000000000000000000000000000000000000001 PUSH 0x01 SHL --- 0x0000000000000000000000000000000000000000000000000000000000000002
-
PUSH 0x0000000000000000000000000000000000000000000000000000000000000001 PUSH 0xff SHL --- 0x8000000000000000000000000000000000000000000000000000000000000000
-
PUSH 0x0000000000000000000000000000000000000000000000000000000000000001 PUSH 0x0100 SHL --- 0x0000000000000000000000000000000000000000000000000000000000000000
-
PUSH 0x0000000000000000000000000000000000000000000000000000000000000001 PUSH 0x0101 SHL --- 0x0000000000000000000000000000000000000000000000000000000000000000
-
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff PUSH 0x00 SHL --- 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff PUSH 0x01 SHL --- 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe
-
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff PUSH 0xff SHL --- 0x8000000000000000000000000000000000000000000000000000000000000000
-
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff PUSH 0x0100 SHL --- 0x0000000000000000000000000000000000000000000000000000000000000000
-
PUSH 0x0000000000000000000000000000000000000000000000000000000000000000 PUSH 0x01 SHL --- 0x0000000000000000000000000000000000000000000000000000000000000000
-
PUSH 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff PUSH 0x01 SHL --- 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe
SHR
(逻辑右移)
-
PUSH 0x0000000000000000000000000000000000000000000000000000000000000001 PUSH 0x00 SHR --- 0x0000000000000000000000000000000000000000000000000000000000000001
-
PUSH 0x0000000000000000000000000000000000000000000000000000000000000001 PUSH 0x01 SHR --- 0x0000000000000000000000000000000000000000000000000000000000000000
-
PUSH 0x8000000000000000000000000000000000000000000000000000000000000000 PUSH 0x01 SHR --- 0x4000000000000000000000000000000000000000000000000000000000000000
-
PUSH 0x8000000000000000000000000000000000000000000000000000000000000000 PUSH 0xff SHR --- 0x0000000000000000000000000000000000000000000000000000000000000001
-
PUSH 0x8000000000000000000000000000000000000000000000000000000000000000 PUSH 0x0100 SHR --- 0x0000000000000000000000000000000000000000000000000000000000000000
-
PUSH 0x8000000000000000000000000000000000000000000000000000000000000000 PUSH 0x0101 SHR --- 0x0000000000000000000000000000000000000000000000000000000000000000
-
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff PUSH 0x00 SHR --- 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff PUSH 0x01 SHR --- 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff PUSH 0xff SHR --- 0x0000000000000000000000000000000000000000000000000000000000000001
-
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff PUSH 0x0100 SHR --- 0x0000000000000000000000000000000000000000000000000000000000000000
-
PUSH 0x0000000000000000000000000000000000000000000000000000000000000000 PUSH 0x01 SHR --- 0x0000000000000000000000000000000000000000000000000000000000000000
SAR
(算术右移)
-
PUSH 0x0000000000000000000000000000000000000000000000000000000000000001 PUSH 0x00 SAR --- 0x0000000000000000000000000000000000000000000000000000000000000001
-
PUSH 0x0000000000000000000000000000000000000000000000000000000000000001 PUSH 0x01 SAR --- 0x0000000000000000000000000000000000000000000000000000000000000000
-
PUSH 0x8000000000000000000000000000000000000000000000000000000000000000 PUSH 0x01 SAR --- 0xc000000000000000000000000000000000000000000000000000000000000000
-
PUSH 0x8000000000000000000000000000000000000000000000000000000000000000 PUSH 0xff SAR --- 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-
PUSH 0x8000000000000000000000000000000000000000000000000000000000000000 PUSH 0x0100 SAR --- 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-
PUSH 0x8000000000000000000000000000000000000000000000000000000000000000 PUSH 0x0101 SAR --- 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff PUSH 0x00 SAR --- 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff PUSH 0x01 SAR --- 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff PUSH 0xff SAR --- 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-
PUSH 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff PUSH 0x0100 SAR --- 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
-
PUSH 0x0000000000000000000000000000000000000000000000000000000000000000 PUSH 0x01 SAR --- 0x0000000000000000000000000000000000000000000000000000000000000000
-
PUSH 0x4000000000000000000000000000000000000000000000000000000000000000 PUSH 0xfe SAR --- 0x0000000000000000000000000000000000000000000000000000000000000001
-
PUSH 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff PUSH 0xf8 SAR --- 0x000000000000000000000000000000000000000000000000000000000000007f
-
PUSH 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff PUSH 0xfe SAR --- 0x0000000000000000000000000000000000000000000000000000000000000001
-
PUSH 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff PUSH 0xff SAR --- 0x0000000000000000000000000000000000000000000000000000000000000000
-
PUSH 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff PUSH 0x0100 SAR --- 0x0000000000000000000000000000000000000000000000000000000000000000
实现
客户端支持:
- cpp-ethereum: https://github.com/ethereum/cpp-ethereum/pull/4054
编译器支持:
- Solidity/LLL: https://github.com/ethereum/solidity/pull/2541
测试
来源:
- https://github.com/ethereum/tests/tree/develop/src/GeneralStateTestsFiller/stShift
已填充的测试:
- https://github.com/ethereum/tests/tree/develop/GeneralStateTests/stShift
- https://github.com/ethereum/tests/tree/develop/BlockchainTests/GeneralStateTests/stShift
版权
在 CC0 下放弃版权及相关权利。
Citation
Please cite this document as:
Alex Beregszaszi (@axic), Paweł Bylica (@chfast), "EIP-145: EVM 中的按位移位指令," Ethereum Improvement Proposals, no. 145, February 2017. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-145.