-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Branches in atomic sections, and simplified atomic syntax #142
Conversation
Instead of having two atomic syntaxes: ``` <x = y++>; // single atomic action <{ x = y; y = y + 1; }>; // multiple atomic actions ``` We now have a single syntax: ``` <| x = y++; |> // single atomic action <| x = y; y = y + 1; |> // multiple atomic actions ``` Note that the new syntax behaves exactly like a block: it requires semicolons to terminate inner actions, but has no semicolon at the end. This is in preparation for making atomic syntax richer.
This still needs two more changes: 1) Making microcode conditionals sequentially composed instead of parallel composed; 2) Exposing the syntax.
It probably fails 99.9% of tests at the moment. Will pick up after 日本語の勉強.
Re encoding CAS, can we write this?
|
...but in general, it'd be sensible to be able to write an arbitrary expression to a local var. Is there a technical reason we can't do this? |
Currently the rhs of an assignment to a local variable has to be a shared lvalue, so that doesn't work. This is an arbitrary restriction I put in place to make starling atomics have a clear load/store model, and I'm becoming convinced it needs to go.
…Sent from my iPhone
On 16 Feb 2017, at 16:21, Mike Dodds ***@***.***> wrote:
Re encoding CAS, can we write this?
<| test = ! %{ [|x|].lock };
if (test) {
%{ [|x|].lock := true };
} |>
―
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub, or mute the thread.
|
@septract aside from the future work, is there anything else suspect about this? It's a fairly large and boring PRQ I'm afraid. |
Haven't looked through the code yet. The changes all sound entirely
sensible.
…On 17 February 2017 at 15:01, Matt Windsor ***@***.***> wrote:
@septract <https://github.com/septract> aside from the future work, is
there anything else suspect about this? It's a fairly large and boring PRQ
I'm afraid.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#142 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AANd9mc8xD9Y98fPy5642S2dXxbNBlv8ks5rdbZmgaJpZM4MDAS7>
.
|
Could we look through the code together at some point? |
On 20 Feb 2017, at 14:45, Mike Dodds ***@***.***> wrote:
Could we look through the code together at some point?
Sorry for late reply. Sure, this would be good. When would be convenient?
|
I'm now tracking the separate problem of overly strict assignment restrictions with #147. |
| ACond of | ||
cond : Expression | ||
* trueBranch : Atomic list | ||
* falseBranch : (Atomic list) option |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just adding if (c) { … } else { … }
and if (c) { … }
to the AST.
/// <summary> | ||
/// Hidden building-blocks for AST pretty-printers. | ||
/// </summary> | ||
module private Helpers = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a F# feature I didn't realise existed until recently. It feels like we should have made more use of this throughout the code!
<+> (maybe | ||
Nop | ||
(fun e -> syntaxStr "else" <+> printBlock pLeg e) | ||
elseLeg) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Abstracted this out because it accounts both for atomic and non-atomic conditionals.
@@ -290,7 +331,7 @@ module Pretty = | |||
/// <param name="s">The symbolic to print.</param> | |||
/// <returns> | |||
/// The <see cref="Doc"/> resulting from printing <paramref name="s"/>. | |||
/// </returns> | |||
/// </returns> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Space error
braced (ivsep (List.map (pCmd >> Indent) c)) | ||
| ACond (cond = c; trueBranch = t; falseBranch = f) -> | ||
Helpers.printITE printExpression printAtomic c t f | ||
and printAtomic (x : Atomic) : Doc = printAtomic' x.Node |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just adding conditionals to the printer. This now needs to be recursive, because conditionals can contain atomics.
printBlock printCommand f ]) | ||
fo) ] | ||
| Command'.If(c, t, f) -> | ||
Helpers.printITE printExpression printCommand c t f |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using the new abstraction.
@@ -84,7 +89,7 @@ module Types = | |||
| /// <summary> | |||
/// The given microcode command cannot be expressed in Grasshopper. | |||
/// </summary> | |||
CommandNotImplemented of cmd : Microcode<CTyped<MarkedVar>, Sym<MarkedVar>> list | |||
CommandNotImplemented of cmd : Microcode<CTyped<MarkedVar>, Sym<MarkedVar>> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above, things that used to be ||-composed lists of microcode are now just flattened into single microcode instructions
String "if" | ||
<+> parened (printBoolExprG (printSymGrass printGrassVar) c) | ||
<+> printBlock t | ||
<+> (if f.IsEmpty then Nop else (String "else" <+> printBlock f)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As well as adding Branch
, rearrange this because not every command now needs withSemi
.
id) | ||
(traverseMicrocode | ||
collectVars | ||
(tliftOverExpr collectSymVars)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Going from list list to list.
[ printMicrocode | ||
(printCTyped printMarkedVar) | ||
(printSym printMarkedVar) | ||
cmd ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing one level of list
@@ -407,75 +417,75 @@ let findTermVars (term : Backends.Z3.Types.ZTerm) | |||
/// <returns> | |||
/// A Chessie result, containing a list of Grasshopper commands. | |||
/// </returns> | |||
let grassMicrocode (routine : Microcode<CTyped<MarkedVar>, Sym<MarkedVar>> list list) | |||
let rec grassMicrocode (routine : Microcode<CTyped<MarkedVar>, Sym<MarkedVar>> list) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Going from list list to list, and adding branches introduces recursion.
fail | ||
(CommandNotImplemented | ||
(cmd = ent, | ||
why = "Cannot encode commands with inner conditionals.")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We now can encode inner conditionals, see line 434 of the new version.
lift3 (fun c' t' f' -> [ Branch (c', t', f') ]) | ||
(grassBool c) | ||
(grassMicrocode t) | ||
(grassMicrocode f) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Branches are new, but distribute.
ok [] | ||
(* We can only translate pure assignments and fully spatial | ||
(symbolic) assignments. *) | ||
| Microcode.Assign (x, Some (Int (_, IVar (Sym s)))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This stuff, I think, has mainly just moved and re-indented.
@@ -805,8 +810,29 @@ and modelBoolExpr | |||
| Eq -> mkEq | |||
| Neq -> mkNeq | |||
| _ -> failwith "unreachable[modelBoolExpr::AnyIn]" | |||
(* If at least one of the operands is a symbol, we need to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This new code just tries to make sure that, if one side of an equality/nonequality is a symbol, we try work out its type by modelling the other side first.
This is unrelated to atomic conditionals, I think it's wormed its way into here due to some hacking I was doing around CAV.
| SymAtomic sym -> | ||
// TODO(CaptainHayashi): split out. | ||
let symMR = | ||
(tryMapSym | ||
(wrapMessages BadExpr (modelExpr ctx.Env Full id)) | ||
sym) | ||
lift SymC symMR | ||
| ACond (cond = c; trueBranch = t; falseBranch = f) -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New code to allow modelling of atomic conditionals.
@@ -585,6 +585,10 @@ module Graph = | |||
| // TODO(CaptainHayashi): is this correct? | |||
Intrinsic (Havoc v) -> typedVarIsThreadLocal v | |||
| Stored { Args = ps } -> Seq.forall isLocalArg ps | |||
| PrimBranch (trueBranch = t; falseBranch = f) -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Locality, I think, just distributes through branches.
/// <summary> | ||
/// Parser for items in a pair of matching brackets. | ||
/// Automatically parses any whitespace after `bra`, and before `ket`. | ||
/// </summary> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lots of boring changes to top-level comments here, but there are important parser changes coming.
/// <summary> | ||
/// Parser for items in <c><|atomic braces|></c>. | ||
/// </summary> | ||
let inAtomicBraces p = inBrackets "<|" "|>" p |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The brackets have changed!
@@ -90,6 +103,10 @@ let parseView, parseViewRef = | |||
let parseViewSignature, parseViewSignatureRef = | |||
createParserForwardedToRef<ViewSignature, unit> () | |||
|
|||
/// Parser for atomic sets. | |||
let parseAtomic, parseAtomicRef = | |||
createParserForwardedToRef<Atomic, unit> () |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needed because atomics now parse recursively.
.>>? notFollowedBy (anyOf ";+-") | ||
(* A binary operator cannot ever be followed by + or -. | ||
This check removes ambiguity between + and ++, and - and --. *) | ||
.>>? notFollowedBy (anyOf "+-") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changing from < >
to <| |>
means we lose the parser ambiguity formerly induced by < foo = x > 3 >;
, so we can simplify this.
(inBraces pLeg) | ||
(opt (pstring "else" >>. ws >>. inBraces pLeg)) | ||
ctor | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Abstract out the parser logic for both atomic and non-atomic conditionals.
<|> | ||
// ...or an atomic{} block. | ||
(inBraces (many (parseAtomic .>> wsSemi .>> ws)))) | ||
inAtomicBraces (many1 (parseAtomic .>> ws)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new syntax knocks both of the old cases into one.
parseAssume | ||
parseCAS | ||
parseFetchOrPostfix ] | ||
parseIfLike (many1 (parseAtomic .>> ws)) (curry3 ACond) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Atomic conditionals are now a possibility here.
(* | ||
* Views. | ||
*) | ||
|
||
/// Parses a conditional view. | ||
let parseIfView = | ||
// TODO: use parseIflike. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This TODO is optional, really. Changing to this would make view conditionals look like
{| if (x) { y } else { z} |}
which is ugly but consistent.
@@ -540,7 +558,7 @@ let parsePrimSet = | |||
2 is easier to spot, so we try it first. *) | |||
let parseAtomicFirstPrimSet = | |||
pipe2 | |||
(parseAtomicSet .>> wsSemi .>> ws) | |||
(parseAtomicSet .>> ws) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We no longer require a ;
after an atomic block.
@@ -776,6 +776,17 @@ let pushVar (ctx : TraversalContext<'Var>) (v : CTyped<'Var>) | |||
| c -> fail (ContextMismatch ("vars context", stripVars c)) | |||
|
|||
/// <summary> | |||
/// As <see cref="pushVar"/>, but does not crash on invalid context. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was borne out of frustration mainly, and just means I can get away with not doing a lot of traversal mangling to add and remove contexts just so pushVar
works.
@septract I've tried annotating this code with top-level explanations, mainly as cues for myself when we get to reviewing this :) |
Also, the failing Travis build is due to travis-ci/travis-ci#7401 |
@septract it doesn't look like Travis is going to build this reliably any time soon. I'd recommend pulling and testing locally. |
This looks okay to me, although I haven't grokked the details. |
This pull request contains three large changes to Starling's syntax and semantics:
Simplify atomic syntax
Previously, a Starling atomic could be written as
<cmd>;
if it was one command, or<{cmd1; cmd2; cmdN;}>;
if it contained more than one.This seemed somewhat wasteful and confusing, and mainly happened because the second was an afterthought. This pull request removes the first form and slightly changes the second form, so that atomic commands are now always in the form
All of the
Pass
,Fail
,PassGH
, andFailGH
examples have been rewritten. (None of theWIP
ones have, yet.)Allow branches in atomic sections
Atomic blocks can now contain the form
which atomically evaluates the conditional and then the appropriate atomic block.
This allows us to write a pure-Starling CAS inline. For example, the
CAS
inExamples/Pass/spinLock.cvf
could be written as:We can also almost write a heap CAS. This does the same thing as
CAS_to_true
inExamples/PassGH/spinLock.cvf
, but in a slightly convoluted way (see below caveats):Rewrite microcode translation pipeline
To allow 2) to go through, the bit of Starling that converts
Microcode
into marked, normalised microcode or Boolean relations needed a significant overhaul. This is because previously it assumed any microcode instructions inside a branch (or, indeed, inside a single stored command!) were disjoint, and thus could share the sameIntermediate
level.Summary of the changes:
Future work
if (x) { y } else { z }
for consistency and language simplicity, but this would make views somewhat less readable.