Merge branch 'feature/babylon-optimizer' into 'dev'

Update optimizer for Babylon

See merge request ligolang/ligo!158
This commit is contained in:
Tom Jack 2019-10-31 15:17:00 +00:00
commit 76ecd56e3d
2 changed files with 63 additions and 49 deletions

View File

@ -14,13 +14,44 @@ open Tezos_utils.Michelson
without effects other than gas consumption. It must never fail. *) without effects other than gas consumption. It must never fail. *)
let arity : prim -> int option = function let arity : prim -> int option = function
(* stack things *)
| I_DIP -> None
| I_DROP -> None
| I_DUP -> None
| I_SWAP -> None
| I_DIG -> None
| I_DUG -> None
(* control *)
| I_FAILWITH -> None
| I_EXEC -> None
| I_IF -> None
| I_IF_CONS -> None
| I_IF_LEFT -> None
| I_IF_NONE -> None
| I_LOOP -> None
| I_MAP -> None
| I_ITER -> None
| I_LOOP_LEFT -> None
(* internal ops *)
| I_CREATE_ACCOUNT -> None
| I_CREATE_CONTRACT -> None
| I_TRANSFER_TOKENS -> None
| I_SET_DELEGATE -> None
(* tez arithmetic (can fail) *)
| I_ADD -> None
| I_MUL -> None
| I_SUB -> None (* can fail for tez *)
(* etc *)
| I_CONCAT -> None (* sometimes 1, sometimes 2 :( *)
| I_CAST -> None
| I_RENAME -> None
(* stuff *)
| I_PACK -> Some 1 | I_PACK -> Some 1
| I_UNPACK -> Some 1 | I_UNPACK -> Some 1
| I_BLAKE2B -> Some 1 | I_BLAKE2B -> Some 1
| I_SHA256 -> Some 1 | I_SHA256 -> Some 1
| I_SHA512 -> Some 1 | I_SHA512 -> Some 1
| I_ABS -> Some 1 | I_ABS -> Some 1
| I_ADD -> None (* can fail for tez *)
| I_AMOUNT -> Some 0 | I_AMOUNT -> Some 0
| I_AND -> Some 2 | I_AND -> Some 2
| I_BALANCE -> Some 0 | I_BALANCE -> Some 0
@ -28,39 +59,24 @@ let arity : prim -> int option = function
| I_CDR -> Some 1 | I_CDR -> Some 1
| I_CHECK_SIGNATURE -> Some 3 | I_CHECK_SIGNATURE -> Some 3
| I_COMPARE -> Some 2 | I_COMPARE -> Some 2
| I_CONCAT -> None (* sometimes 1, sometimes 2 :( *)
| I_CONS -> Some 2 | I_CONS -> Some 2
| I_CREATE_ACCOUNT -> None (* effects, kind of *)
| I_CREATE_CONTRACT -> None (* effects, kind of *)
| I_IMPLICIT_ACCOUNT -> Some 1 | I_IMPLICIT_ACCOUNT -> Some 1
| I_DIP -> None
| I_DROP -> None
| I_DUP -> None
| I_EDIV -> Some 2 | I_EDIV -> Some 2
| I_EMPTY_MAP -> Some 0 | I_EMPTY_MAP -> Some 0
| I_EMPTY_SET -> Some 0 | I_EMPTY_SET -> Some 0
| I_EQ -> Some 1 | I_EQ -> Some 1
| I_EXEC -> None (* effects *)
| I_FAILWITH -> None
| I_GE -> Some 1 | I_GE -> Some 1
| I_GET -> Some 2 | I_GET -> Some 2
| I_GT -> Some 1 | I_GT -> Some 1
| I_HASH_KEY -> Some 1 | I_HASH_KEY -> Some 1
| I_IF -> None
| I_IF_CONS -> None
| I_IF_LEFT -> None
| I_IF_NONE -> None
| I_INT -> Some 1 | I_INT -> Some 1
| I_LAMBDA -> Some 0 | I_LAMBDA -> Some 0
| I_LE -> Some 1 | I_LE -> Some 1
| I_LEFT -> Some 1 | I_LEFT -> Some 1
| I_LOOP -> None
| I_LSL -> Some 1 | I_LSL -> Some 1
| I_LSR -> Some 1 | I_LSR -> Some 1
| I_LT -> Some 1 | I_LT -> Some 1
| I_MAP -> None
| I_MEM -> Some 2 | I_MEM -> Some 2
| I_MUL -> None (* can fail for tez *)
| I_NEG -> Some 1 | I_NEG -> Some 1
| I_NEQ -> Some 1 | I_NEQ -> Some 1
| I_NIL -> Some 0 | I_NIL -> Some 0
@ -78,26 +94,17 @@ let arity : prim -> int option = function
| I_SELF -> Some 0 | I_SELF -> Some 0
| I_SLICE -> Some 3 | I_SLICE -> Some 3
| I_STEPS_TO_QUOTA -> Some 0 | I_STEPS_TO_QUOTA -> Some 0
| I_SUB -> None (* can fail for tez *)
| I_SWAP -> None
| I_TRANSFER_TOKENS -> None (* effects, kind of *)
| I_SET_DELEGATE -> None (* effects, kind of *)
| I_UNIT -> Some 0 | I_UNIT -> Some 0
| I_UPDATE -> Some 3 | I_UPDATE -> Some 3
| I_XOR -> Some 2 | I_XOR -> Some 2
| I_ITER -> None
| I_LOOP_LEFT -> None
| I_ADDRESS -> Some 1 | I_ADDRESS -> Some 1
| I_CONTRACT -> Some 1 | I_CONTRACT -> Some 1
| I_ISNAT -> Some 1 | I_ISNAT -> Some 1
| I_CAST -> None
| I_RENAME -> None
| I_CHAIN_ID -> Some 0 | I_CHAIN_ID -> Some 0
| I_EMPTY_BIG_MAP -> Some 0 | I_EMPTY_BIG_MAP -> Some 0
| I_APPLY -> None | I_APPLY -> Some 2
| I_DIG -> None
| I_DUG -> None
(* not instructions *)
| K_parameter | K_parameter
| K_storage | K_storage
| K_code | K_code
@ -271,15 +278,15 @@ let rec iterate_optimizer (f : michelson -> bool * michelson) : michelson -> mic
let opt_drop2 : peep2 = function let opt_drop2 : peep2 = function
(* nullary_op ; DROP ↦ *) (* nullary_op ; DROP ↦ *)
| Prim (_, p, _, _), Prim (_, I_DROP, _, _) when is_nullary_op p -> Some [] | Prim (_, p, _, _), Prim (_, I_DROP, [], _) when is_nullary_op p -> Some []
(* DUP ; DROP ↦ *) (* DUP ; DROP ↦ *)
| Prim (_, I_DUP, _, _), Prim (_, I_DROP, _, _) -> Some [] | Prim (_, I_DUP, _, _), Prim (_, I_DROP, [], _) -> Some []
(* unary_op ; DROP ↦ DROP *) (* unary_op ; DROP ↦ DROP *)
| Prim (_, p, _, _), Prim (_, I_DROP, _, _) when is_unary_op p -> Some [i_drop] | Prim (_, p, _, _), Prim (_, I_DROP, [], _) when is_unary_op p -> Some [i_drop]
(* binary_op ; DROP ↦ DROP ; DROP *) (* binary_op ; DROP ↦ DROP ; DROP *)
| Prim (_, p, _, _), Prim (_, I_DROP, _, _) when is_binary_op p -> Some [i_drop; i_drop] | Prim (_, p, _, _), Prim (_, I_DROP, [], _) when is_binary_op p -> Some [i_drop; i_drop]
(* ternary_op ; DROP ↦ DROP ; DROP ; DROP *) (* ternary_op ; DROP ↦ DROP ; DROP ; DROP *)
| Prim (_, p, _, _), Prim (_, I_DROP, _, _) when is_ternary_op p -> Some [i_drop; i_drop; i_drop] | Prim (_, p, _, _), Prim (_, I_DROP, [], _) when is_ternary_op p -> Some [i_drop; i_drop; i_drop]
| _ -> None | _ -> None
let opt_drop4 : peep4 = function let opt_drop4 : peep4 = function
@ -287,7 +294,7 @@ let opt_drop4 : peep4 = function
| Prim (_, I_DUP, _, _), | Prim (_, I_DUP, _, _),
(Prim (_, p, _, _) as unary_op), (Prim (_, p, _, _) as unary_op),
Prim (_, I_SWAP, _, _), Prim (_, I_SWAP, _, _),
Prim (_, I_DROP, _, _) Prim (_, I_DROP, [], _)
when is_unary_op p -> when is_unary_op p ->
Some [unary_op] Some [unary_op]
| _ -> None | _ -> None
@ -301,19 +308,6 @@ let opt_dip1 : peep1 = function
(* DIP { unary_op } ↦ SWAP ; unary_op ; SWAP *) (* DIP { unary_op } ↦ SWAP ; unary_op ; SWAP *)
| Prim (_, I_DIP, [Seq (_, [(Prim (_, p, _, _) as unary_op)])], _) when is_unary_op p -> | Prim (_, I_DIP, [Seq (_, [(Prim (_, p, _, _) as unary_op)])], _) when is_unary_op p ->
Some [i_swap ; unary_op ; i_swap] Some [i_swap ; unary_op ; i_swap]
(* saves 5 bytes *)
(* DIP { DROP } ↦ SWAP ; DROP *)
| Prim (_, I_DIP, [Seq (_, [Prim (_, I_DROP, _, _)])], _) ->
Some [i_swap; i_drop]
(* saves 3 bytes *)
(* DIP { DROP ; DROP } ↦ SWAP ; DROP ; SWAP ; DROP *)
| Prim (_, I_DIP, [Seq (_, [Prim (_, I_DROP, _, _) ; Prim (_, I_DROP, _, _)])], _) ->
Some [i_swap; i_drop; i_swap; i_drop]
(* still saves 1 byte *)
(* DIP { DROP ; DROP ; DROP } ↦ SWAP ; DROP ; SWAP ; DROP ; SWAP ; DROP *)
| Prim (_, I_DIP, [Seq (_, [Prim (_, I_DROP, _, _) ; Prim (_, I_DROP, _, _) ; Prim (_, I_DROP, _, _)])], _) ->
Some [i_swap; i_drop; i_swap; i_drop; i_swap; i_drop]
(* after this, DIP { DROP ; ... } is smaller *)
| _ -> None | _ -> None
let opt_dip2 : peep2 = function let opt_dip2 : peep2 = function
@ -323,16 +317,16 @@ let opt_dip2 : peep2 = function
| Prim (_, I_DIP, [Seq (_, code1)], _), Prim (_, I_DIP, [Seq (_, code2)], _) -> | Prim (_, I_DIP, [Seq (_, code1)], _), Prim (_, I_DIP, [Seq (_, code2)], _) ->
Some [Prim (0, I_DIP, [Seq (0, code1 @ code2)], [])] Some [Prim (0, I_DIP, [Seq (0, code1 @ code2)], [])]
(* DIP { code } ; DROP ↦ DROP ; code *) (* DIP { code } ; DROP ↦ DROP ; code *)
| Prim (_, I_DIP, code, _), (Prim (_, I_DROP, _, _) as drop) -> | Prim (_, I_DIP, [Seq (_, code)], _), (Prim (_, I_DROP, [], _) as drop) ->
Some (drop :: code) Some (drop :: code)
(* nullary_op ; DIP { code } ↦ code ; nullary_op *) (* nullary_op ; DIP { code } ↦ code ; nullary_op *)
| (Prim (_, p, _, _) as nullary_op), Prim (_, I_DIP, [Seq (_, code)], _) when is_nullary_op p -> | (Prim (_, p, _, _) as nullary_op), Prim (_, I_DIP, [Seq (_, code)], _) when is_nullary_op p ->
Some (code @ [nullary_op]) Some (code @ [nullary_op])
(* DIP { code } ; unary_op ↦ unary_op ; DIP { code } *) (* DIP { code } ; unary_op ↦ unary_op ; DIP { code } *)
| (Prim (_, I_DIP, _, _) as dip), (Prim (_, p, _, _) as unary_op) when is_unary_op p -> | (Prim (_, I_DIP, [Seq _], _) as dip), (Prim (_, p, _, _) as unary_op) when is_unary_op p ->
Some [unary_op; dip] Some [unary_op; dip]
(* unary_op ; DIP { code } ↦ DIP { code } ; unary_op *) (* unary_op ; DIP { code } ↦ DIP { code } ; unary_op *)
(* | (Prim (_, p, _, _) as unary_op), (Prim (_, I_DIP, _, _) as dip) when is_unary_op p -> (* | (Prim (_, p, _, _) as unary_op), (Prim (_, I_DIP, [Seq _], _) as dip) when is_unary_op p ->
* Some [dip; unary_op] *) * Some [dip; unary_op] *)
| _ -> None | _ -> None
@ -378,6 +372,24 @@ let rec opt_tail_fail : michelson -> michelson =
Prim (l, p, List.map opt_tail_fail args, annot) Prim (l, p, List.map opt_tail_fail args, annot)
| x -> x | x -> x
let rec opt_combine_drops (x : michelson) : michelson =
let rec combine : michelson list -> michelson list = function
| [] -> []
| Prim (_, I_DROP, [], []) :: xs ->
let xs' = combine xs in
begin match xs' with
| [] -> [Prim (-1, I_DROP, [], [])]
| Prim (_, I_DROP, [], []) :: xs' -> Prim (-1, I_DROP, [Int (-1, Z.of_int 2)], []) :: xs'
| Prim (_, I_DROP, [Int (_, n)], []) :: xs' -> Prim (-1, I_DROP, [Int (-1, Z.of_int (1 + Z.to_int n))], []) :: xs'
| x' :: xs' -> Prim (-1, I_DROP, [], []) :: x' :: xs'
end
| x :: xs -> x :: combine xs in
match x with
| Seq (l, args) -> Seq (l, combine (List.map opt_combine_drops args))
| Prim (l, p, args, annot) ->
Prim (l, p, List.map opt_combine_drops args, annot)
| x -> x
let optimize : michelson -> michelson = let optimize : michelson -> michelson =
fun x -> fun x ->
let x = use_lambda_instr x in let x = use_lambda_instr x in
@ -391,4 +403,5 @@ let optimize : michelson -> michelson =
peephole @@ peep2 opt_swap2 ; peephole @@ peep2 opt_swap2 ;
] in ] in
let x = iterate_optimizer (sequence_optimizers optimizers) x in let x = iterate_optimizer (sequence_optimizers optimizers) x in
let x = opt_combine_drops x in
x x

View File

@ -58,6 +58,7 @@ let i_some = prim I_SOME
let i_lambda arg ret body = prim ~children:[arg;ret;body] I_LAMBDA let i_lambda arg ret body = prim ~children:[arg;ret;body] I_LAMBDA
let i_empty_map src dst = prim ~children:[src;dst] I_EMPTY_MAP let i_empty_map src dst = prim ~children:[src;dst] I_EMPTY_MAP
let i_drop = prim I_DROP let i_drop = prim I_DROP
let i_dropn n = prim I_DROP ~children:[int (Z.of_int n)]
let i_exec = prim I_EXEC let i_exec = prim I_EXEC
let i_if a b = prim ~children:[seq [a] ; seq[b]] I_IF let i_if a b = prim ~children:[seq [a] ; seq[b]] I_IF