Definition decode_encode_val (v1: val) (chunk1 chunk2: memory_chunk) (v2: val) : Prop :=
match v1, chunk1, chunk2 with
| Vundef, _, _ => v2 = Vundef
| Vint n, Mint8signed, Mint8signed => v2 = Vint(Int.sign_ext 8 n)
| Vint n, Mint8unsigned, Mint8signed => v2 = Vint(Int.sign_ext 8 n)
| Vint n, Mint8signed, Mint8unsigned => v2 = Vint(Int.zero_ext 8 n)
| Vint n, Mint8unsigned, Mint8unsigned => v2 = Vint(Int.zero_ext 8 n)
| Vint n, Mint16signed, Mint16signed => v2 = Vint(Int.sign_ext 16 n)
| Vint n, Mint16unsigned, Mint16signed => v2 = Vint(Int.sign_ext 16 n)
| Vint n, Mint16signed, Mint16unsigned => v2 = Vint(Int.zero_ext 16 n)
| Vint n, Mint16unsigned, Mint16unsigned => v2 = Vint(Int.zero_ext 16 n)
| Vint n, Mint32, Mint32 => v2 = Vint n
| Vint n, Many32, Many32 => v2 = Vint n
| Vint n, Mint32, Mfloat32 => v2 = Vsingle(Float32.of_bits n)
| Vint n, Many64, Many64 => v2 = Vint n
| Vint n, (Mint64 | Mfloat32 | Mfloat64 | Many64), _ => v2 = Vundef
| Vint n, _, _ => True (**r nothing meaningful to say about v2 *)
| Vptr b ofs, (Mint32 | Many32), (Mint32 | Many32) => v2 = if Archi.ptr64 then Vundef else Vptr b ofs
| Vptr b ofs, Mint64, (Mint64 | Many64) => v2 = if Archi.ptr64 then Vptr b ofs else Vundef
| Vptr b ofs, Many64, Many64 => v2 = Vptr b ofs
| Vptr b ofs, Many64, Mint64 => v2 = if Archi.ptr64 then Vptr b ofs else Vundef
| Vptr b ofs, _, _ => v2 = Vundef
| Vlong n, Mint64, Mint64 => v2 = Vlong n
| Vlong n, Mint64, Mfloat64 => v2 = Vfloat(Float.of_bits n)
| Vlong n, Many64, Many64 => v2 = Vlong n
| Vlong n, (Mint8signed|Mint8unsigned|Mint16signed|Mint16unsigned|Mint32|Mfloat32|Mfloat64|Many32), _ => v2 = Vundef
| Vlong n, _, _ => True (**r nothing meaningful to say about v2 *)
| Vfloat f, Mfloat64, Mfloat64 => v2 = Vfloat f
| Vfloat f, Mfloat64, Mint64 => v2 = Vlong(Float.to_bits f)
| Vfloat f, Many64, Many64 => v2 = Vfloat f
| Vfloat f, (Mint8signed|Mint8unsigned|Mint16signed|Mint16unsigned|Mint32|Mfloat32|Mint64|Many32), _ => v2 = Vundef
| Vfloat f, _, _ => True   (* nothing interesting to say about v2 *)
| Vsingle f, Mfloat32, Mfloat32 => v2 = Vsingle f
| Vsingle f, Mfloat32, Mint32 => v2 = Vint(Float32.to_bits f)
| Vsingle f, Many32, Many32 => v2 = Vsingle f
| Vsingle f, Many64, Many64 => v2 = Vsingle f
| Vsingle f, (Mint8signed|Mint8unsigned|Mint16signed|Mint16unsigned|Mint32|Mint64|Mfloat64|Many64), _ => v2 = Vundef
| Vsingle f, _, _ => True (* nothing interesting to say about v2 *)
end.
Remark decode_val_undef:
forall bl chunk, decode_val chunk (Undef :: bl) = Vundef.
Remark proj_bytes_inj_value:
forall q v, proj_bytes (inj_value q v) = None.
Ltac solve_decode_encode_val_general :=
exact I || reflexivity ||
match goal with
| |- context [ if Archi.ptr64 then _ else _ ] => destruct Archi.ptr64 eqn:?
| |- context [ proj_bytes (inj_bytes _) ] => rewrite proj_inj_bytes
| |- context [ proj_bytes (inj_value _ _) ] => rewrite proj_bytes_inj_value
| |- context [ proj_value _ (inj_value _ _) ] => rewrite ?proj_inj_value, ?proj_inj_value_mismatch by congruence
| |- context [ Int.repr(decode_int (encode_int 1 (Int.unsigned _))) ] => rewrite decode_encode_int_1
| |- context [ Int.repr(decode_int (encode_int 2 (Int.unsigned _))) ] => rewrite decode_encode_int_2
| |- context [ Int.repr(decode_int (encode_int 4 (Int.unsigned _))) ] => rewrite decode_encode_int_4
| |- context [ Int64.repr(decode_int (encode_int 8 (Int64.unsigned _))) ] => rewrite decode_encode_int_8
| |- Vint (Int.sign_ext _ (Int.sign_ext _ _)) = Vint _ => f_equal; apply Int.sign_ext_idem; omega
| |- Vint (Int.zero_ext _ (Int.zero_ext _ _)) = Vint _ => f_equal; apply Int.zero_ext_idem; omega
| |- Vint (Int.sign_ext _ (Int.zero_ext _ _)) = Vint _ => f_equal; apply Int.sign_ext_zero_ext; omega
end.

Lemma decode_encode_val_similar:
forall v1 chunk1 chunk2 v2,
type_of_chunk chunk1 = type_of_chunk chunk2 ->
size_chunk chunk1 = size_chunk chunk2 ->
decode_encode_val v1 chunk1 chunk2 v2 ->
v2 = Val.load_result chunk2 v1.