diff --git a/tests/compiler/ir/test_optimize_ir.py b/tests/compiler/ir/test_optimize_ir.py index 80eab3cbdd9..86405b76112 100644 --- a/tests/compiler/ir/test_optimize_ir.py +++ b/tests/compiler/ir/test_optimize_ir.py @@ -74,6 +74,13 @@ (["mod", "x", 128], ["and", "x", 127]), (["sdiv", "x", 64], ["sdiv", "x", 64]), # no-op (["smod", "x", 64], ["smod", "x", 64]), # no-op + (["exp", 3, 5], [3**5]), + (["exp", 3, 256], [(3**256) % (2**256)]), + (["exp", 2, 257], [0]), + (["exp", "x", 0], ["iszero", "x"]), + (["exp", "x", 1], ["x"]), + (["exp", 1, "x"], [1]), + (["exp", 0, "x"], [0]), # bitwise ops (["shr", 0, "x"], ["x"]), (["sar", 0, "x"], ["x"]), diff --git a/vyper/ir/optimizer.py b/vyper/ir/optimizer.py index 0fec39b6e0f..69ef6b5684a 100644 --- a/vyper/ir/optimizer.py +++ b/vyper/ir/optimizer.py @@ -47,6 +47,7 @@ def _is_int(node: IRnode) -> bool: "sdiv": (evm_div, "/", SIGNED), "mod": (evm_mod, "%", UNSIGNED), "smod": (evm_mod, "%", SIGNED), + "exp": (operator.pow, "**", UNSIGNED), "eq": (operator.eq, "==", UNSIGNED), "ne": (operator.ne, "!=", UNSIGNED), "lt": (operator.lt, "<", UNSIGNED), @@ -165,6 +166,20 @@ def _conservative_eq(x, y): new_val = "sub" new_args = [0, args[0]] + elif binop == "exp": + # n ** 0 == (0 if n == 0 else 1) + if _int(args[1]) == 0: + new_val = "iszero" + new_args = [args[0]] + # n ** 1 == n + if _int(args[1]) == 1: + new_val = args[0].value + new_args = args[0].args + # 0 ** n == 0; 1 ** n == 1 + if _int(args[0]) in (0, 1): + new_val = _int(args[0]) + new_args = [] + # maybe OK: # elif binop == "div" and _int(args[1], UNSIGNED) == MAX_UINT256: # # (div x (2**256 - 1)) == (eq x (2**256 - 1))