//
// Preliminary Version of a points-to analysis for C
//

.type Var <: symbol
.type Obj <: symbol

.decl DirectFlow(v:Var,w:Var)
.input DirectFlow()
.decl Load(v:Var,w:Var)
.input Load()
.decl Store(v:Var,w:Var)
.input Store()
.decl ExtReturn(v:Var,w:Var)
.input ExtReturn()
.decl EscapePtr(v:Var)
.input EscapePtr()
.decl HeapAlloc(v:Var,o:Obj)
.input HeapAlloc()
.decl StackAlloc(v:Var,o:Obj)
.input StackAlloc()
.decl Function(v:Var,o:Obj)
.input Function()
.decl Global(v:Var,o:Obj)
.input Global()

.decl LptrVar (v:Var)
.decl IsPtr (v:Var,o:Obj)
.decl Memory(o1:Obj,o2:Obj)
.decl IsReachable(v:Var,o:Obj)
.decl CFormat(o:Obj)
.decl CPtrLoad(v1:Var,v2:Var)
.output CPtrLoad()
.decl CPtrStore(v1:Var,v2:Var)
.output CPtrStore()

LptrVar(v) :- StackAlloc(v,_).
LptrVar(v) :- HeapAlloc(v,_).
LptrVar(v) :- Load(_,v).
LptrVar(v) :- Store(_,v).
LptrVar(v) :- DirectFlow(v,w), LptrVar(w).
LptrVar(v) :- DirectFlow(w,v), LptrVar(w).


IsPtr(v,o) :- HeapAlloc(v,o).
IsPtr(v,o) :- StackAlloc(v,o).
IsPtr(dest,o) :- DirectFlow(src,dest), IsPtr(src,o).
IsPtr(dest,o) :- Load(dest, addr), IsPtr(addr, o1), Memory(o1,o).
IsPtr(v,o) :- ExtReturn(arg,v), IsReachable(arg,o).

IsPtr(v,o) :- Global(v, o).

Memory(o1,o2) :- Store(src,addr), IsPtr(src,o2), IsPtr(addr, o1).

IsReachable(v,o) :- IsPtr(v,o).
IsReachable(v,o) :- Memory(o1,o), IsReachable(v,o1).

CFormat(o) :- EscapePtr(v), IsReachable(v,o).


IsPtr(v,"ttt_obj") :- ExtReturn(_,v).

CFormat("ttt_obj") :- ExtReturn(_,_).
Memory("ttt_obj", "ttt_obj") :- ExtReturn(_,_).


CPtrLoad(dest, addr) :- Load(dest, addr), IsPtr(addr, o), CFormat(o), LptrVar(dest).
CPtrStore(src, addr) :- Store(src, addr), IsPtr(addr, o), CFormat(o), LptrVar(src).

CFormat(o) :- CPtrLoad(_,v), IsPtr(v,o).
CFormat(o) :- CPtrStore(_,v), IsPtr(v,o).

CFormat(o) :- Load(v,addr), IsPtr(addr,o), !LptrVar(v).
CFormat(o) :- Store(v,addr), IsPtr(addr,o), !LptrVar(v).


