You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
84 lines
3.0 KiB
84 lines
3.0 KiB
6 years ago
|
(*
|
||
|
* Copyright (c) 2018-present, Facebook, Inc.
|
||
|
*
|
||
|
* This source code is licensed under the MIT license found in the
|
||
|
* LICENSE file in the root directory of this source tree.
|
||
|
*)
|
||
|
|
||
|
open! IStd
|
||
|
module F = Format
|
||
|
module L = Logging
|
||
|
module Dead = AbstractDomain.InvertedSet (Var)
|
||
|
module Reverse = AbstractDomain.FiniteMultiMap (Var) (Var)
|
||
|
|
||
|
type t =
|
||
|
{ resolve: IdAccessPathMapDomain.t
|
||
|
; reverse: Reverse.t
|
||
|
(** there is a [x -> y] mapping in reverse for each variable [y] appearing in [resolve x] *)
|
||
|
; dead: Dead.t }
|
||
|
|
||
|
let empty = {resolve= IdAccessPathMapDomain.empty; reverse= Reverse.empty; dead= Dead.empty}
|
||
|
|
||
|
let add id ap {resolve; reverse; dead} =
|
||
|
let resolve = IdAccessPathMapDomain.add id ap resolve in
|
||
|
let reverse =
|
||
|
HilExp.AccessExpression.fold_vars ap ~init:reverse ~f:(fun acc var_in_ap ->
|
||
|
Reverse.add var_in_ap id acc )
|
||
|
in
|
||
|
let dead = Dead.remove id dead in
|
||
|
{resolve; reverse; dead}
|
||
|
|
||
|
|
||
|
let exit_scope id bindings =
|
||
|
let {resolve; reverse; dead} = bindings in
|
||
|
match (Reverse.mem id reverse, IdAccessPathMapDomain.find_opt id resolve) with
|
||
|
| true, None ->
|
||
|
let dead = Dead.add id dead in
|
||
|
({resolve; reverse; dead}, [])
|
||
|
| true, Some _ ->
|
||
|
L.(die InternalError) "Variable appearing on both sides of bindings"
|
||
|
| false, None ->
|
||
|
(bindings, [id])
|
||
|
| false, Some ap ->
|
||
|
let resolve = IdAccessPathMapDomain.remove id resolve in
|
||
|
let reverse, vars, dead =
|
||
|
HilExp.AccessExpression.fold_vars ap ~init:(reverse, [], dead)
|
||
|
~f:(fun (reverse, vars, dead) var_in_ap ->
|
||
|
let reverse = Reverse.remove var_in_ap id reverse in
|
||
|
if (not (Reverse.mem var_in_ap reverse)) && Dead.mem var_in_ap dead then
|
||
|
(reverse, var_in_ap :: vars, Dead.remove var_in_ap dead)
|
||
|
else (reverse, vars, dead) )
|
||
|
in
|
||
|
({resolve; reverse; dead}, vars)
|
||
|
|
||
|
|
||
|
let resolve {resolve} id = IdAccessPathMapDomain.find_opt id resolve
|
||
|
|
||
|
let fold {resolve} ~init ~f = IdAccessPathMapDomain.fold f resolve init
|
||
|
|
||
|
let pp f {resolve; reverse; dead} =
|
||
|
F.fprintf f "{@[<v1> resolve=@[<hv>%a@];@;reverse=@[<hv>%a@];@;dead=@[<hv>%a@];@]}"
|
||
|
IdAccessPathMapDomain.pp resolve Reverse.pp reverse Dead.pp dead
|
||
|
|
||
|
|
||
|
let ( <= ) ~lhs ~rhs = IdAccessPathMapDomain.( <= ) ~lhs:lhs.resolve ~rhs:rhs.resolve
|
||
|
|
||
|
let join bindings1 bindings2 =
|
||
|
if phys_equal bindings1 bindings2 then bindings1
|
||
|
else
|
||
|
let {resolve= resolve1; reverse= reverse1; dead= dead1} = bindings1 in
|
||
|
let {resolve= resolve2; reverse= reverse2; dead= dead2} = bindings2 in
|
||
|
{ resolve= IdAccessPathMapDomain.join resolve1 resolve2
|
||
|
; reverse= Reverse.join reverse1 reverse2
|
||
|
; dead= Dead.join dead1 dead2 }
|
||
|
|
||
|
|
||
|
let widen ~prev ~next ~num_iters =
|
||
|
if phys_equal prev next then prev
|
||
|
else
|
||
|
let {resolve= resolve1; reverse= reverse1; dead= dead1} = prev in
|
||
|
let {resolve= resolve2; reverse= reverse2; dead= dead2} = next in
|
||
|
{ resolve= IdAccessPathMapDomain.widen ~prev:resolve1 ~next:resolve2 ~num_iters
|
||
|
; reverse= Reverse.widen ~prev:reverse1 ~next:reverse2 ~num_iters
|
||
|
; dead= Dead.widen ~prev:dead1 ~next:dead2 ~num_iters }
|