Fil-C on Nix

Filnix wiki

the formal campaign

rocq/backend/Copy.v

# Copy propagation

As copy.pl's copy_module/2, on terms: in each function in strict SSA form, a copy let(tmp(D), K, copy, [Src]) of a value of the same class goes, and every use of D reads what Src stands for; then each phi whose arguments, apart from itself, are one value goes the same way, which can make another phi trivial. A function that is not in strict SSA form, or that calls setjmp, is left as it is.

What copy.pl does besides is left out, as in Pizlonate.v: the context records and their sites. copy_module gives None where copy_module/2 fails or throws: an item, an instruction, a value or a jump of no known shape, or a jump to a label no block has. The gate (tests/promote.sh) holds the result to the term nanofilpromote − terms prints.

From Stdlib Require Import String ZArith List Bool
From Nanofil Require Import Term Maps Semantics Cfg
From Backend Require Import Text Order Pizlonate Liveness TermCfg
Import ListNotations
Open Scope string_scope
Open Scope Z_scope
Open Scope list_scope

String equality, written as Prolog's ==.

27Notation a == b ≔ String.eqba b (at level 70)

Classes

The temporaries the instruction i defines, each with the class of its definition; an output of an asm_fixed is a w.

33Definition inst_classesi : term : listterm × term ≔
let result r ≔
match r with
TAppf t; k
⇒
f == "result"
→
mapλd ⇒ d, k tmp_namet
else
[ ]
_
⇒
[ ]
in
match i with
TAppf xs
⇒
f == "let"
→
match xs with
d; k; _; _
⇒
mapλd ⇒ d, k tmp_named
_
⇒
[ ]
f == "call"
→
match xs with
r; _; _
⇒
match r with
⇒
g == "tuple"
→
flat_mapresult rs
else
[ ]
_
⇒
resultr
_
⇒
[ ]
f == "asm_fixed"
→
mapλd ⇒ d, TAtom"w" inst_defsi
else
[ ]
_
⇒
[ ]

As temp_classes(Params, Blocks, Classes): the class of each temporary's definition.

59Definition temp_classesparams : listterm bs : listtblock : nmapterm ≔
flat_map
λ p  ⇒
match p with
TAppf k; t
⇒
f == "param"
→
mapλd ⇒ d, k tmp_namet
else
[ ]
_
⇒
[ ]
params
++
flat_map
λ b  ⇒
flat_map
λ p  ⇒
match p with
TAppf d; k; _
⇒
f == "phi"
→
mapλd ⇒ d, k tmp_named
else
[ ]
_
⇒
[ ]
++
bs

As copy_value(Src, K, Classes, V): what a copy at the class k of the value src can be replaced by: a temporary of that class, or a constant at w or l, reduced to the class's width.

78Definition copy_valueclasses : nmapterm k src : term : optionterm ≔
match src with
TAppf x
⇒
f == "tmp"
→
match nm_findx classes with
Somek′
⇒
term_eqbk′ k
→
Somesrc
else
None
None
⇒
None
f == "const"
→
match x with
⇒
is_atom"w" k
→
SomeTApp"const" TIntn mod 2 ^ 32
is_atom"l" k
→
SomeTApp"const" TIntn mod 2 ^ 64
else
None
_
⇒
None
else
None
_
⇒
None

Chains

As copy_chain/6: following the copies, and the values already in reps, from the value v ends at a value that is not copied; the path has the temporaries on the way that reps lacks. A chain has at most as many links as there are copies, the fuel.

104Fixpoint copy_chainfuel : nat copies reps : nmapterm v : term path : listterm : optionlistterm × term ≔
match fuel with
O
⇒
None
Sfuel′
⇒
match tmp_namev with
t
⇒
match nm_findt reps with
Somev′
⇒
Somepath, v′
None
⇒
match nm_findt copies with
Somesrc
⇒
copy_chainfuel′ copies reps src t :: path
None
⇒
Somepath, v
_
⇒
Somepath, v

As foldl(copy_reps(Copies), Pairs, Empty, Reps): the value that replaces each temporary of pairs, the end of its chain.

125Definition chain_repspairs : listterm × term : optionnmapterm ≔
let copies ≔ nm_of_listpairs in
let fuel ≔ SSlengthpairs in
fold_left
λ acc p  ⇒
let* reps ≔ acc in
let* r ≔ copy_chainfuel copies reps tmpfstp [ ] in
Somefold_leftλm t ⇒ nm_addt sndr m fstr reps
pairs

Substitution

