Mark Batty - Mike Dodds - Alexey Gotsman
Compositional C11 Program Transformation
Imperial Concurrency Workshop, July 2015
@miike
Compositional C11 Program Transformation Mark Batty - Mike - - PowerPoint PPT Presentation
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.
Mark Batty - Mike Dodds - Alexey Gotsman
Imperial Concurrency Workshop, July 2015
@miike
fragment of C11 / C++11.
compiler optimisations.
a set of histories (denotational-ish).
The C11 model is (arguably) broken: we omit problem features, most importantly no RLX.
C(−) Context (program with hole) P Program fragment + = C(P) Whole program C
JCK
P1 P2
Is this a sound transformation on C11?
Assume operations are release-acquire unless
P2 : P1 :
P1 P2
all contexts executions of transformed program executions
program equivalent
behaviour Soundness: ∀C. ∀X2 ∈ JC(P2)K. ∃X1 ∈ JC(P1)K. obsv(X2) = obsv(X1)
(…a kind of denotation) JPKd Adequacy: JP2Kd ⊆ JP1Kd = ⇒ ∀C. ∀X2 ∈ JC(P2)K. ∃X1 ∈ JC(P1)K. obsv(X2) = obsv(X1) Thus: JP2Kd ⊆ JP1Kd = ⇒ P1 P2 is sound
We’d also like finiteness: P is loop-free code = ⇒ is finite
(…possibly with symbolic values?)
JPKd This would support e.g. automated checking
Executions: multiple partial orders on memory actions. memory actions read- writes hA, rf, hb, moi 2 JCK happens before per-location coherence
C11 semantics is very non-compositional:
Validity forbids eg: write(x,v) write(x,v’) read(x,v)
hb hb rf
forbidden!
P
write(x,5) write(y,2) write(y,1) read(y,1)
rf?
thread 1 thread 2
P
write(x,5) write(y,2) read(x) write(y,1) read(y,1)
hb hb hb rf rf? hb
thread 1 thread 2
P
write(x,5) write(y,2) write(y,1) read(y,1)
hb hb hb rf?
read(x)
thread 1 thread 2
Idea: treat code transformation as library abstraction
C(P)
execution
execution
P C(−)
execution
P C(−)
‘History’ Projection of hb relation to interface actions
return call
read(x,7) write(y,4)
return call
History includes context reads / writes to locations accessed in code block
write(x,5) read(x,7) write(y,4) write(y,7) read(y,9) read(x,9) write(y,8) read(z,7) write(z,8) read(z,8)
return call
In history
return call
In history Don’t record internal actions in history
read(x,5) write(x,5)
rf
Not in history
return call
write(x,5)
Don’t record internal actions in history
return call
In history
write(x,5) read(x,5)
rf
return call
read(x,5)
return call
read(x) read(y)
rf
write(y) write(x)
rf
Some internal order matters!
return call
read(y) write(x)
Some internal order matters!
return call
write(x) read(x)
rf
write(x) read(x)
rf
In history as a deny Prohibits a hb order Some internal order matters!
return call
read(x) read(x)
Some internal order matters!
To build : JPKd
collection of contexts.
JPK
JPKd : P(History)
Interface actions hb projection (‘guarantee’)
History: P(Action) × P(Action × Action) × P(Action × Action)
forbidden hb (‘deny’)
return call
P2 : P1 : Show : JP2Kd ⊆ JP1Kd
rf
rf
In history
P2 P1
∀C. ∀X2 ∈ JC(P2)K. ∃X1 ∈ JC(P1)K. obsv(X2) = obsv(X1) all contexts?
return call
write(x,5) read(x,7) write(y,4) write(y,7) read(y,9) read(x,9) write(y,8) read(z,7) write(z,8) read(z,8)
Drop non-interface context actions
return call
write(x) read(x)
rf
read(x)
rf
Drop duplicate interface reads
return call
write(x) read(x)
rf
write(x)
Drop interface reads from interface writes
return call
write(x)
Drop interface writes with siblings in modification-order
write(x) write(x) read(x) write(x)
rf mo mo mo
P is loop-free code = ⇒ is finite JPKd {X ∈ JPK | cut(X)} is finite = ⇒ cut(X)
∆
⇐ ⇒ “only interface actions” “only rf-distinguished reads” “only mo-distinguished writes” ∧ ∧
(release-acquire, NA, working on SC)
Would like to define parallel composition: Would (maybe) like full abstraction: ∀C. ∀X2 ∈ JC(P2)K. ∃X1 ∈ JC(P1)K. obsv(X2) = obsv(X1) = ⇒ JP2Kd ⊆ JP1Kd JP1kP2Kd
def
= JP1Kd JP2Kd