The core of SSA is that each value name has only one static definition, with uses explicitly associated with that definition. "Static" is important: the same instruction in a loop can be executed dynamically many times, producing different results each time, and still conform to SSA.
SSA improves the representation of data dependencies; it does not automatically eliminate all loop analysis requirements, nor does it require infinite physical registers or that memory can only be written once.
How to represent reassignment in branches at merge points
In a normal program, x is set to 1, then possibly set to 2 depending on a condition, and finally x is used. After converting to SSA, the two assignments use different names, and a φ definition is added at the merge point to select the input based on the incoming predecessor edge.
φ does not evaluate both inputs simultaneously and then check the condition; rather, it is a value selection associated with the actual control flow edge. In this example, it returns 3 or 2. It can exist as an IR instruction, but the target ISA does not need to have a machine instruction with the same name.
Dominance: Is a definition necessarily visible to its uses?
Block A dominates B if every path from the entry to B passes through A. For standard SSA usage, a definition should dominate its uses; within the same block, definitions must precede uses. φ inputs are checked against uses on their corresponding predecessor edges.
The immediate dominance relationship forms a tree on entry-reachable blocks, where each non-entry node has exactly one immediate dominator. A merge node in the CFG can have multiple predecessors, but it will not have two parent nodes in the dominator tree. Labeling a diamond-shaped CFG directly as a dominator tree confuses these two structures.
φ in loops: Connecting initial values with back-edge values
On the first entry to header, it selects 0; subsequently, returning from body, it selects next from the previous iteration. Definitions and uses may form cycles in the text or dependency graph; this does not violate SSA. Therefore, fixed-point analyses do not necessarily become single-pass just because SSA is used.
How the same static name produces multiple dynamic results when n=2
Edge entering header
Current %i
Comparison Result
What happens next
entry → header
0
0 < 2 is true
body calculates %next=1
body → header
1
1 < 2 is true
body calculates %next=2
body → header
2
2 < 2 is false
exit returns 2
In the text, %i has only one φ definition, and %next has only one add definition; the table records three dynamic arrivals of the same program, introducing no conflicting static definitions. If n=0 or negative, the first comparison exits and returns 0, with no body → header back-edge executions.
Putting the two IR snippets from choose and count_to into the same file ssa.ll, you can first run opt -passes=verify -disable-output ssa.ll. Then, use the following C driver to observe the two branches and zero/multiple loop iterations:
If you keep the CFG body → header back-edge but remove [ %next, %body ] from the φ for %i, the verifier should reject it: φ inputs must correspond to the predecessor structure. If %next is used directly as a normal value in entry, its definition does not dominate that use, which should also be rejected. The verifier proves that the IR structure satisfies the rules, not that the frontend has correctly expressed the source program's intent. LLVM φ Rules
How does one phi receive the initial and back-edge values?
Separate static instruction identity from dynamic visit number. There is always one definition of %i; the selected header visit determines whether phi takes the entry value or the preceding iteration’s result. At i=n the run compares and exits without computing another next.
Preparing the visual
How does one phi receive the initial and back-edge values?
Entry selects 0; later body edges select the preceding next. Repeated execution is not repeated static definition, and the exit visit skips the body.
{"id":"phi-loop-edges","title":"How does one phi receive the initial and back-edge values?","summary":"Entry selects 0; later body edges select the preceding next. Repeated execution is not repeated static definition, and the exit visit skips the body.","height":1000,"html":"<h2 data-i18n=\"heading\"></h2><p class=\"intro\" data-i18n=\"intro\"></p><div class=\"control\"><label for=\"n\" data-i18n=\"n\"></label><output for=\"n\" id=\"n-value\"></output><input id=\"n\" type=\"range\" min=\"0\" max=\"5\" value=\"2\" step=\"1\"></div><div class=\"control\"><label for=\"visit\" data-i18n=\"visit\"></label><output for=\"visit\" id=\"visit-value\"></output><input id=\"visit\" type=\"range\" min=\"0\" max=\"2\" value=\"1\" step=\"1\"></div><svg id=\"cfg\" class=\"diagram\" viewBox=\"0 0 360 180\" role=\"img\"></svg><div id=\"visits\" class=\"track\"></div><div class=\"metrics\"><div><span data-i18n=\"incoming\"></span><strong id=\"incoming\"></strong></div><div><span data-i18n=\"value\"></span><strong id=\"value\"></strong></div></div><p id=\"equation\" class=\"formula\"></p><div class=\"copy\"><p id=\"explanation\" role=\"status\"></p><p class=\"reserve\" aria-hidden=\"true\" data-i18n=\"body\"></p><p class=\"reserve\" aria-hidden=\"true\" data-i18n=\"exit\"></p></div><details class=\"scope\"><summary data-i18n=\"scopeLabel\"></summary><p data-i18n=\"scope\"></p></details>","css":".intro{margin:8px 0 18px;color:var(--muted);font-size:14px}.caption,.hint{font-size:12px;color:var(--muted);margin-top:12px}.control{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px 12px;align-items:center;margin:14px 0;font-size:13px}.control label{font-size:13px}.control output{color:var(--accent);min-width:5em;text-align:right;font-variant-numeric:tabular-nums}.control input{grid-column:1/-1;width:100%;margin:0}.presets{display:flex;gap:4px;align-items:stretch}.presets button{flex:1 1 0;min-width:0;overflow-wrap:anywhere;font-size:13px}.actions{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0}.actions button{flex:1;min-width:0;font-size:13px;min-height:42px}.copy{display:grid;font-size:14px;margin:16px 0}.copy>*{grid-area:1/1;margin:0}.reserve{visibility:hidden}.scope{margin-top:14px;color:var(--muted);font-size:12px}.scope summary{padding:8px 0;cursor:pointer}.scope p{margin-top:10px}.two{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.card{border:1px solid var(--rule);border-radius:9px;padding:14px;min-width:0}.card header{font-size:14px;font-weight:600;margin-bottom:10px}.card button{font-size:12px;width:100%;min-width:0}.card small{display:block;font-size:12px;color:var(--muted)}.card code{font-size:12px;overflow-wrap:anywhere}.metrics{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.metrics>div{border-left:2px solid var(--accent);padding-left:10px;min-width:0}.metrics span{display:block;min-height:3.2em;color:var(--muted);font-size:12px}.metrics strong{font-size:23px;display:block;font-weight:500;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.formula{border-top:1px solid var(--rule);padding-top:12px;margin-top:14px;font-size:13px;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}.value{font:500 20px var(--viz-font-ui)}.legend{display:flex;flex-wrap:wrap;gap:6px 14px;font-size:12px;color:var(--muted);margin:12px 0}.legend span:before{content:'';display:inline-block;width:8px;height:8px;border-radius:2px;background:var(--accent);margin-right:6px}.legend .second:before{background:var(--second)}.check{display:flex;align-items:center;gap:8px;font-size:13px;margin:12px 0}.check input{width:16px;height:16px;flex-shrink:0;accent-color:var(--accent)}select,input[type=text],input[type=number]{background:var(--paper);color:var(--ink);font:inherit;font-size:13px;padding:10px;border:1px solid var(--rule);border-radius:7px;max-width:100%;min-width:0}select{width:100%;min-height:42px}.band{height:20px;display:flex;background:var(--surface);border-radius:4px;overflow:hidden}.band i{height:100%;display:block;background:var(--accent);transition:width .25s}.band i.second{background:var(--second)}button:disabled{cursor:default}.status{font-size:13px;min-height:4.8em}.mono{font-family:var(--viz-font-mono);font-variant-numeric:tabular-nums}.muted{color:var(--muted)}\n@media(max-width:480px){.two{gap:8px}.card{padding:12px 9px}.actions button,.presets button{font-size:12px}.metrics strong{font-size:20px}.metrics{gap:8px}}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{transition:none!important;animation:none!important}}\n.track-row{margin:16px 0}.track-row>span{display:block;font-size:12px;color:var(--muted);margin-bottom:7px}.track{display:flex;gap:5px;min-width:0}.cell{flex:1;min-width:0;min-height:48px;border:1px solid var(--rule);border-radius:5px;background:var(--surface);display:flex;align-items:center;justify-content:center;text-align:center;padding:5px 3px;font-size:12px;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.cell.on{background:var(--accent-soft);border-color:var(--accent)}.cell.gold{background:var(--second-soft);border-color:var(--second)}.cell.empty{border-style:dashed;color:var(--muted)}.cell.error{border-color:var(--second);text-decoration:line-through}.choices{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;margin:14px 0}.choices button{min-width:0;padding:10px 4px;font-size:12px;overflow-wrap:anywhere}.choices button[aria-current=true]{border-color:var(--accent);background:var(--accent-soft)}.relation{display:grid;grid-template-columns:minmax(0,1fr) 28px minmax(0,1fr);align-items:center;gap:6px;margin:12px 0}.relation .cell{min-height:72px}.relation>i{text-align:center;font-style:normal;color:var(--accent)}.readout{font-size:13px;white-space:pre-line;min-height:6.4em;overflow-wrap:anywhere}.plot{position:relative;border-left:1px solid var(--rule);border-bottom:1px solid var(--rule);padding:8px 0;margin:18px 0}.plot-row{height:28px;position:relative;margin:4px 0;background:var(--surface)}.plot-row i{position:absolute;inset-block:5px;background:var(--accent);min-width:2px;transition:width .2s,left .2s}.plot-row b{position:relative;padding:4px 6px;font:11px/28px var(--viz-font-ui);background:var(--paper);border-radius:3px}.axis{display:flex;justify-content:space-between;font-size:11px;color:var(--muted)}\n\n/* Action labels must remain readable across locales and narrow embeds. */\n.actions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}\n.actions button{overflow-wrap:anywhere;white-space:normal;min-height:58px;padding:8px}\nbutton{overflow-wrap:anywhere}\n@media(min-width:640px){.actions{grid-template-columns:repeat(3,minmax(0,1fr))}}\n\n.metrics span{overflow-wrap:anywhere}\n.panel{border:1px solid var(--rule);border-radius:9px;padding:12px;margin:14px 0;min-width:0}.panel h3{font-size:13px;margin:0 0 10px;color:var(--muted)}.source{font:13px/1.8 var(--viz-font-mono);white-space:pre-wrap;overflow-wrap:anywhere;margin:12px 0}.source mark{background:var(--accent-soft);color:var(--ink);border-bottom:2px solid var(--accent)}.source .fault{background:var(--second-soft);border-color:var(--second)}.diagram{display:block;width:100%;height:auto;max-height:320px;margin:14px 0;overflow:visible}.diagram text{fill:var(--ink);font:12px var(--viz-font-ui)}.diagram .edge{stroke:var(--muted);stroke-width:1.5;fill:none}.diagram .edge.on{stroke:var(--accent);stroke-width:3}.diagram .node{fill:var(--surface);stroke:var(--rule);stroke-width:1.5}.diagram .node.on{fill:var(--accent-soft);stroke:var(--accent)}.diagram .node.gold{fill:var(--second-soft);stroke:var(--second)}.log{font:12px/1.8 var(--viz-font-mono);white-space:pre-line;overflow-wrap:anywhere;min-height:7.2em}.table{display:grid;gap:5px;margin:14px 0}.table .tr{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:5px}.table .tr>*{padding:8px 5px;background:var(--surface);border-radius:4px;min-width:0;overflow-wrap:anywhere;font-size:12px}.table .tr .on{background:var(--accent-soft)}.table .tr .gold{background:var(--second-soft)}.choices button{min-height:44px}.metrics strong{min-height:1.6em}.code-line{display:block}.code-line.on{background:var(--accent-soft);border-left:2px solid var(--accent);padding-left:6px}.status-badge{font-size:12px;color:var(--accent)}.tile-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px}.tile-grid .cell{min-height:40px}.actions button{min-height:48px}.form-field{display:grid;gap:8px;margin:14px 0;font-size:13px}.form-field input{width:100%;font-family:var(--viz-font-ui)}.metrics.three{grid-template-columns:repeat(3,minmax(0,1fr))}.formula{min-height:3.2em}.presets{flex-wrap:wrap}.presets button{flex-basis:25%;min-height:44px}\n\n.metrics strong{font-size:18px}#equation{white-space:pre-line;min-height:7.2em}","js":"const $=s=>document.querySelector(s);const set=(id,v)=>$('#'+id).textContent=v;const t=k=>viz.t(k);function cells(id,values){$('#'+id).replaceChildren(...values.map(v=>{const e=document.createElement('div');e.className='cell '+(v.cls||'');e.textContent=v.text;e.title=v.title||v.text;return e;}));}function pressed(mode){document.querySelectorAll('[data-mode]').forEach(e=>e.setAttribute('aria-pressed',String(e.dataset.mode===mode)));}const esc=s=>String(s).replace(/[&<>\"']/g,c=>({'&':'&','<':'<','>':'>','\"':'"',\"'\":'''}[c]));const fmt=s=>'{'+[...s].sort().join(', ')+'}';function graph(id,nodes,edges){const el=$('#'+id);el.setAttribute('viewBox','0 0 360 200');el.innerHTML='<defs><marker id=\"arrow-'+id+'\" viewBox=\"0 0 10 10\" refX=\"8\" refY=\"5\" markerWidth=\"5\" markerHeight=\"5\" orient=\"auto-start-reverse\"><path d=\"M 0 0 L 10 5 L 0 10 z\" fill=\"var(--muted)\"/></marker></defs>'+edges.map(e=>{const a=nodes[e[0]],b=nodes[e[1]],dx=b.x-a.x,dy=b.y-a.y,d=Math.hypot(dx,dy)||1;if(edges.some(r=>r[0]===e[1]&&r[1]===e[0])){const nx=-dy/d,ny=dx/d;return '<path class=\"edge '+(e[2]?'on':'')+'\" d=\"M '+(a.x+dx/d*22+nx*12)+' '+(a.y+dy/d*22+ny*12)+' Q '+((a.x+b.x)/2+nx*38)+' '+((a.y+b.y)/2+ny*38)+' '+(b.x-dx/d*25+nx*12)+' '+(b.y-dy/d*25+ny*12)+'\" marker-end=\"url(#arrow-'+id+')\"/>';}return '<line class=\"edge '+(e[2]?'on':'')+'\" x1=\"'+(a.x+dx/d*25)+'\" y1=\"'+(a.y+dy/d*25)+'\" x2=\"'+(b.x-dx/d*28)+'\" y2=\"'+(b.y-dy/d*28)+'\" marker-end=\"url(#arrow-'+id+')\"/>';}).join('')+nodes.map(n=>'<g><circle class=\"node '+(n.cls||'')+'\" cx=\"'+n.x+'\" cy=\"'+n.y+'\" r=\"25\"/><text x=\"'+n.x+'\" y=\"'+(n.y+4)+'\" text-anchor=\"middle\">'+esc(n.name)+'</text>'+(n.sub?'<text x=\"'+n.x+'\" y=\"'+(n.y+43)+'\" text-anchor=\"middle\">'+esc(n.sub)+'</text>':'')+'</g>').join('');}function table(id,rows){$('#'+id).replaceChildren(...rows.map(r=>{const row=document.createElement('div');row.className='tr';r.forEach(x=>{const c=document.createElement('div');if(typeof x==='object'){c.textContent=x.text;c.className=x.cls||'';}else c.textContent=x;row.append(c)});return row;}));}function draw(){const n=+$('#n').value;$('#visit').max=n;const i=Math.min(n,+$('#visit').value);set('n-value',n);set('visit-value',i+' / '+n);graph('cfg',[{name:'entry',x:50,y:55},{name:'header',x:180,y:55,cls:'on'},{name:'body',x:305,y:55,cls:i<n?'gold':''},{name:'exit',x:180,y:160,cls:i===n?'gold':''}],[[0,1,i===0],[1,2,i<n],[2,1,i>0],[1,3,i===n]]);cells('visits',Array.from({length:6},(_,j)=>({text:j<=n?'i='+j:'·',cls:j===i?'gold':j<=n?'on':'empty'})));set('incoming',i===0?'entry → header':'body → header');set('value',i);set('equation','%i = φ ['+(i===0?'0 ✓':'0')+', entry], ['+(i>0?i+' ✓':'%next')+', body]\\n'+i+' < '+n+' = '+(i<n));set('explanation',t(i<n?'body':'exit'));$('#value').dataset.exited=String(i===n);}$('#n').oninput=draw;$('#visit').oninput=draw;draw();","audio":false,"strings":{"body":"Condition true: execute body, compute next=i+1 and return to header.","exit":"Condition false: exit and return i; no next is computed on this visit.","heading":"How does one phi receive the initial and back-edge values?","incoming":"Incoming header edge","intro":"Choose the loop limit and header visit. The incoming edge, current i and next action update together; the static definition stays singular.","n":"Loop bound n","next":"Next action","reset":"Reset","scope":"Integer 0≤n≤5, loop i<n, increment by one. Position selects an execution snapshot; changing n recomputes the run.","scopeLabel":"Model scope and assumptions","value":"Current %i","visit":"Header visit to inspect"}}
Dominance Frontier: Where merge points need selection for a definition's influence
DF(X) = {Y | X dominates some predecessor of Y, but X does not strictly dominate Y}.
"Non-strict dominance" allows cases where Y=X in certain loops, so the dominance frontier cannot always be interpreted as the first node completely outside X's dominance region.
The classic construction starts from the definition block of a variable, inserts φs iteratively on the dominance frontier, and the new φ blocks act as definitions for further propagation. Pruned SSA further avoids inserting useless φs by leveraging variable liveness at entry points. This does not mean inserting a φ at every merge point for all variables.
Renaming: Maintaining current versions along the dominator tree
Maintain a version stack for each source variable; create a version for φ results upon entering a block; when scanning normal instructions, first replace uses with the current version, then create a version for the new definition; when leaving the block to process successor edges, fill in the corresponding φ inputs; after recursively processing dominator tree children, pop the versions pushed by the current block.
Uninitialized uses must be determined by source language semantics or frontend error handling; you cannot arbitrarily fill 0 just to make SSA pass. Unreachable blocks also need cleanup or independent handling according to algorithm conventions.
General CFGs, including irreducible control flow, can also have SSA constructed; it is not required to first convert all loops into single-entry natural loops. Some subsequent loop optimizations may require a reduced form, but that is a separate issue.
Which incoming path creates a dominance frontier?
“Does not strictly dominate” is weaker than “does not dominate.” With M’s self-loop, M dominates predecessor M but not strictly itself, so M∈DF(M). In the diamond, selecting L or R shows how the other branch prevents domination of M. Colors come from computed dominator sets; the CFG is not a dominator tree.
DF(X)={Y∣∃P∈pred(Y):XdomP∧¬(XsdomY)}
Preparing the visual
Which incoming path creates a dominance frontier?
Y is in DF(X) when X dominates a predecessor of Y but does not strictly dominate Y. Diamond definitions meet at M; a self-loop can place M in its own frontier.
{"id":"dominance-frontier","title":"Which incoming path creates a dominance frontier?","summary":"Y is in DF(X) when X dominates a predecessor of Y but does not strictly dominate Y. Diamond definitions meet at M; a self-loop can place M in its own frontier.","height":1000,"html":"<h2 data-i18n=\"heading\"></h2><p class=\"intro\" data-i18n=\"intro\"></p><div class=\"presets\" role=\"group\" data-i18n-label=\"choose\"><button data-mode=\"E\" data-i18n=\"E\"></button><button data-mode=\"L\" data-i18n=\"L\"></button><button data-mode=\"R\" data-i18n=\"R\"></button><button data-mode=\"M\" data-i18n=\"M\"></button><button data-mode=\"Z\" data-i18n=\"Z\"></button></div><label class=\"check\"><input type=\"checkbox\" id=\"loop\"><span data-i18n=\"loop\"></span></label><svg id=\"cfg\" class=\"diagram\" viewBox=\"0 0 360 180\" role=\"img\"></svg><div class=\"metrics\"><div><span data-i18n=\"dominated\"></span><strong id=\"dominated\"></strong></div><div><span data-i18n=\"frontier\"></span><strong id=\"frontier\"></strong></div></div><p id=\"reason\" class=\"log\"></p><details class=\"scope\"><summary data-i18n=\"scopeLabel\"></summary><p data-i18n=\"scope\"></p></details>","css":".intro{margin:8px 0 18px;color:var(--muted);font-size:14px}.caption,.hint{font-size:12px;color:var(--muted);margin-top:12px}.control{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px 12px;align-items:center;margin:14px 0;font-size:13px}.control label{font-size:13px}.control output{color:var(--accent);min-width:5em;text-align:right;font-variant-numeric:tabular-nums}.control input{grid-column:1/-1;width:100%;margin:0}.presets{display:flex;gap:4px;align-items:stretch}.presets button{flex:1 1 0;min-width:0;overflow-wrap:anywhere;font-size:13px}.actions{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0}.actions button{flex:1;min-width:0;font-size:13px;min-height:42px}.copy{display:grid;font-size:14px;margin:16px 0}.copy>*{grid-area:1/1;margin:0}.reserve{visibility:hidden}.scope{margin-top:14px;color:var(--muted);font-size:12px}.scope summary{padding:8px 0;cursor:pointer}.scope p{margin-top:10px}.two{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.card{border:1px solid var(--rule);border-radius:9px;padding:14px;min-width:0}.card header{font-size:14px;font-weight:600;margin-bottom:10px}.card button{font-size:12px;width:100%;min-width:0}.card small{display:block;font-size:12px;color:var(--muted)}.card code{font-size:12px;overflow-wrap:anywhere}.metrics{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.metrics>div{border-left:2px solid var(--accent);padding-left:10px;min-width:0}.metrics span{display:block;min-height:3.2em;color:var(--muted);font-size:12px}.metrics strong{font-size:23px;display:block;font-weight:500;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.formula{border-top:1px solid var(--rule);padding-top:12px;margin-top:14px;font-size:13px;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}.value{font:500 20px var(--viz-font-ui)}.legend{display:flex;flex-wrap:wrap;gap:6px 14px;font-size:12px;color:var(--muted);margin:12px 0}.legend span:before{content:'';display:inline-block;width:8px;height:8px;border-radius:2px;background:var(--accent);margin-right:6px}.legend .second:before{background:var(--second)}.check{display:flex;align-items:center;gap:8px;font-size:13px;margin:12px 0}.check input{width:16px;height:16px;flex-shrink:0;accent-color:var(--accent)}select,input[type=text],input[type=number]{background:var(--paper);color:var(--ink);font:inherit;font-size:13px;padding:10px;border:1px solid var(--rule);border-radius:7px;max-width:100%;min-width:0}select{width:100%;min-height:42px}.band{height:20px;display:flex;background:var(--surface);border-radius:4px;overflow:hidden}.band i{height:100%;display:block;background:var(--accent);transition:width .25s}.band i.second{background:var(--second)}button:disabled{cursor:default}.status{font-size:13px;min-height:4.8em}.mono{font-family:var(--viz-font-mono);font-variant-numeric:tabular-nums}.muted{color:var(--muted)}\n@media(max-width:480px){.two{gap:8px}.card{padding:12px 9px}.actions button,.presets button{font-size:12px}.metrics strong{font-size:20px}.metrics{gap:8px}}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{transition:none!important;animation:none!important}}\n.track-row{margin:16px 0}.track-row>span{display:block;font-size:12px;color:var(--muted);margin-bottom:7px}.track{display:flex;gap:5px;min-width:0}.cell{flex:1;min-width:0;min-height:48px;border:1px solid var(--rule);border-radius:5px;background:var(--surface);display:flex;align-items:center;justify-content:center;text-align:center;padding:5px 3px;font-size:12px;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.cell.on{background:var(--accent-soft);border-color:var(--accent)}.cell.gold{background:var(--second-soft);border-color:var(--second)}.cell.empty{border-style:dashed;color:var(--muted)}.cell.error{border-color:var(--second);text-decoration:line-through}.choices{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;margin:14px 0}.choices button{min-width:0;padding:10px 4px;font-size:12px;overflow-wrap:anywhere}.choices button[aria-current=true]{border-color:var(--accent);background:var(--accent-soft)}.relation{display:grid;grid-template-columns:minmax(0,1fr) 28px minmax(0,1fr);align-items:center;gap:6px;margin:12px 0}.relation .cell{min-height:72px}.relation>i{text-align:center;font-style:normal;color:var(--accent)}.readout{font-size:13px;white-space:pre-line;min-height:6.4em;overflow-wrap:anywhere}.plot{position:relative;border-left:1px solid var(--rule);border-bottom:1px solid var(--rule);padding:8px 0;margin:18px 0}.plot-row{height:28px;position:relative;margin:4px 0;background:var(--surface)}.plot-row i{position:absolute;inset-block:5px;background:var(--accent);min-width:2px;transition:width .2s,left .2s}.plot-row b{position:relative;padding:4px 6px;font:11px/28px var(--viz-font-ui);background:var(--paper);border-radius:3px}.axis{display:flex;justify-content:space-between;font-size:11px;color:var(--muted)}\n\n/* Action labels must remain readable across locales and narrow embeds. */\n.actions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}\n.actions button{overflow-wrap:anywhere;white-space:normal;min-height:58px;padding:8px}\nbutton{overflow-wrap:anywhere}\n@media(min-width:640px){.actions{grid-template-columns:repeat(3,minmax(0,1fr))}}\n\n.metrics span{overflow-wrap:anywhere}\n.panel{border:1px solid var(--rule);border-radius:9px;padding:12px;margin:14px 0;min-width:0}.panel h3{font-size:13px;margin:0 0 10px;color:var(--muted)}.source{font:13px/1.8 var(--viz-font-mono);white-space:pre-wrap;overflow-wrap:anywhere;margin:12px 0}.source mark{background:var(--accent-soft);color:var(--ink);border-bottom:2px solid var(--accent)}.source .fault{background:var(--second-soft);border-color:var(--second)}.diagram{display:block;width:100%;height:auto;max-height:320px;margin:14px 0;overflow:visible}.diagram text{fill:var(--ink);font:12px var(--viz-font-ui)}.diagram .edge{stroke:var(--muted);stroke-width:1.5;fill:none}.diagram .edge.on{stroke:var(--accent);stroke-width:3}.diagram .node{fill:var(--surface);stroke:var(--rule);stroke-width:1.5}.diagram .node.on{fill:var(--accent-soft);stroke:var(--accent)}.diagram .node.gold{fill:var(--second-soft);stroke:var(--second)}.log{font:12px/1.8 var(--viz-font-mono);white-space:pre-line;overflow-wrap:anywhere;min-height:7.2em}.table{display:grid;gap:5px;margin:14px 0}.table .tr{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:5px}.table .tr>*{padding:8px 5px;background:var(--surface);border-radius:4px;min-width:0;overflow-wrap:anywhere;font-size:12px}.table .tr .on{background:var(--accent-soft)}.table .tr .gold{background:var(--second-soft)}.choices button{min-height:44px}.metrics strong{min-height:1.6em}.code-line{display:block}.code-line.on{background:var(--accent-soft);border-left:2px solid var(--accent);padding-left:6px}.status-badge{font-size:12px;color:var(--accent)}.tile-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px}.tile-grid .cell{min-height:40px}.actions button{min-height:48px}.form-field{display:grid;gap:8px;margin:14px 0;font-size:13px}.form-field input{width:100%;font-family:var(--viz-font-ui)}.metrics.three{grid-template-columns:repeat(3,minmax(0,1fr))}.formula{min-height:3.2em}.presets{flex-wrap:wrap}.presets button{flex-basis:25%;min-height:44px}\n\n.metrics strong{font-size:17px;min-height:3.2em}#cfg{min-height:160px}","js":"const $=s=>document.querySelector(s);const set=(id,v)=>$('#'+id).textContent=v;const t=k=>viz.t(k);function cells(id,values){$('#'+id).replaceChildren(...values.map(v=>{const e=document.createElement('div');e.className='cell '+(v.cls||'');e.textContent=v.text;e.title=v.title||v.text;return e;}));}function pressed(mode){document.querySelectorAll('[data-mode]').forEach(e=>e.setAttribute('aria-pressed',String(e.dataset.mode===mode)));}const esc=s=>String(s).replace(/[&<>\"']/g,c=>({'&':'&','<':'<','>':'>','\"':'"',\"'\":'''}[c]));const fmt=s=>'{'+[...s].sort().join(', ')+'}';function graph(id,nodes,edges){const el=$('#'+id);el.setAttribute('viewBox','0 0 360 200');el.innerHTML='<defs><marker id=\"arrow-'+id+'\" viewBox=\"0 0 10 10\" refX=\"8\" refY=\"5\" markerWidth=\"5\" markerHeight=\"5\" orient=\"auto-start-reverse\"><path d=\"M 0 0 L 10 5 L 0 10 z\" fill=\"var(--muted)\"/></marker></defs>'+edges.map(e=>{const a=nodes[e[0]],b=nodes[e[1]],dx=b.x-a.x,dy=b.y-a.y,d=Math.hypot(dx,dy)||1;if(edges.some(r=>r[0]===e[1]&&r[1]===e[0])){const nx=-dy/d,ny=dx/d;return '<path class=\"edge '+(e[2]?'on':'')+'\" d=\"M '+(a.x+dx/d*22+nx*12)+' '+(a.y+dy/d*22+ny*12)+' Q '+((a.x+b.x)/2+nx*38)+' '+((a.y+b.y)/2+ny*38)+' '+(b.x-dx/d*25+nx*12)+' '+(b.y-dy/d*25+ny*12)+'\" marker-end=\"url(#arrow-'+id+')\"/>';}return '<line class=\"edge '+(e[2]?'on':'')+'\" x1=\"'+(a.x+dx/d*25)+'\" y1=\"'+(a.y+dy/d*25)+'\" x2=\"'+(b.x-dx/d*28)+'\" y2=\"'+(b.y-dy/d*28)+'\" marker-end=\"url(#arrow-'+id+')\"/>';}).join('')+nodes.map(n=>'<g><circle class=\"node '+(n.cls||'')+'\" cx=\"'+n.x+'\" cy=\"'+n.y+'\" r=\"25\"/><text x=\"'+n.x+'\" y=\"'+(n.y+4)+'\" text-anchor=\"middle\">'+esc(n.name)+'</text>'+(n.sub?'<text x=\"'+n.x+'\" y=\"'+(n.y+43)+'\" text-anchor=\"middle\">'+esc(n.sub)+'</text>':'')+'</g>').join('');}function table(id,rows){$('#'+id).replaceChildren(...rows.map(r=>{const row=document.createElement('div');row.className='tr';r.forEach(x=>{const c=document.createElement('div');if(typeof x==='object'){c.textContent=x.text;c.className=x.cls||'';}else c.textContent=x;row.append(c)});return row;}));}let chosen='L';const names=['E','L','R','M','Z'];function draw(){let edges=[[0,1],[0,2],[1,3],[2,3],[3,4]];if($('#loop').checked)edges.push([3,3]);let dom=names.map((_,i)=>new Set(i?names:[names[0]])),changed=true;while(changed){changed=false;for(let i=1;i<5;i++){const pred=edges.filter(e=>e[1]===i).map(e=>e[0]),d=new Set([names[i],...names.filter(x=>pred.every(p=>dom[p].has(x)))]);if(fmt(d)!==fmt(dom[i])){dom[i]=d;changed=true}}}const dominated=names.filter((_,i)=>dom[i].has(chosen)),df=names.filter((y,i)=>edges.some(([p,q])=>q===i&&dom[p].has(chosen))&&!(y!==chosen&&dom[i].has(chosen)));const pos=[[180,28],[65,95],[295,95],[180,135],[180,250]];graph('cfg',names.map((name,i)=>({name,x:pos[i][0],y:pos[i][1],cls:df.includes(name)?'gold':dominated.includes(name)?'on':''})),edges.filter(e=>e[0]!==e[1]));$('#cfg').setAttribute('viewBox','0 0 360 285');if($('#loop').checked)$('#cfg').insertAdjacentHTML('beforeend','<path class=\"edge\" d=\"M205 135 C290 125 290 195 200 155\" marker-end=\"url(#arrow-cfg)\"/>');set('dominated',fmt(dominated));set('frontier',fmt(df));set('reason',df.map(y=>{const i=names.indexOf(y),p=edges.find(([p,q])=>q===i&&dom[p].has(chosen))[0];return chosen+' dom '+names[p]+' → '+y+'; '+chosen+' ≠ strict-dom('+y+')'}).join('\\n')||'DF('+chosen+') = ∅');$('#frontier').dataset.members=df.join(',');pressed(chosen);}document.querySelectorAll('[data-mode]').forEach(b=>b.onclick=()=>{chosen=b.dataset.mode;draw()});$('#loop').onchange=draw;draw();","audio":false,"strings":{"E":"E","L":"L","M":"M","R":"R","Z":"Z","choose":"Choose X","dominated":"Blocks dominated by X","frontier":"DF(X)","heading":"Which incoming path creates a dominance frontier?","intro":"Choose X: blue marks dominated blocks, gold marks DF(X). Add M’s self-loop to see how a frontier may include X itself.","loop":"Add M → M back edge","reason":"Frontier witness: predecessor and non-strict domination","reset":"Reset","scope":"Fixed reachable CFG E→L/R→M→Z, optional M→M. Dominators are solved iteratively and frontiers follow the definition. The CFG is not a dominator tree or complete phi-placement algorithm.","scopeLabel":"Model scope and assumptions"}}
Destruction: φ produces parallel copies on edges
When there are multiple φ inputs on a predecessor edge, they can be understood as simultaneous assignments to the result locations. For example, after location allocation, if a←b and b←a are needed, sequential execution would lose one old value; a temporary location or a proper swap sequence must be used.
For critical edges where a predecessor has multiple successors and a successor has multiple predecessors, copies cannot be unconditionally placed at the end of the predecessor or the beginning of the successor; this is often handled by splitting edges to create execution locations specific to that path.
φ inputs coming from different predecessors do not prove that they are never simultaneously active throughout the program. The source values may still be used elsewhere, so sharing physical locations requires interference and copy coalescing checks; you cannot unconditionally merge all values of a φ into a single register.
A set of swap copies must read the same old state
The old values of locations a and b are 10 and 20, respectively, and the target parallel copy is a←b, b←a. After the first sequential copy, a has become 20; if the second copy reads a again, it will get the new value, resulting in both being 20. The role of the temporary location is to preserve the old value that was overwritten early.
This problem occurs after mapping SSA values to reusable physical locations; it is not saying that SSA itself allows reassigning the same name. General parallel copies may have acyclic chains and multiple cycles: arrange copies that do not destroy other old inputs first, and introduce temporary locations when encountering cycles; only when swapping two items can you directly use this three-step template.
Copies cannot simply be moved to the end of P, otherwise P→X would also execute them; nor can they be placed at the entry of M, otherwise Q→M would also execute the copy from P. After splitting the edge, the φ predecessor for M must be updated from P to the new block, not just changing the jump target.
Can a later copy still read an overwritten old value?
The overwritten entities are reusable locations, not SSA names. All target RHS operands refer to one old state. Actions preserve visible current values and recent writes. Try two direct copies, reset, then use a temporary to locate the loss precisely. Saving too late merely preserves an already overwritten value.
Preparing the visual
Can a later copy still read an overwritten old value?
All RHS values in a parallel copy come from the same old state. Sequential writes can lose one; a temporary preserves old a for b. Reset starts a new attempt.
{"id":"parallel-copy-cycle","title":"Can a later copy still read an overwritten old value?","summary":"All RHS values in a parallel copy come from the same old state. Sequential writes can lose one; a temporary preserves old a for b. Reset starts a new attempt.","height":1000,"html":"<h2 data-i18n=\"heading\"></h2><p class=\"intro\" data-i18n=\"intro\"></p><p class=\"source\">old: a=10, b=20 → target: a=20, b=10</p><div class=\"actions\"><button id=\"save\" data-i18n=\"save\"></button><button id=\"ab\" data-i18n=\"ab\"></button><button id=\"ba\" data-i18n=\"ba\"></button><button id=\"bt\" data-i18n=\"bt\"></button><button id=\"reset\" data-i18n=\"reset\"></button></div><div id=\"current\" class=\"track\"></div><section class=\"panel\"><h3 data-i18n=\"history\"></h3><div id=\"history\"></div></section><div class=\"copy\"><p id=\"explanation\" role=\"status\"></p><p class=\"reserve\" aria-hidden=\"true\" data-i18n=\"ok\"></p><p class=\"reserve\" aria-hidden=\"true\" data-i18n=\"wait\"></p></div><details class=\"scope\"><summary data-i18n=\"scopeLabel\"></summary><p data-i18n=\"scope\"></p></details>","css":".intro{margin:8px 0 18px;color:var(--muted);font-size:14px}.caption,.hint{font-size:12px;color:var(--muted);margin-top:12px}.control{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px 12px;align-items:center;margin:14px 0;font-size:13px}.control label{font-size:13px}.control output{color:var(--accent);min-width:5em;text-align:right;font-variant-numeric:tabular-nums}.control input{grid-column:1/-1;width:100%;margin:0}.presets{display:flex;gap:4px;align-items:stretch}.presets button{flex:1 1 0;min-width:0;overflow-wrap:anywhere;font-size:13px}.actions{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0}.actions button{flex:1;min-width:0;font-size:13px;min-height:42px}.copy{display:grid;font-size:14px;margin:16px 0}.copy>*{grid-area:1/1;margin:0}.reserve{visibility:hidden}.scope{margin-top:14px;color:var(--muted);font-size:12px}.scope summary{padding:8px 0;cursor:pointer}.scope p{margin-top:10px}.two{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.card{border:1px solid var(--rule);border-radius:9px;padding:14px;min-width:0}.card header{font-size:14px;font-weight:600;margin-bottom:10px}.card button{font-size:12px;width:100%;min-width:0}.card small{display:block;font-size:12px;color:var(--muted)}.card code{font-size:12px;overflow-wrap:anywhere}.metrics{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.metrics>div{border-left:2px solid var(--accent);padding-left:10px;min-width:0}.metrics span{display:block;min-height:3.2em;color:var(--muted);font-size:12px}.metrics strong{font-size:23px;display:block;font-weight:500;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.formula{border-top:1px solid var(--rule);padding-top:12px;margin-top:14px;font-size:13px;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}.value{font:500 20px var(--viz-font-ui)}.legend{display:flex;flex-wrap:wrap;gap:6px 14px;font-size:12px;color:var(--muted);margin:12px 0}.legend span:before{content:'';display:inline-block;width:8px;height:8px;border-radius:2px;background:var(--accent);margin-right:6px}.legend .second:before{background:var(--second)}.check{display:flex;align-items:center;gap:8px;font-size:13px;margin:12px 0}.check input{width:16px;height:16px;flex-shrink:0;accent-color:var(--accent)}select,input[type=text],input[type=number]{background:var(--paper);color:var(--ink);font:inherit;font-size:13px;padding:10px;border:1px solid var(--rule);border-radius:7px;max-width:100%;min-width:0}select{width:100%;min-height:42px}.band{height:20px;display:flex;background:var(--surface);border-radius:4px;overflow:hidden}.band i{height:100%;display:block;background:var(--accent);transition:width .25s}.band i.second{background:var(--second)}button:disabled{cursor:default}.status{font-size:13px;min-height:4.8em}.mono{font-family:var(--viz-font-mono);font-variant-numeric:tabular-nums}.muted{color:var(--muted)}\n@media(max-width:480px){.two{gap:8px}.card{padding:12px 9px}.actions button,.presets button{font-size:12px}.metrics strong{font-size:20px}.metrics{gap:8px}}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{transition:none!important;animation:none!important}}\n.track-row{margin:16px 0}.track-row>span{display:block;font-size:12px;color:var(--muted);margin-bottom:7px}.track{display:flex;gap:5px;min-width:0}.cell{flex:1;min-width:0;min-height:48px;border:1px solid var(--rule);border-radius:5px;background:var(--surface);display:flex;align-items:center;justify-content:center;text-align:center;padding:5px 3px;font-size:12px;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.cell.on{background:var(--accent-soft);border-color:var(--accent)}.cell.gold{background:var(--second-soft);border-color:var(--second)}.cell.empty{border-style:dashed;color:var(--muted)}.cell.error{border-color:var(--second);text-decoration:line-through}.choices{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;margin:14px 0}.choices button{min-width:0;padding:10px 4px;font-size:12px;overflow-wrap:anywhere}.choices button[aria-current=true]{border-color:var(--accent);background:var(--accent-soft)}.relation{display:grid;grid-template-columns:minmax(0,1fr) 28px minmax(0,1fr);align-items:center;gap:6px;margin:12px 0}.relation .cell{min-height:72px}.relation>i{text-align:center;font-style:normal;color:var(--accent)}.readout{font-size:13px;white-space:pre-line;min-height:6.4em;overflow-wrap:anywhere}.plot{position:relative;border-left:1px solid var(--rule);border-bottom:1px solid var(--rule);padding:8px 0;margin:18px 0}.plot-row{height:28px;position:relative;margin:4px 0;background:var(--surface)}.plot-row i{position:absolute;inset-block:5px;background:var(--accent);min-width:2px;transition:width .2s,left .2s}.plot-row b{position:relative;padding:4px 6px;font:11px/28px var(--viz-font-ui);background:var(--paper);border-radius:3px}.axis{display:flex;justify-content:space-between;font-size:11px;color:var(--muted)}\n\n/* Action labels must remain readable across locales and narrow embeds. */\n.actions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}\n.actions button{overflow-wrap:anywhere;white-space:normal;min-height:58px;padding:8px}\nbutton{overflow-wrap:anywhere}\n@media(min-width:640px){.actions{grid-template-columns:repeat(3,minmax(0,1fr))}}\n\n.metrics span{overflow-wrap:anywhere}\n.panel{border:1px solid var(--rule);border-radius:9px;padding:12px;margin:14px 0;min-width:0}.panel h3{font-size:13px;margin:0 0 10px;color:var(--muted)}.source{font:13px/1.8 var(--viz-font-mono);white-space:pre-wrap;overflow-wrap:anywhere;margin:12px 0}.source mark{background:var(--accent-soft);color:var(--ink);border-bottom:2px solid var(--accent)}.source .fault{background:var(--second-soft);border-color:var(--second)}.diagram{display:block;width:100%;height:auto;max-height:320px;margin:14px 0;overflow:visible}.diagram text{fill:var(--ink);font:12px var(--viz-font-ui)}.diagram .edge{stroke:var(--muted);stroke-width:1.5;fill:none}.diagram .edge.on{stroke:var(--accent);stroke-width:3}.diagram .node{fill:var(--surface);stroke:var(--rule);stroke-width:1.5}.diagram .node.on{fill:var(--accent-soft);stroke:var(--accent)}.diagram .node.gold{fill:var(--second-soft);stroke:var(--second)}.log{font:12px/1.8 var(--viz-font-mono);white-space:pre-line;overflow-wrap:anywhere;min-height:7.2em}.table{display:grid;gap:5px;margin:14px 0}.table .tr{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:5px}.table .tr>*{padding:8px 5px;background:var(--surface);border-radius:4px;min-width:0;overflow-wrap:anywhere;font-size:12px}.table .tr .on{background:var(--accent-soft)}.table .tr .gold{background:var(--second-soft)}.choices button{min-height:44px}.metrics strong{min-height:1.6em}.code-line{display:block}.code-line.on{background:var(--accent-soft);border-left:2px solid var(--accent);padding-left:6px}.status-badge{font-size:12px;color:var(--accent)}.tile-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px}.tile-grid .cell{min-height:40px}.actions button{min-height:48px}.form-field{display:grid;gap:8px;margin:14px 0;font-size:13px}.form-field input{width:100%;font-family:var(--viz-font-ui)}.metrics.three{grid-template-columns:repeat(3,minmax(0,1fr))}.formula{min-height:3.2em}.presets{flex-wrap:wrap}.presets button{flex-basis:25%;min-height:44px}\n\n#history{font:13px/1.8 var(--viz-font-ui);min-height:7.2em;white-space:pre-line}","js":"const $=s=>document.querySelector(s);const set=(id,v)=>$('#'+id).textContent=v;const t=k=>viz.t(k);function cells(id,values){$('#'+id).replaceChildren(...values.map(v=>{const e=document.createElement('div');e.className='cell '+(v.cls||'');e.textContent=v.text;e.title=v.title||v.text;return e;}));}function pressed(mode){document.querySelectorAll('[data-mode]').forEach(e=>e.setAttribute('aria-pressed',String(e.dataset.mode===mode)));}const esc=s=>String(s).replace(/[&<>\"']/g,c=>({'&':'&','<':'<','>':'>','\"':'"',\"'\":'''}[c]));const fmt=s=>'{'+[...s].sort().join(', ')+'}';function graph(id,nodes,edges){const el=$('#'+id);el.setAttribute('viewBox','0 0 360 200');el.innerHTML='<defs><marker id=\"arrow-'+id+'\" viewBox=\"0 0 10 10\" refX=\"8\" refY=\"5\" markerWidth=\"5\" markerHeight=\"5\" orient=\"auto-start-reverse\"><path d=\"M 0 0 L 10 5 L 0 10 z\" fill=\"var(--muted)\"/></marker></defs>'+edges.map(e=>{const a=nodes[e[0]],b=nodes[e[1]],dx=b.x-a.x,dy=b.y-a.y,d=Math.hypot(dx,dy)||1;if(edges.some(r=>r[0]===e[1]&&r[1]===e[0])){const nx=-dy/d,ny=dx/d;return '<path class=\"edge '+(e[2]?'on':'')+'\" d=\"M '+(a.x+dx/d*22+nx*12)+' '+(a.y+dy/d*22+ny*12)+' Q '+((a.x+b.x)/2+nx*38)+' '+((a.y+b.y)/2+ny*38)+' '+(b.x-dx/d*25+nx*12)+' '+(b.y-dy/d*25+ny*12)+'\" marker-end=\"url(#arrow-'+id+')\"/>';}return '<line class=\"edge '+(e[2]?'on':'')+'\" x1=\"'+(a.x+dx/d*25)+'\" y1=\"'+(a.y+dy/d*25)+'\" x2=\"'+(b.x-dx/d*28)+'\" y2=\"'+(b.y-dy/d*28)+'\" marker-end=\"url(#arrow-'+id+')\"/>';}).join('')+nodes.map(n=>'<g><circle class=\"node '+(n.cls||'')+'\" cx=\"'+n.x+'\" cy=\"'+n.y+'\" r=\"25\"/><text x=\"'+n.x+'\" y=\"'+(n.y+4)+'\" text-anchor=\"middle\">'+esc(n.name)+'</text>'+(n.sub?'<text x=\"'+n.x+'\" y=\"'+(n.y+43)+'\" text-anchor=\"middle\">'+esc(n.sub)+'</text>':'')+'</g>').join('');}function table(id,rows){$('#'+id).replaceChildren(...rows.map(r=>{const row=document.createElement('div');row.className='tr';r.forEach(x=>{const c=document.createElement('div');if(typeof x==='object'){c.textContent=x.text;c.className=x.cls||'';}else c.textContent=x;row.append(c)});return row;}));}let a=10,b=20,temp=null,history=[];function draw(){cells('current',[{text:'a = '+a,cls:a===20?'on':'gold'},{text:'b = '+b,cls:b===10?'on':'gold'},{text:'t = '+(temp??'∅'),cls:temp===10?'on':'empty'}]);$('#bt').disabled=temp===null;set('history',history.slice(-4).join('\\n')||'∅');set('explanation',t(a===20&&b===10?'ok':'wait'));$('#current').dataset.values=[a,b,temp].join(',');}for(const k of ['save','ab','ba','bt'])$('#'+k).onclick=()=>{if(k==='save')temp=a;if(k==='ab')a=b;if(k==='ba')b=a;if(k==='bt')b=temp;history.push(t(k)+' → ['+a+','+b+','+(temp??'∅')+']');draw()};$('#reset').onclick=()=>{a=10;b=20;temp=null;history=[];draw()};draw();","audio":false,"strings":{"ab":"a ← b","ba":"b ← a","bt":"b ← t","current":"Current locations","goal":"Parallel target","heading":"Can a later copy still read an overwritten old value?","history":"Executed writes","intro":"Goal: parallel a←b, b←a. Choose writes in any order; saving old a before overwriting it breaks the cycle.","ok":"Current state matches the parallel-copy target.","reset":"Reset","save":"t ← a","scope":"Two reusable locations, a=10,b=20, one temporary. Actions perform sequential copies; not general SSA destruction, critical-edge splitting or multi-cycle scheduling.","scopeLabel":"Model scope and assumptions","wait":"Target requires a=20,b=10; inspect which old values remain."}}
SSA values coexisting with mutable memory
LLVM's %p = alloca i32 defines the pointer value only once, after which memory can be stored to multiple times; each load produces a new SSA value. SSA constrains named values, not turning the entire heap into immutable data.
mem2reg converts suitable local slots to SSA values and φs; aliasing, address escaping, and unsupported accesses affect promotion. The frontend can first use alloca to express mutable local variables and then hand them over to the promotion process, avoiding the need to immediately implement full SSA construction. LLVM Mutable Variables Tutorial
Verification Checklist
Check for unique definitions, types, dominance relationships, correspondence between φs and predecessor edges, terminator instructions, and handling of unreachable blocks. When modifying the CFG, also update φ inputs; deleting an edge while keeping the corresponding input breaks the IR.