As value_reps(V0, Reps, V): what replaces the value v, or v itself.

138Definition value_repsreps : nmapterm v : term : optionterm ≔
match v with
TAppf x
⇒
f == "tmp"
→
Some
match nm_findx reps with
Somev′
⇒
v′
None
⇒
v
f == "const" || f == "global"
→
Somev
else
None
_
⇒
None

As inst_reps(Inst0, Reps, Inst).

148Definition inst_repsreps : nmapterm i : term : optionterm ≔
match i with
⇒
a == "fence"
→
Somei
else
None
TAppf xs
⇒
f == "loc"
→
arity2 xs
→
Somei
else
None
f == "let"
→
match xs with
d; k; o; TListvs
⇒
let* vs′ ≔ map_optionvalue_repsreps vs in
SomeTAppf d; k; o; TListvs′
_
⇒
None
f == "store" || f == "atomic_store"
→
match xs with
w; v; a
⇒
let* v′ ≔ value_repsreps v in
let* a′ ≔ value_repsreps a in
SomeTAppf w; v′; a′
_
⇒
None
f == "access"
→
match xs with
k; a; s; al
⇒
let* a′ ≔ value_repsreps a in
SomeTAppf k; a′; s; al
_
⇒
None
f == "asm_fixed"
→
match xs with
m; TListins; outs
⇒
let* ins′ ≔
λ p  ⇒
let* rv ≔ pair_partsp in
let* v′ ≔ value_repsreps sndrv in
SomeTApp"-" fstrv; v′
ins
in
SomeTAppf m; TListins′; outs
_
⇒
None
f == "call"
→
match xs with
r; g; TListargs
⇒
let* g′ ≔ value_repsreps g in
let* args′ ≔
λ a  ⇒
match a with
TApph k; v
⇒
h == "arg"
→
let* v′ ≔ value_repsreps v in
SomeTApph k; v′
else
None
_
⇒
None
args
in
SomeTAppf r; g′; TListargs′
_
⇒
None
else
None
_
⇒
None

As jump_reps(Jump0, Reps, Jump).

202Definition jump_repsreps : nmapterm j : term : optionterm ≔
match j with
⇒
a == "ret" || a == "unreachable"
→
Somej
else
None
TAppf xs
⇒
f == "goto"
→
arity1 xs
→
Somej
else
None
f == "branch"
→
match xs with
v; t; e
⇒
let* v′ ≔ value_repsreps v in
SomeTAppf v′; t; e
_
⇒
None
f == "ret"
→
match xs with
v
⇒
let* v′ ≔ value_repsreps v in
SomeTAppf v′
_
⇒
None
f == "rets"
→
match xs with
⇒
let* vs′ ≔ map_optionvalue_repsreps vs in
SomeTAppf TListvs′
_
⇒
None
else
None
_
⇒
None

Whether the term t defines, as a phi or as a copy, a temporary that reps replaces.

228Definition replacedreps : nmapterm t : term : bool ≔
match t with
TAppf d; _; x
⇒
f == "phi" && existsbλd ⇒ nm_memd reps tmp_named
TAppf d; _; o; _
⇒
f == "let" && is_atom"copy" o && existsbλd ⇒ nm_memd reps tmp_named
_
⇒
false

As reps_block(Reps, Block0, Block, _): the block b without the phis and the copies whose temporary reps replaces, and with every use of such a temporary replaced by its value.

240Definition reps_blockreps : nmapterm b : tblock : optiontblock ≔
let* phis ≔
λ p  ⇒
match p with
TAppf d; k; TListargs
⇒
f == "phi"
→
let* args′ ≔
λ a  ⇒
let* lv ≔ pair_partsa in
let* v′ ≔ value_repsreps sndlv in
SomeTApp"-" fstlv; v′
args
in
SomeTAppf d; k; TListargs′
else
None
_
⇒
None
filterλp ⇒ negbreplacedreps p tb_phisb
in
let* insts ≔ map_optioninst_repsreps filterλi ⇒ negbreplacedreps i tb_instsb in
let* j ≔ jump_repsreps tb_jumpb in
SomemkTBlocktb_labelb phis insts j

Trivial phis

As phi_worklist_reps/5: the value of each trivial phi, found by a worklist over the phi temporaries pending, an ordset. phis has the operand values of each phi not yet simplified, and users the ordset of the phis that read each temporary. A phi is trivial when its operands other than itself are one value; the phis that read it then read that value, and are looked at again. The result is in the order the phis were simplified, the last first; the caller puts it in the order of the temporaries, an assoc's. Each step takes a temporary off pending or simplifies a phi, and only simplifying adds any, at most all the phis: the fuel.

