Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 71 additions & 3 deletions datalog/analysis/boq-hpt.dl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
.type CodeName = Variable | Function

// External function (name, effectful)
.decl External(f:Function,effectful:number,ret:SimpleType)
.decl External(f:Function, effectful:number, ret:SimpleType)
.decl ExternalParam(f:Function, i:number, st:SimpleType)

// variable
Expand All @@ -15,6 +15,7 @@

// literal value
// example: result <- pure 1
// QUESTION: why the type?
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VariableSimpleType uses this.

.decl LitAssign(result:Variable, st:SimpleType, l:Literal)

// node value
Expand All @@ -38,6 +39,33 @@

// bind pattern
// example: node@(Ctag param0 param1) <- pure input_value
// QUESTION: what about: node @ (Ctag param0) <- f x
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just initial design. Main motivation was to be simple.

/* ANSWER:
NodePattern(node, Ctag, node)
NodeParameter(node, 0, param0)
Call(node, f)
CallArgument(node, 0, x)
*/
/* QUESTION: is the third field of NodePattern redundant?
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep AST simple, so that DL analysis is simple.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just use a transformation on the GRIN level.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add linter check.

Now it is only used in this when "moving" a variable:

node @ (Ctag param0) <- pure x
NodePattern(node, Ctag)
NodeParameter(node, 0, param0)
Move(node, x)

node @ (Ctag param0) <- f x
NodePattern(node, Ctag)
NodeParameter(node, 0, param0)
Call(node, f)
CallArgument(node, 0, x)

node @ (Ctag param0) <- pure (Ctag 5)
NodePattern(node, Ctag)
NodeParameter(node, 0, param0)
Node(node, Ctag)
NodeArgument(node, 0, "lit:int")
*/
.decl NodePattern(node:Variable, t:Tag, input_value:Variable)
.decl NodeParameter(node:Variable, i:number, parameter:Variable)

Expand All @@ -51,15 +79,22 @@
// alt_value@(Ctag param0 param1) -> basic_block_name arg0 arg1
.decl Case(case_result:Variable, scrutinee:Variable)
.decl Alt(case_result:Variable, alt_value:Variable, t:Tag)
// NOTE: first could be just alt_value since it's unique
// QUESTION: why the tag here again? Maybe just store it here, and let case_result be alt_value
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, we can add redundant fields to avoid additional JOINs in DL clauses. In this specific instance, the tag field can be omitted since that information is always available when using this AltParameter relation.

.decl AltParameter(case_result:Variable, t:Tag, i:number, parameter:Variable)
.decl AltLiteral(case_result:Variable, alt_value:Variable, l:Literal)
.decl AltDefault(case_result:Variable, alt_value:Variable)

// pure a.k.a. return value
// example: pure value
// QUESTION: shouldn't this be the return value of a function?
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last instruction of a bind sequence of the form pure <var_name>.

// QUESTION: can the return value of a function be only of form: pure <var_name> ?
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just use a transformation on the GRIN level.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add linter check.

.decl ReturnValue(n:CodeName, value:Variable)

// instruction ordering
/* QUESTION: What about f x = pure x
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solve this on DL level.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is particularly nasty since the last instruction of the function is of form pure <var>, but it has no name.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just found out that this type of function definition is not allowed in mini-grin. That being said, this is still an issue for the extended GRIN AST.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is handled by the current relations:

What is the first instruction?
*/
.decl FirstInst(n:CodeName, result:Variable)
.decl NextInst(prev:Variable, next:Variable)

Expand Down Expand Up @@ -93,6 +128,11 @@
.decl CodeNameInst(n:CodeName, v:Variable)
.output CodeNameInst(delimiter=",")

/* QUESTION: Do we really need NextInst?
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be a one-to-one mapping between the GRIN AST and the Datalog model of the AST. This is why this relation is needed.

Currently, NextInst is only used to define CodeNameInst.
Just a random thought, but maybe instruction order isn't even important,
only the dataflow is. Dataflow is already defined by the other relations.
*/
CodeNameInst(n, v) :-
FirstInst(n, v).
CodeNameInst(n, v) :-
Expand Down Expand Up @@ -133,6 +173,8 @@ VarPointsTo(v,t) :-
VarPointsTo(v0, t),
ReachableInst(r).

