Compositional C11 Program Transformation Mark Batty - Mike Dodds - Alexey Gotsman Imperial Concurrency Workshop, July 2015 @miike
Overview The C11 model is (arguably) broken: we omit problem features, most importantly no RLX. • Context: relaxed memory, axiomatic semantics, fragment of C11 / C++11. • Immediate aim: program transformation, eg compiler optimisations. • Approach: summarise context interactions using a set of histories (denotational- ish ). • Under construction!
Overview 1. Objective: compositional transformation 2. C11 semantics primer 3. Defining execution histories 4. Cutting down contexts
Fragments and Contexts - whole program C J C K - semantics (defined by a set of executions) + C ( − ) C ( P ) = P Whole Context Program program (program with hole) fragment
Motivation: Compiler Optimisations - replace one fragment with another P 1 P 2 r=read(x); r=read(x); P 1 : P 2 : r=read(x); Assume operations are release-acquire unless otherwise mentioned Is this a sound transformation on C11?
Motivation: Compiler Optimisations - replace one fragment with another P 1 P 2 Soundness: ∀ C. ∀ X 2 ∈ J C ( P 2 ) K . ∃ X 1 ∈ J C ( P 1 ) K . obsv ( X 2 ) = obsv ( X 1 ) equivalent all executions of executions observed contexts transformed of prior behaviour program program
Approach J P K d - summarises of all possible interactions (…a kind of denotation ) Adequacy: J P 2 K d ⊆ J P 1 K d = ⇒ ∀ C. ∀ X 2 ∈ J C ( P 2 ) K . ∃ X 1 ∈ J C ( P 1 ) K . obsv ( X 2 ) = obsv ( X 1 ) Thus: J P 2 K d ⊆ J P 1 K d = ⇒ P 1 P 2 is sound
Approach We’d also like finiteness: J P K d P is loop-free code is finite ⇒ = (…possibly with symbolic values?) This would support e.g. automated checking
1. Objective: compositional transformation 2. C11 semantics primer 3. Defining execution histories 4. Cutting down contexts
C11 concurrency semantics Executions: multiple partial orders on memory actions. h A , rf , hb , mo i 2 J C K memory read- happens per-location actions writes before coherence
C11 concurrency semantics (II) C11 semantics is very non-compositional: 1. Generate whole-program execution candidates . 2. Filter on the basis of validity axioms. Validity forbids eg: rf write(x,v) write(x,v’) read(x,v) hb hb forbidden!
Observable behaviour thread 1 thread 2 write(y,1) rf? write(y,2) P write(x,5) read(y,1)
Observable behaviour thread 1 thread 2 write(y,1) hb rf? write(y,2) hb P rf write(x,5) read(x) hb hb read(y,1)
Observable behaviour thread 1 thread 2 write(y,1) hb write(y,2) rf? hb P write(x,5) read(x) hb read(y,1)
C11 Challenges 1. Semantics is whole-program and axiomatic. 2. No notion of a global state 3. Unclear when orders can be observed
1. Objective: compositional transformation 2. C11 semantics primer 3. Defining execution histories 4. Cutting down contexts
Inspiration Idea: treat code transformation as library abstraction
Intuition C ( P ) execution
Intuition C ( − ) P execution
Intuition C ( − ) ‘History’ P Projection of hb relation to interface actions execution
Interface actions call read(x,7) write(y,4) return
Interface actions read(x,9) read(z,8) call read(y,9) write(z,8) read(x,7) read(z,7) write(y,7) write(y,4) write(y,8) write(x,5) return History includes context reads / writes to locations accessed in code block
History In history call return
History call Not in history rf write(x,5) read(x,5) In history return Don’t record internal actions in history
History call write(x,5) return Don’t record internal actions in history
History call In history write(x,5) read(x,5) rf return
History call read(x,5) return
History call rf write(x) read(x) write(y) read(y) rf return Some internal order matters!
History call write(x) read(y) return Some internal order matters!
History call In history as read(x) write(x) a deny rf Prohibits a write(x) hb order read(x) rf return Some internal order matters!
History call read(x) read(x) return Some internal order matters!
Building J P K d hb projection forbidden hb Interface actions (‘ guarantee ’) (‘ deny ’) History : P ( Action ) × P ( Action × Action ) × P ( Action × Action ) J P K d : P ( History ) J P K d To build : J P K 1. Generate executions in for a limited collection of contexts. 2. Extract the history from each execution.
Validating the example read(x); read(x); P 1 : P 2 : read(x); J P 2 K d ⊆ J P 1 K d Show : write(x); rf call P 2 P 1 rf read(x); read(x); In history return
1. Objective: compositional transformation 2. C11 semantics primer 3. Defining execution histories 4. Cutting down contexts
Which contexts matter? ∀ C. ∀ X 2 ∈ J C ( P 2 ) K . ∃ X 1 ∈ J C ( P 1 ) K . obsv ( X 2 ) = obsv ( X 1 ) all contexts?
Which contexts matter? read(x,9) read(z,8) call read(y,9) write(z,8) read(x,7) read(z,7) write(y,7) write(y,4) write(y,8) return write(x,5) Drop non-interface context actions
Which contexts matter? call read(x) rf write(x) read(x) rf return Drop duplicate interface reads
Which contexts matter? call write(x) rf write(x) read(x) return Drop interface reads from interface writes
Which contexts matter? call write(x) mo write(x) mo write(x) read(x) mo return rf write(x) Drop interface writes with siblings in modification-order
Which contexts matter? ∆ “only interface actions” cut ( X ) ⇐ ⇒ ∧ “only rf-distinguished reads” ∧ “only mo-distinguished writes” P is loop-free code { X ∈ J P K | cut ( X ) } is finite ⇒ = J P K d is finite ⇒ =
Current status • Proved adequacy for a fragment of C11. (release-acquire, NA, working on SC) • Validated a collection of optimisations. • Finiteness theorem (mostly done). • Full abstraction (in progress). • Checking tool (planning stages) .
Towards a compositional semantics? Would like to define parallel composition: def J P 1 k P 2 K d J P 1 K d � J P 2 K d = Would (maybe) like full abstraction: ∀ C. ∀ X 2 ∈ J C ( P 2 ) K . ∃ X 1 ∈ J C ( P 1 ) K . obsv ( X 2 ) = obsv ( X 1 ) = J P 2 K d ⊆ J P 1 K d ⇒
Recommend
More recommend