270Fixpoint phi_worklistfuel : nat pending : names phis : nmaplistterm users : nmapnames found : listterm × term : optionlistterm × term ≔
match fuel with
O
⇒
None
Sfuel′
⇒
match pending with
[ ]
⇒
Somefound
d :: pending0
⇒
let self ≔ tmpd in
match option_mapλvs ⇒ sortterm_compare filterλv ⇒ negbterm_eqbv self vs nm_findd phis with
Somev
⇒
let phis1 ≔ nm_removed phis in
let live ≔ filterλu ⇒ nm_memu phis1 names_atusers d in
let phis2 ≔
fold_left
λ m u  ⇒
match nm_findu m with
Somevs
⇒
map
λ v0  ⇒
term_eqbv0 self
→
v
else
v0
vs
m
None
⇒
m
live
phis1
in
let users′ ≔
match tmp_namev with
s
⇒
nm_mems phis2
→
nm_adds nunionnames_atusers s live users
else
users
_
⇒
users
in
phi_worklistfuel′ nunionpending0 live phis2 users′ d, v :: found
_
⇒
phi_worklistfuel′ pending0 phis users found

As trivial_phis/6: the blocks bs without their trivial phis. Only a phi of a reachable block whose every argument a copy could stand for (copy_value) is looked at.

307Definition trivial_phisclasses : nmapterm reach : nmapunit bs : listtblock : optionlisttblock ≔
let pairs ≔
flat_map
λ b  ⇒
→
flat_map
λ p  ⇒
match p with
TAppf d; k; TListargs
⇒
f == "phi"
→
match tmp_named, map_optionλa ⇒ let* lv ≔ pair_partsa in copy_valueclasses k sndlv args with
d, Somevs
⇒
d, vs
_, _
⇒
[ ]
else
[ ]
_
⇒
[ ]
else
[ ]
bs
in
let edges ≔ sortλa b ⇒ thencterm_comparefsta fstb term_comparesnda sndb flat_mapλp ⇒ mapλs ⇒ s, fstp flat_maptmp_name sndp pairs in
let users ≔ fold_leftλm e ⇒ nm_addfste snde :: names_atm fste m rev'edges nm_empty in
let n ≔ lengthpairs in
let* found ≔ phi_worklistSn + n × n nsortmapfst pairs nm_of_listpairs users [ ] in
let* reps ≔ chain_repsmsortλa b ⇒ term_comparefsta fstb found in

Functions and modules

As copy_context/4, without the records: the blocks bs of a function with the given params, its copies and trivial phis gone.

342Definition copy_blocksfilc : bool params : listterm bs : listtblock : optionlisttblock ≔
→
Somebs
else
let* g ≔ term_cfgbs in
let* idom ≔ cfg_idomsg in
negbstrict_ssadef_countsparams bs params bs g idom
→
Somebs
else
let classes ≔ temp_classesparams bs in
let reach ≔ reachedg in
let copies ≔
flat_map
λ b  ⇒
→
flat_map
λ i  ⇒
match i with
TAppf d; k; o; TListsrc
⇒
f == "let" && is_atom"copy" o
→
match tmp_named, copy_valueclasses k src with
d, Somev
⇒
d, v
_, _
⇒
[ ]
else
[ ]
_
⇒
[ ]
else
[ ]
bs
in
let* reps ≔ chain_repscopies in
let* copied ≔ map_optionreps_blockreps bs in
trivial_phisclasses reach copied

As copy_module/2, without the context items.

369Definition copy_modulem : term : optionterm ≔

A copy goes, and its use reads the source.

372Example copy_goes: copy_moduleTApp"module" TListTApp"func" TAtom"f"; TAtom"export"; TAtom"w"; TListTApp"param" TAtom"w"; tmpTAtom"a"; TListTApp"block" TAtom"top"; TList[ ]; TListTApp"let" tmpTAtom"x"; TAtom"w"; TAtom"copy"; TListtmpTAtom"a"; TApp"ret" tmpTAtom"x" = SomeTApp"module" TListTApp"func" TAtom"f"; TAtom"export"; TAtom"w"; TListTApp"param" TAtom"w"; tmpTAtom"a"; TListTApp"block" TAtom"top"; TList[ ]; TList[ ]; TApp"ret" tmpTAtom"a"
Proof 1 step Qed
reflexivity