// QUESTION: How about the name CreatedBy?
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about Origin?

// It matches the previous terminology, and is a nice name for a binary relation.
// Value Computation
.decl Value(v:Variable, value:Variable)
.output Value(delimiter=",")
Expand All @@ -149,6 +191,12 @@ Heap(heap_orig, sv) :-
Heap(heap_orig, _),
SharedLocation(heap).

// QUESTION: don't we need this as well?
// ANSWER: probably not, if we are not concerned with aliases (we need only the unique locations)
// Heap(heap, sv) :-
// Update(_, heap, sv),
// SharedLocation(heap).

Value(n,n) :-
LitAssign(n,_,_).

Expand All @@ -165,6 +213,17 @@ Value(v,v) :-
External(f,_,_),
Call(v,f).

/* QUESTION: What about the general Move case?
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaphs a valid bug. Fix it.

It seems to me that the Value relation doesn't see through multiple moves.
main =
m1 <- pure 5
n1.0 <- pure (CInt m1)
n1.1 <- pure n1.0
n1.2 <- pure n1.1
pure ()

What is the Value of n1.2?
*/
Value(v, n) :-
Node(n, _),
Move(v, n).
Expand Down Expand Up @@ -203,7 +262,7 @@ Value(param, argval) :-
NodeArgument(nval, i, arg),
Value(arg, argval).

// Alt value when matched on tag.
// Alt value when matched on literal.
Value(alt_val, scrut_val) :-
Case(case_result, scrut),
AltLiteral(case_result, alt_val, _),
Expand All @@ -214,6 +273,7 @@ Value(alt_val, scrut_val) :-
Case(case_result, scrut),
Alt(case_result, alt_val, tag),
Value(scrut, scrut_val),
// NOTE: this just checks whether the alternative is possible
Node(scrut_val, tag).

// Value of alt parameter when matched on tag
Expand All @@ -225,6 +285,9 @@ Value(parameter, val) :-
Node(scrut_val,tag),
NodeArgument(scrut_val,i,val).

// NOTE: every alternative should be related to its return value (via ReturnValue)
// QUESTION: alt_values (altNames) might have different meaning based on the analysis, would that be a problem?
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just create a separate relation for that. Not a problem.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a standalone variable (as it was in the abstract machine), but just a name.

// QUESTION: shouldn't we check for dead alternatives?
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this can be refined. However, check whether it is already handled.

// Result of case/alt when matched on a node.
Value(case_result, val) :-
Case(case_result, _),
Expand All @@ -239,6 +302,8 @@ Value(case_result, val) :-
ReturnValue(alt_value, v),
Value(v, val).

// QUESTION: could implement liveness check here as well? (ignore alt when impossible)
// ANSWER: would have to collect all tags of all possible origins of the scrutinee, then check whether all are covered
// Result of case/alt when matched on the default alternative.
Value(case_result, val) :-
Case(case_result, _),
Expand All @@ -263,6 +328,7 @@ VariableSimpleType(n,st) :- LitAssign(n,st,_).
VariableSimpleType(n,"Unit") :- Update(n,_,_).
VariableSimpleType(n,st) :- External(f,_,st), Call(n,f).
VariableSimpleType(n,st) :- ExternalParam(f,i,st), Call(r,f), CallArgument(r,i,n).
// NOTE: that's nice!
VariableSimpleType(n,st) :- Value(n,r), VariableSimpleType(r,st).

.output VariableNodeParamType(delimiter=",")
Expand All @@ -276,6 +342,7 @@ VariableNodeParamType(n,t,i,ty)
.output VariableNodeTag(delimiter=",")
VariableNodeTag(n,t) :- Value(n,r), Node(r,t).

// QUESTION: is this basically Value constrained by AbstractLocation? (i.e. all variables who have pointer producers?)
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably yes.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a helper to convert the analysis result to TypeEnv?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Always try to decompose rules into separate relations.

