Theory IRGraphFrames
subsection ‹Dynamic Frames›
text ‹
This theory defines two operators, 'unchanged' and 'changeonly',
that are useful for specifying which nodes in an IRGraph can change.
The dynamic framing idea originates from 'Dynamic Frames' in software verification,
started by Ioannis T. Kassios in "Dynamic frames: Support for framing,
dependencies and sharing without restrictions", In FM 2006.
›
theory IRGraphFrames
imports
Form
begin
fun unchanged :: "ID set ⇒ IRGraph ⇒ IRGraph ⇒ bool" where
"unchanged ns g1 g2 = (∀ n . n ∈ ns ⟶
(n ∈ ids g1 ∧ n ∈ ids g2 ∧ kind g1 n = kind g2 n ∧ stamp g1 n = stamp g2 n))"
fun changeonly :: "ID set ⇒ IRGraph ⇒ IRGraph ⇒ bool" where
"changeonly ns g1 g2 = (∀ n . n ∈ ids g1 ∧ n ∉ ns ⟶
(n ∈ ids g1 ∧ n ∈ ids g2 ∧ kind g1 n = kind g2 n ∧ stamp g1 n = stamp g2 n))"
lemma node_unchanged:
assumes "unchanged ns g1 g2"
assumes "nid ∈ ns"
shows "kind g1 nid = kind g2 nid"
using assms by simp
lemma other_node_unchanged:
assumes "changeonly ns g1 g2"
assumes "nid ∈ ids g1"
assumes "nid ∉ ns"
shows "kind g1 nid = kind g2 nid"
using assms by simp
text ‹Some notation for input nodes used›
inductive eval_uses:: "IRGraph ⇒ ID ⇒ ID ⇒ bool"
for g where
use0: "nid ∈ ids g
⟹ eval_uses g nid nid" |
use_inp: "nid' ∈ inputs g n
⟹ eval_uses g nid nid'" |
use_trans: "⟦eval_uses g nid nid';
eval_uses g nid' nid''⟧
⟹ eval_uses g nid nid''"
fun eval_usages :: "IRGraph ⇒ ID ⇒ ID set" where
"eval_usages g nid = {n ∈ ids g . eval_uses g nid n}"
lemma eval_usages_self:
assumes "nid ∈ ids g"
shows "nid ∈ eval_usages g nid"
using assms by (simp add: ids.rep_eq eval_uses.intros(1))
lemma not_in_g_inputs:
assumes "nid ∉ ids g"
shows "inputs g nid = {}"
proof -
have k: "kind g nid = NoNode"
using assms by (simp add: not_in_g)
then show ?thesis
by (simp add: k)
qed
lemma child_member:
assumes "n = kind g nid"
assumes "n ≠ NoNode"
assumes "List.member (inputs_of n) child"
shows "child ∈ inputs g nid"
by (metis in_set_member inputs.simps assms(1,3))
lemma child_member_in:
assumes "nid ∈ ids g"
assumes "List.member (inputs_of (kind g nid)) child"
shows "child ∈ inputs g nid"
by (metis child_member ids_some assms)
lemma inp_in_g:
assumes "n ∈ inputs g nid"
shows "nid ∈ ids g"
proof -
have "inputs g nid ≠ {}"
by (metis empty_iff empty_set assms)
then have "kind g nid ≠ NoNode"
by (metis not_in_g_inputs ids_some)
then show ?thesis
by (metis not_in_g)
qed
lemma inp_in_g_wf:
assumes "wf_graph g"
assumes "n ∈ inputs g nid"
shows "n ∈ ids g"
using assms wf_folds inp_in_g by blast
lemma kind_unchanged:
assumes "nid ∈ ids g1"
assumes "unchanged (eval_usages g1 nid) g1 g2"
shows "kind g1 nid = kind g2 nid"
proof -
show ?thesis
using assms eval_usages_self by simp
qed
lemma stamp_unchanged:
assumes "nid ∈ ids g1"
assumes "unchanged (eval_usages g1 nid) g1 g2"
shows "stamp g1 nid = stamp g2 nid"
by (meson assms eval_usages_self unchanged.elims(2))
lemma child_unchanged:
assumes "child ∈ inputs g1 nid"
assumes "unchanged (eval_usages g1 nid) g1 g2"
shows "unchanged (eval_usages g1 child) g1 g2"
by (smt assms eval_usages.simps mem_Collect_eq unchanged.simps use_inp use_trans)
lemma eval_usages:
assumes "us = eval_usages g nid"
assumes "nid' ∈ ids g"
shows "eval_uses g nid nid' ⟷ nid' ∈ us" (is "?P ⟷ ?Q")
using assms by (simp add: ids.rep_eq)
lemma inputs_are_uses:
assumes "nid' ∈ inputs g nid"
shows "eval_uses g nid nid'"
by (metis assms use_inp)
lemma inputs_are_usages:
assumes "nid' ∈ inputs g nid"
assumes "nid' ∈ ids g"
shows "nid' ∈ eval_usages g nid"
using assms by (simp add: inputs_are_uses)
lemma inputs_of_are_usages:
assumes "List.member (inputs_of (kind g nid)) nid'"
assumes "nid' ∈ ids g"
shows "nid' ∈ eval_usages g nid"
by (metis assms in_set_member inputs.elims inputs_are_usages)
lemma usage_includes_inputs:
assumes "us = eval_usages g nid"
assumes "ls = inputs g nid"
assumes "ls ⊆ ids g"
shows "ls ⊆ us"
using inputs_are_usages assms by blast
lemma elim_inp_set:
assumes "k = kind g nid"
assumes "k ≠ NoNode"
assumes "child ∈ set (inputs_of k)"
shows "child ∈ inputs g nid"
using assms by simp
lemma encode_in_ids:
assumes "g ⊢ nid ≃ e"
shows "nid ∈ ids g"
using assms apply (induction rule: rep.induct) by fastforce+
lemma eval_in_ids:
assumes "[g, m, p] ⊢ nid ↦ v"
shows "nid ∈ ids g"
using assms encode_in_ids by (auto simp add: encodeeval.simps)
lemma transitive_kind_same:
assumes "unchanged (eval_usages g1 nid) g1 g2"
shows "∀ nid' ∈ (eval_usages g1 nid) . kind g1 nid' = kind g2 nid'"
by (meson unchanged.elims(1) assms)
theorem stay_same_encoding:
assumes nc: "unchanged (eval_usages g1 nid) g1 g2"
assumes g1: "g1 ⊢ nid ≃ e"
assumes wf: "wf_graph g1"
shows "g2 ⊢ nid ≃ e"
proof -
have dom: "nid ∈ ids g1"
using g1 encode_in_ids by simp
show ?thesis
using g1 nc wf dom
proof (induction e rule: rep.induct)
case (ConstantNode n c)
then have "kind g2 n = ConstantNode c"
by (metis kind_unchanged)
then show ?case
using rep.ConstantNode by presburger
next
case (ParameterNode n i s)
then have "kind g2 n = ParameterNode i"
by (metis kind_unchanged)
then show ?case
by (metis ParameterNode.hyps(2) ParameterNode.prems(1,3) rep.ParameterNode stamp_unchanged)
next
case (ConditionalNode n c t f ce te fe)
then have "kind g2 n = ConditionalNode c t f"
by (metis kind_unchanged)
have "c ∈ eval_usages g1 n ∧ t ∈ eval_usages g1 n ∧ f ∈ eval_usages g1 n"
by (metis inputs_of_ConditionalNode ConditionalNode.hyps(1,2,3,4) encode_in_ids inputs.simps
inputs_are_usages list.set_intros(1) set_subset_Cons subset_code(1))
then show ?case
by (metis ConditionalNode.hyps(1) ConditionalNode.prems(1) IRNodes.inputs_of_ConditionalNode
‹kind g2 n = ConditionalNode c t f› child_unchanged inputs.simps list.set_intros(1)
local.ConditionalNode(5,6,7,9) rep.ConditionalNode set_subset_Cons subset_code(1)
unchanged.elims(2))
next
case (AbsNode n x xe)
then have "kind g2 n = AbsNode x"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n"
by (metis inputs_of_AbsNode AbsNode.hyps(1,2) encode_in_ids inputs.simps inputs_are_usages
list.set_intros(1))
then show ?case
by (metis AbsNode.IH AbsNode.hyps(1) AbsNode.prems(1,3) IRNodes.inputs_of_AbsNode rep.AbsNode
‹kind g2 n = AbsNode x› child_member_in child_unchanged local.wf member_rec(1)
unchanged.simps)
next
case (ReverseBytesNode n x xe)
then have "kind g2 n = ReverseBytesNode x"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n"
by (metis IRNodes.inputs_of_ReverseBytesNode ReverseBytesNode.hyps(1,2) encode_in_ids
inputs.simps inputs_are_usages list.set_intros(1))
then show ?case
by (metis IRNodes.inputs_of_ReverseBytesNode ReverseBytesNode.IH ReverseBytesNode.hyps(1,2)
ReverseBytesNode.prems(1) child_member_in child_unchanged local.wf member_rec(1)
‹kind g2 n = ReverseBytesNode x› encode_in_ids rep.ReverseBytesNode)
next
case (BitCountNode n x xe)
then have "kind g2 n = BitCountNode x"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n"
by (metis BitCountNode.hyps(1,2) IRNodes.inputs_of_BitCountNode encode_in_ids inputs.simps
inputs_are_usages list.set_intros(1))
then show ?case
by (metis BitCountNode.IH BitCountNode.hyps(1,2) BitCountNode.prems(1) member_rec(1) local.wf
IRNodes.inputs_of_BitCountNode ‹kind g2 n = BitCountNode x› encode_in_ids rep.BitCountNode
child_member_in child_unchanged)
next
case (NotNode n x xe)
then have "kind g2 n = NotNode x"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n"
by (metis inputs_of_NotNode NotNode.hyps(1,2) encode_in_ids inputs.simps inputs_are_usages
list.set_intros(1))
then show ?case
by (metis NotNode.IH NotNode.hyps(1) NotNode.prems(1,3) IRNodes.inputs_of_NotNode rep.NotNode
‹kind g2 n = NotNode x› child_member_in child_unchanged local.wf member_rec(1)
unchanged.simps)
next
case (NegateNode n x xe)
then have "kind g2 n = NegateNode x"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n"
by (metis inputs_of_NegateNode NegateNode.hyps(1,2) encode_in_ids inputs.simps inputs_are_usages
list.set_intros(1))
then show ?case
by (metis IRNodes.inputs_of_NegateNode NegateNode.IH NegateNode.hyps(1) NegateNode.prems(1,3)
‹kind g2 n = NegateNode x› child_member_in child_unchanged local.wf member_rec(1)
rep.NegateNode unchanged.elims(1))
next
case (LogicNegationNode n x xe)
then have "kind g2 n = LogicNegationNode x"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n"
by (metis inputs_of_LogicNegationNode inputs_of_are_usages LogicNegationNode.hyps(1,2)
encode_in_ids member_rec(1))
then show ?case
by (metis IRNodes.inputs_of_LogicNegationNode LogicNegationNode.IH LogicNegationNode.hyps(1,2)
LogicNegationNode.prems(1) ‹kind g2 n = LogicNegationNode x› child_unchanged encode_in_ids
inputs.simps list.set_intros(1) local.wf rep.LogicNegationNode)
next
case (AddNode n x y xe ye)
then have "kind g2 n = AddNode x y"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n ∧ y ∈ eval_usages g1 n"
by (metis AddNode.hyps(1,2,3) IRNodes.inputs_of_AddNode encode_in_ids in_mono inputs.simps
inputs_are_usages list.set_intros(1) set_subset_Cons)
then show ?case
by (metis AddNode.IH(1,2) AddNode.hyps(1,2,3) AddNode.prems(1) IRNodes.inputs_of_AddNode
‹kind g2 n = AddNode x y› child_unchanged encode_in_ids in_set_member inputs.simps
local.wf member_rec(1) rep.AddNode)
next
case (MulNode n x y xe ye)
then have "kind g2 n = MulNode x y"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n ∧ y ∈ eval_usages g1 n"
by (metis MulNode.hyps(1,2,3) IRNodes.inputs_of_MulNode encode_in_ids in_mono inputs.simps
inputs_are_usages list.set_intros(1) set_subset_Cons)
then show ?case
by (metis ‹kind g2 n = MulNode x y› child_unchanged inputs.simps list.set_intros(1) rep.MulNode
set_subset_Cons subset_iff unchanged.elims(2) inputs_of_MulNode MulNode(1,4,5,6,7))
next
case (DivNode n x y xe ye)
then have "kind g2 n = SignedFloatingIntegerDivNode x y"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n ∧ y ∈ eval_usages g1 n"
by (metis DivNode.hyps(1,2,3) IRNodes.inputs_of_SignedFloatingIntegerDivNode encode_in_ids in_mono inputs.simps
inputs_are_usages list.set_intros(1) set_subset_Cons)
then show ?case
by (metis ‹kind g2 n = SignedFloatingIntegerDivNode x y› child_unchanged inputs.simps list.set_intros(1) rep.DivNode
set_subset_Cons subset_iff unchanged.elims(2) inputs_of_SignedFloatingIntegerDivNode DivNode(1,4,5,6,7))
next
case (ModNode n x y xe ye)
then have "kind g2 n = SignedFloatingIntegerRemNode x y"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n ∧ y ∈ eval_usages g1 n"
by (metis ModNode.hyps(1,2,3) IRNodes.inputs_of_SignedFloatingIntegerRemNode encode_in_ids in_mono inputs.simps
inputs_are_usages list.set_intros(1) set_subset_Cons)
then show ?case
by (metis ‹kind g2 n = SignedFloatingIntegerRemNode x y› child_unchanged inputs.simps list.set_intros(1) rep.ModNode
set_subset_Cons subset_iff unchanged.elims(2) inputs_of_SignedFloatingIntegerRemNode ModNode(1,4,5,6,7))
next
case (SubNode n x y xe ye)
then have "kind g2 n = SubNode x y"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n ∧ y ∈ eval_usages g1 n"
by (metis SubNode.hyps(1,2,3) IRNodes.inputs_of_SubNode encode_in_ids in_mono inputs.simps
inputs_are_usages list.set_intros(1) set_subset_Cons)
then show ?case
by (metis ‹kind g2 n = SubNode x y› child_member child_unchanged encode_in_ids ids_some SubNode
member_rec(1) rep.SubNode inputs_of_SubNode)
next
case (AndNode n x y xe ye)
then have "kind g2 n = AndNode x y"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n ∧ y ∈ eval_usages g1 n"
by (metis AndNode.hyps(1,2,3) IRNodes.inputs_of_AndNode encode_in_ids in_mono inputs.simps
inputs_are_usages list.set_intros(1) set_subset_Cons)
then show ?case
by (metis AndNode(1,4,5,6,7) inputs_of_AndNode ‹kind g2 n = AndNode x y› child_unchanged
inputs.simps list.set_intros(1) rep.AndNode set_subset_Cons subset_iff unchanged.elims(2))
next
case (OrNode n x y xe ye)
then have "kind g2 n = OrNode x y"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n ∧ y ∈ eval_usages g1 n"
by (metis OrNode.hyps(1,2,3) IRNodes.inputs_of_OrNode encode_in_ids in_mono inputs.simps
inputs_are_usages list.set_intros(1) set_subset_Cons)
then show ?case
by (metis inputs_of_OrNode ‹kind g2 n = OrNode x y› child_unchanged encode_in_ids rep.OrNode
child_member ids_some member_rec(1) OrNode)
next
case (XorNode n x y xe ye)
then have "kind g2 n = XorNode x y"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n ∧ y ∈ eval_usages g1 n"
by (metis XorNode.hyps(1,2,3) IRNodes.inputs_of_XorNode encode_in_ids in_mono inputs.simps
inputs_are_usages list.set_intros(1) set_subset_Cons)
then show ?case
by (metis inputs_of_XorNode ‹kind g2 n = XorNode x y› child_member child_unchanged rep.XorNode
encode_in_ids ids_some member_rec(1) XorNode)
next
case (ShortCircuitOrNode n x y xe ye)
then have "kind g2 n = ShortCircuitOrNode x y"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n ∧ y ∈ eval_usages g1 n"
by (metis ShortCircuitOrNode.hyps(1,2,3) IRNodes.inputs_of_ShortCircuitOrNode inputs_are_usages
in_mono inputs.simps list.set_intros(1) set_subset_Cons encode_in_ids)
then show ?case
by (metis ShortCircuitOrNode inputs_of_ShortCircuitOrNode ‹kind g2 n = ShortCircuitOrNode x y›
child_member child_unchanged encode_in_ids ids_some member_rec(1) rep.ShortCircuitOrNode)
next
case (LeftShiftNode n x y xe ye)
then have "kind g2 n = LeftShiftNode x y"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n ∧ y ∈ eval_usages g1 n"
by (metis LeftShiftNode.hyps(1,2,3) IRNodes.inputs_of_LeftShiftNode encode_in_ids inputs.simps
inputs_are_usages list.set_intros(1) set_subset_Cons in_mono)
then show ?case
by (metis LeftShiftNode inputs_of_LeftShiftNode ‹kind g2 n = LeftShiftNode x y› child_unchanged
encode_in_ids ids_some member_rec(1) rep.LeftShiftNode child_member)
next
case (RightShiftNode n x y xe ye)
then have "kind g2 n = RightShiftNode x y"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n ∧ y ∈ eval_usages g1 n"
by (metis RightShiftNode.hyps(1,2,3) IRNodes.inputs_of_RightShiftNode encode_in_ids inputs.simps
inputs_are_usages list.set_intros(1) set_subset_Cons in_mono)
then show ?case
by (metis RightShiftNode inputs_of_RightShiftNode ‹kind g2 n = RightShiftNode x y› child_member
child_unchanged encode_in_ids ids_some member_rec(1) rep.RightShiftNode)
next
case (UnsignedRightShiftNode n x y xe ye)
then have "kind g2 n = UnsignedRightShiftNode x y"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n ∧ y ∈ eval_usages g1 n"
by (metis UnsignedRightShiftNode.hyps(1,2,3) IRNodes.inputs_of_UnsignedRightShiftNode in_mono
encode_in_ids inputs.simps inputs_are_usages list.set_intros(1) set_subset_Cons)
then show ?case
by (metis UnsignedRightShiftNode inputs_of_UnsignedRightShiftNode child_member child_unchanged
‹kind g2 n = UnsignedRightShiftNode x y› encode_in_ids ids_some rep.UnsignedRightShiftNode
member_rec(1))
next
case (IntegerBelowNode n x y xe ye)
then have "kind g2 n = IntegerBelowNode x y"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n ∧ y ∈ eval_usages g1 n"
by (metis IntegerBelowNode.hyps(1,2,3) IRNodes.inputs_of_IntegerBelowNode encode_in_ids in_mono
inputs.simps inputs_are_usages list.set_intros(1) set_subset_Cons)
then show ?case
by (metis inputs_of_IntegerBelowNode ‹kind g2 n = IntegerBelowNode x y› rep.IntegerBelowNode
child_member child_unchanged encode_in_ids ids_some member_rec(1) IntegerBelowNode)
next
case (IntegerEqualsNode n x y xe ye)
then have "kind g2 n = IntegerEqualsNode x y"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n ∧ y ∈ eval_usages g1 n"
by (metis IntegerEqualsNode.hyps(1,2,3) IRNodes.inputs_of_IntegerEqualsNode inputs_are_usages
in_mono inputs.simps encode_in_ids list.set_intros(1) set_subset_Cons)
then show ?case
by (metis inputs_of_IntegerEqualsNode ‹kind g2 n = IntegerEqualsNode x y› rep.IntegerEqualsNode
child_member child_unchanged encode_in_ids ids_some member_rec(1) IntegerEqualsNode)
next
case (IntegerLessThanNode n x y xe ye)
then have "kind g2 n = IntegerLessThanNode x y"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n ∧ y ∈ eval_usages g1 n"
by (metis IntegerLessThanNode.hyps(1,2,3) IRNodes.inputs_of_IntegerLessThanNode encode_in_ids
in_mono inputs.simps inputs_are_usages list.set_intros(1) set_subset_Cons)
then show ?case
by (metis rep.IntegerLessThanNode inputs_of_IntegerLessThanNode child_unchanged encode_in_ids
‹kind g2 n = IntegerLessThanNode x y› child_member member_rec(1) IntegerLessThanNode
ids_some)
next
case (IntegerTestNode n x y xe ye)
then have "kind g2 n = IntegerTestNode x y"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n ∧ y ∈ eval_usages g1 n"
by (metis IntegerTestNode.hyps IRNodes.inputs_of_IntegerTestNode encode_in_ids
in_mono inputs.simps inputs_are_usages list.set_intros(1) set_subset_Cons)
then show ?case
by (metis rep.IntegerTestNode inputs_of_IntegerTestNode child_unchanged encode_in_ids
‹kind g2 n = IntegerTestNode x y› child_member member_rec(1) IntegerTestNode ids_some)
next
case (IntegerNormalizeCompareNode n x y xe ye)
then have "kind g2 n = IntegerNormalizeCompareNode x y"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n ∧ y ∈ eval_usages g1 n"
by (metis IRNodes.inputs_of_IntegerNormalizeCompareNode IntegerNormalizeCompareNode.hyps(1,2,3)
encode_in_ids in_set_member inputs.simps inputs_are_usages member_rec(1))
then show ?case
by (metis IRNodes.inputs_of_IntegerNormalizeCompareNode IntegerNormalizeCompareNode.IH(1,2)
IntegerNormalizeCompareNode.hyps(1,2,3) IntegerNormalizeCompareNode.prems(1) inputs.simps
‹kind (g2::IRGraph) (n::nat) = IntegerNormalizeCompareNode (x::nat) (y::nat)› local.wf
encode_in_ids list.set_intros(1) rep.IntegerNormalizeCompareNode set_subset_Cons in_mono
child_unchanged)
next
case (IntegerMulHighNode n x y xe ye)
then have "kind g2 n = IntegerMulHighNode x y"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n"
by (metis IRNodes.inputs_of_IntegerMulHighNode IntegerMulHighNode.hyps(1,2) encode_in_ids
inputs_of_are_usages member_rec(1))
then show ?case
by (metis inputs_of_IntegerMulHighNode IntegerMulHighNode.IH(1,2) IntegerMulHighNode.hyps(1,2,3)
IntegerMulHighNode.prems(1) child_unchanged encode_in_ids inputs.simps list.set_intros(1,2)
‹kind (g2::IRGraph) (n::nat) = IntegerMulHighNode (x::nat) (y::nat)› rep.IntegerMulHighNode
local.wf)
next
case (NarrowNode n ib rb x xe)
then have "kind g2 n = NarrowNode ib rb x"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n"
by (metis NarrowNode.hyps(1,2) IRNodes.inputs_of_NarrowNode inputs_are_usages encode_in_ids
list.set_intros(1) inputs.simps)
then show ?case
by (metis NarrowNode(1,3,4,5) inputs_of_NarrowNode ‹kind g2 n = NarrowNode ib rb x› inputs.elims
child_unchanged list.set_intros(1) rep.NarrowNode unchanged.simps)
next
case (SignExtendNode n ib rb x xe)
then have "kind g2 n = SignExtendNode ib rb x"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n"
by (metis inputs_of_SignExtendNode SignExtendNode.hyps(1,2) inputs_are_usages encode_in_ids
list.set_intros(1) inputs.simps)
then show ?case
by (metis SignExtendNode(1,3,4,5,6) inputs_of_SignExtendNode in_set_member list.set_intros(1)
‹kind g2 n = SignExtendNode ib rb x› child_member_in child_unchanged rep.SignExtendNode
unchanged.elims(2))
next
case (ZeroExtendNode n ib rb x xe)
then have "kind g2 n = ZeroExtendNode ib rb x"
by (metis kind_unchanged)
then have "x ∈ eval_usages g1 n"
by (metis ZeroExtendNode.hyps(1,2) IRNodes.inputs_of_ZeroExtendNode encode_in_ids inputs.simps
inputs_are_usages list.set_intros(1))
then show ?case
by (metis ZeroExtendNode(1,3,4,5,6) inputs_of_ZeroExtendNode child_unchanged unchanged.simps
‹kind g2 n = ZeroExtendNode ib rb x› child_member_in rep.ZeroExtendNode member_rec(1))
next
case (LeafNode n s)
then show ?case
by (metis kind_unchanged rep.LeafNode stamp_unchanged)
next
case (PiNode n n' gu)
then have "kind g2 n = PiNode n' gu"
by (metis kind_unchanged)
then show ?case
by (metis PiNode.IH ‹kind (g2) (n) = PiNode (n') (gu)› child_unchanged encode_in_ids rep.PiNode
inputs.elims list.set_intros(1)PiNode.hyps PiNode.prems(1,2) IRNodes.inputs_of_PiNode)
next
case (RefNode n n')
then have "kind g2 n = RefNode n'"
by (metis kind_unchanged)
then have "n' ∈ eval_usages g1 n"
by (metis IRNodes.inputs_of_RefNode RefNode.hyps(1,2) inputs_are_usages list.set_intros(1)
inputs.elims encode_in_ids)
then show ?case
by (metis IRNodes.inputs_of_RefNode RefNode.IH RefNode.hyps(1,2) RefNode.prems(1) inputs.elims
‹kind g2 n = RefNode n'› child_unchanged encode_in_ids list.set_intros(1) rep.RefNode
local.wf)
next
case (IsNullNode n v)
then have "kind g2 n = IsNullNode v"
by (metis kind_unchanged)
then show ?case
by (metis IRNodes.inputs_of_IsNullNode IsNullNode.IH IsNullNode.hyps(1,2) IsNullNode.prems(1)
‹kind g2 n = IsNullNode v› child_unchanged encode_in_ids inputs.simps list.set_intros(1)
local.wf rep.IsNullNode)
qed
qed
theorem stay_same:
assumes nc: "unchanged (eval_usages g1 nid) g1 g2"
assumes g1: "[g1, m, p] ⊢ nid ↦ v1"
assumes wf: "wf_graph g1"
shows "[g2, m, p] ⊢ nid ↦ v1"
proof -
have nid: "nid ∈ ids g1"
using g1 eval_in_ids by simp
then have "nid ∈ eval_usages g1 nid"
using eval_usages_self by simp
then have kind_same: "kind g1 nid = kind g2 nid"
using nc node_unchanged by blast
obtain e where e: "(g1 ⊢ nid ≃ e) ∧ ([m,p] ⊢ e ↦ v1)"
using g1 by (auto simp add: encodeeval.simps)
then have val: "[m,p] ⊢ e ↦ v1"
by (simp add: g1 encodeeval.simps)
then show ?thesis
using e nc unfolding encodeeval.simps
proof (induct e v1 arbitrary: nid rule: "evaltree.induct")
case (ConstantExpr c)
then show ?case
by (meson local.wf stay_same_encoding)
next
case (ParameterExpr i s)
have "g2 ⊢ nid ≃ ParameterExpr i s"
by (meson local.wf stay_same_encoding ParameterExpr)
then show ?case
by (meson ParameterExpr.hyps evaltree.ParameterExpr)
next
case (ConditionalExpr ce cond branch te fe v)
then have "g2 ⊢ nid ≃ ConditionalExpr ce te fe"
using local.wf stay_same_encoding by presburger
then show ?case
by (meson ConditionalExpr.prems(1))
next
case (UnaryExpr xe v op)
then show ?case
using local.wf stay_same_encoding by blast
next
case (BinaryExpr xe x ye y op)
then show ?case
using local.wf stay_same_encoding by blast
next
case (LeafExpr val nid s)
then show ?case
by (metis local.wf stay_same_encoding)
qed
qed
lemma add_changed:
assumes "gup = add_node new k g"
shows "changeonly {new} g gup"
by (simp add: assms add_node.rep_eq kind.rep_eq stamp.rep_eq)
lemma disjoint_change:
assumes "changeonly change g gup"
assumes "nochange = ids g - change"
shows "unchanged nochange g gup"
using assms by simp
lemma add_node_unchanged:
assumes "new ∉ ids g"
assumes "nid ∈ ids g"
assumes "gup = add_node new k g"
assumes "wf_graph g"
shows "unchanged (eval_usages g nid) g gup"
proof -
have "new ∉ (eval_usages g nid)"
using assms by simp
then have "changeonly {new} g gup"
using assms add_changed by simp
then show ?thesis
using assms by auto
qed
lemma eval_uses_imp:
"((nid' ∈ ids g ∧ nid = nid')
∨ nid' ∈ inputs g nid
∨ (∃nid'' . eval_uses g nid nid'' ∧ eval_uses g nid'' nid'))
⟷ eval_uses g nid nid'"
by (meson eval_uses.simps)
lemma wf_use_ids:
assumes "wf_graph g"
assumes "nid ∈ ids g"
assumes "eval_uses g nid nid'"
shows "nid' ∈ ids g"
using assms(3) apply (induction rule: eval_uses.induct) using assms(1) inp_in_g_wf by auto
lemma no_external_use:
assumes "wf_graph g"
assumes "nid' ∉ ids g"
assumes "nid ∈ ids g"
shows "¬(eval_uses g nid nid')"
proof -
have 0: "nid ≠ nid'"
using assms by auto
have inp: "nid' ∉ inputs g nid"
using assms inp_in_g_wf by auto
have rec_0: "∄n . n ∈ ids g ∧ n = nid'"
using assms by simp
have rec_inp: "∄n . n ∈ ids g ∧ n ∈ inputs g nid'"
using assms(2) by (simp add: inp_in_g)
have rec: "∄nid'' . eval_uses g nid nid'' ∧ eval_uses g nid'' nid'"
using wf_use_ids assms by blast
from inp 0 rec show ?thesis
using eval_uses_imp by blast
qed
end