.output VariableAbstractLocation(delimiter=",")
VariableAbstractLocation(n,n) :- AbstractLocation(n).
VariableAbstractLocation(n,v) :- Value(n,v), AbstractLocation(v).
Expand Down Expand Up @@ -307,7 +374,7 @@ SharedLocation(l) :-

// For non-linear variables
// A location may only become shared if it is a possible value of a nonlinear variable.
//
// NOTE: linear => not shared ~ nonlinear <= shared (aggrees with the above statement)

.decl NonLinearVar(v:Variable)
.output NonLinearVar(delimiter=",")
Expand All @@ -319,6 +386,7 @@ SharedLocation(l) :-
// NodeParameter NP -- - - -- xx
// ReturnValue RV -- - - -- --

// NOTE: can't we use $ for this somehow?
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably can investigate this.

NonLinearVar(n) :- CallArgument(f,_,n), CallArgument(g,_,n), !(f=g).
NonLinearVar(n) :- CallArgument(_,i,n), CallArgument(_,j,n), !(i=j).
NonLinearVar(n) :- CallArgument(_,_,n), Move(_,n).
Expand Down
7 changes: 6 additions & 1 deletion datalog/analysis/dead-code.dl
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@
.input AltParameter
.input AltLiteral
.input AltDefault
.input AltArgument
.input ReturnValue
.input FirstInst
.input NextInst
Expand All @@ -105,6 +104,7 @@

.output DeadVariable(delimiter=",")
.output DeadParameter(delimiter=",")
.output Effectful(delimiter=",")
// .output UsedVariable(delimiter=",")

UsedVariable(n) :- Move(_,n).
Expand Down Expand Up @@ -140,13 +140,18 @@ ReachableCode(n) :-


.decl EffectfulFunction(f:Function)
.output EffectfulFunction(delimiter=",")

// QUESTION: Why do we need f to have parameters?
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably meant that f is function. Use a relation for that?

EffectfulFunction(f)
:- FunctionParameter(f,_,_)
, CodeNameInst(f,n)
, Effectful(n).

// QUESTION: CallArgument(n,_,_) means that it is not a nullary function? Why do we need this restriction?
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably meant that n is the result of a function call.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably redundant?

Effectful(n) :- External(f,1), Call(n, f), CallArgument(n,_,_).
// QUESTION: Is Update really effectful? Didn't we settle on a conclusion that Updates can only be inside evals
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is faithful to the Boq PhD, but since then we changed the semantics of "effectful". In the original PhD everything that returned () was effectful, but now only externals that are marked effectful are effectful.

// which means deleting it only effects operational-, but not the denotational semantics?
Effectful(n) :- Update(n,_,_).
Effectful(n) :- EffectfulFunction(f), Call(n,f), CallArgument(n,_,_).

Expand Down
2 changes: 2 additions & 0 deletions grin/src/Grin/Datalog.hs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ convertProgram exp = do
seqAlg :: [G.ExpF (G.Exp, DL ()) -> DL ()] -> G.ExpF (G.Exp, DL ()) -> DL ()
seqAlg algs exp = mapM_ ($ exp) algs

-- QUESTION: What is this? It doesn't interact with the AST and it has no side-effects.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was just an experiment to define algebra compositions.

recurseAlg :: G.ExpF (G.Exp, DL ()) -> DL ()
recurseAlg = mapM_ snd

Expand Down Expand Up @@ -298,6 +299,7 @@ emitAlg = \case
-- call_result <- f value0 value1
-- .decl Call(call_result:Variable, f:Function)
-- .decl CallArgument(call_result:Variable, i:number, value:Variable)
-- QUESTION: Why is this AST invalid? We can express this using the current model of the DL AST.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, see the discussion above.

G.EBindF (G.SApp{},_) (G.BNodePat{}) _ -> error "Invalid AST."
G.EBindF (G.SApp fun args, lhs) (G.BVar res) (_, rhs) -> do
emit $ (Call { call_result = Variable res, f = Function fun })
Expand Down