(** The validation algorithm used here is described in
  "Validating register allocation and spilling",
  by Silvain Rideau and Xavier Leroy,
  in Compiler Construction (CC 2010), LNCS 6011, Springer, 2010. *)

(** * Structural checks *)

(** As a first pass, we check the LTL code returned by the external oracle
  against the original RTL code for structural conformance.
  Each RTL instruction was transformed into a LTL basic block whose
  shape must agree with the RTL instruction.  For example, if the RTL
  instruction is [Istore(Mint32, addr, args, src, s)], the LTL basic block
  must be of the following shape:
- zero, one or several "move" instructions
- a store instruction [Lstore(Mint32, addr, args', src')]
- a [Lbranch s] instruction.

  The [block_shape] type below describes all possible cases of structural
  maching between an RTL instruction and an LTL basic block.
*)

Inductive move: Type :=
  | MV (src dst: loc)
  | MVmakelong (src1 src2 dst: mreg)
  | MVlowlong (src dst: mreg)
  | MVhighlong (src dst: mreg).(** The validation algorithm used here is described in
  "Validating register allocation and spilling",
  by Silvain Rideau and Xavier Leroy,
  in Compiler Construction (CC 2010), LNCS 6011, Springer, 2010. *)

(** * Structural checks *)

(** As a first pass, we check the LTL code returned by the external oracle
  against the original RTL code for structural conformance.
  Each RTL instruction was transformed into a LTL basic block whose
  shape must agree with the RTL instruction.  For example, if the RTL
  instruction is [Istore(Mint32, addr, args, src, s)], the LTL basic block
  must be of the following shape:
- zero, one or several "move" instructions
- a store instruction [Lstore(Mint32, addr, args', src')]
- a [Lbranch s] instruction.

  The [block_shape] type below describes all possible cases of structural
  maching between an RTL instruction and an LTL basic block.
*)

Inductive move: Type :=
  | MV (src dst: loc)
  | MVmakelong (src1 src2 dst: mreg)
  | MVlowlong (src dst: mreg)
  | MVhighlong (src dst: mreg).(** The validation algorithm used here is described in
  "Validating register allocation and spilling",
  by Silvain Rideau and Xavier Leroy,
  in Compiler Construction (CC 2010), LNCS 6011, Springer, 2010. *)

(** * Structural checks *)

(** As a first pass, we check the LTL code returned by the external oracle
  against the original RTL code for structural conformance.
  Each RTL instruction was transformed into a LTL basic block whose
  shape must agree with the RTL instruction.  For example, if the RTL
  instruction is [Istore(Mint32, addr, args, src, s)], the LTL basic block
  must be of the following shape:
- zero, one or several "move" instructions
- a store instruction [Lstore(Mint32, addr, args', src')]
- a [Lbranch s] instruction.

  The [block_shape] type below describes all possible cases of structural
  maching between an RTL instruction and an LTL basic block.
*)

Inductive move: Type :=
  | MV (src dst: loc)
  | MVmakelong (src1 src2 dst: mreg)
  | MVlowlong (src dst: mreg)
  | MVhighlong (src dst: mreg).(** The validation algorithm used here is described in
  "Validating register allocation and spilling",
  by Silvain Rideau and Xavier Leroy,
  in Compiler Construction (CC 2010), LNCS 6011, Springer, 2010. *)

(** * Structural checks *)

(** As a first pass, we check the LTL code returned by the external oracle
  against the original RTL code for structural conformance.
  Each RTL instruction was transformed into a LTL basic block whose
  shape must agree with the RTL instruction.  For example, if the RTL
  instruction is [Istore(Mint32, addr, args, src, s)], the LTL basic block
  must be of the following shape:
- zero, one or several "move" instructions
- a store instruction [Lstore(Mint32, addr, args', src')]
- a [Lbranch s] instruction.

  The [block_shape] type below describes all possible cases of structural
  maching between an RTL instruction and an LTL basic block.
*)

Inductive move: Type :=
  | MV (src dst: loc)
  | MVmakelong (src1 src2 dst: mreg)
  | MVlowlong (src dst: mreg)
  | MVhighlong (src dst: mreg).(** The validation algorithm used here is described in
  "Validating register allocation and spilling",
  by Silvain Rideau and Xavier Leroy,
  in Compiler Construction (CC 2010), LNCS 6011, Springer, 2010. *)

(** * Structural checks *)

(** As a first pass, we check the LTL code returned by the external oracle
  against the original RTL code for structural conformance.
  Each RTL instruction was transformed into a LTL basic block whose
  shape must agree with the RTL instruction.  For example, if the RTL
  instruction is [Istore(Mint32, addr, args, src, s)], the LTL basic block
  must be of the following shape:
- zero, one or several "move" instructions
- a store instruction [Lstore(Mint32, addr, args', src')]
- a [Lbranch s] instruction.

  The [block_shape] type below describes all possible cases of structural
  maching between an RTL instruction and an LTL basic block.
*)

Inductive move: Type :=
  | MV (src dst: loc)
  | MVmakelong (src1 src2 dst: mreg)
  | MVlowlong (src dst: mreg)
  | MVhighlong (src dst: mreg).Definition moves := list move.Inductive block_shape: Type :=
  | BSnop (mv: moves) (s: node)
  | BSmove (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSmakelong (src1 src2: reg) (dst: reg) (mv: moves) (s: node)
  | BSlowlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BShighlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSop (op: operation) (args: list reg) (res: reg)
         (mv1: moves) (args': list mreg) (res': mreg)
         (mv2: moves) (s: node)
  | BSopdead (op: operation) (args: list reg) (res: reg)
         (mv: moves) (s: node)
  | BSload (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSloaddead (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv: moves) (s: node)
  | BSload2 (addr1 addr2: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args1': list mreg) (dst1': mreg)
         (mv2: moves) (args2': list mreg) (dst2': mreg)
         (mv3: moves) (s: node)
  | BSload2_1 (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSload2_2 (addr addr': addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSstore (chunk: memory_chunk) (addr: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args': list mreg) (src': mreg)
         (s: node)
  | BSstore2 (addr1 addr2: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args1': list mreg) (src1': mreg)
         (mv2: moves) (args2': list mreg) (src2': mreg)
         (s: node)
  | BScall (sg: signature) (ros: reg + ident) (args: list reg) (res: reg)
         (mv1: moves) (ros': mreg + ident) (mv2: moves) (s: node)
  | BStailcall (sg: signature) (ros: reg + ident) (args: list reg)
         (mv1: moves) (ros': mreg + ident)
  | BSbuiltin (ef: external_function)
         (args: list (builtin_arg reg)) (res: builtin_res reg)
         (mv1: moves) (args': list (builtin_arg loc)) (res': builtin_res mreg)
         (mv2: moves) (s: node)
  | BScond (cond: condition) (args: list reg)
         (mv: moves) (args': list mreg) (s1 s2: node)
  | BSjumptable (arg: reg)
         (mv: moves) (arg': mreg) (tbl: list node)
  | BSreturn (arg: option reg)
         (mv: moves).Inductive block_shape: Type :=
  | BSnop (mv: moves) (s: node)
  | BSmove (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSmakelong (src1 src2: reg) (dst: reg) (mv: moves) (s: node)
  | BSlowlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BShighlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSop (op: operation) (args: list reg) (res: reg)
         (mv1: moves) (args': list mreg) (res': mreg)
         (mv2: moves) (s: node)
  | BSopdead (op: operation) (args: list reg) (res: reg)
         (mv: moves) (s: node)
  | BSload (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSloaddead (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv: moves) (s: node)
  | BSload2 (addr1 addr2: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args1': list mreg) (dst1': mreg)
         (mv2: moves) (args2': list mreg) (dst2': mreg)
         (mv3: moves) (s: node)
  | BSload2_1 (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSload2_2 (addr addr': addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSstore (chunk: memory_chunk) (addr: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args': list mreg) (src': mreg)
         (s: node)
  | BSstore2 (addr1 addr2: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args1': list mreg) (src1': mreg)
         (mv2: moves) (args2': list mreg) (src2': mreg)
         (s: node)
  | BScall (sg: signature) (ros: reg + ident) (args: list reg) (res: reg)
         (mv1: moves) (ros': mreg + ident) (mv2: moves) (s: node)
  | BStailcall (sg: signature) (ros: reg + ident) (args: list reg)
         (mv1: moves) (ros': mreg + ident)
  | BSbuiltin (ef: external_function)
         (args: list (builtin_arg reg)) (res: builtin_res reg)
         (mv1: moves) (args': list (builtin_arg loc)) (res': builtin_res mreg)
         (mv2: moves) (s: node)
  | BScond (cond: condition) (args: list reg)
         (mv: moves) (args': list mreg) (s1 s2: node)
  | BSjumptable (arg: reg)
         (mv: moves) (arg': mreg) (tbl: list node)
  | BSreturn (arg: option reg)
         (mv: moves).Inductive block_shape: Type :=
  | BSnop (mv: moves) (s: node)
  | BSmove (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSmakelong (src1 src2: reg) (dst: reg) (mv: moves) (s: node)
  | BSlowlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BShighlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSop (op: operation) (args: list reg) (res: reg)
         (mv1: moves) (args': list mreg) (res': mreg)
         (mv2: moves) (s: node)
  | BSopdead (op: operation) (args: list reg) (res: reg)
         (mv: moves) (s: node)
  | BSload (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSloaddead (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv: moves) (s: node)
  | BSload2 (addr1 addr2: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args1': list mreg) (dst1': mreg)
         (mv2: moves) (args2': list mreg) (dst2': mreg)
         (mv3: moves) (s: node)
  | BSload2_1 (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSload2_2 (addr addr': addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSstore (chunk: memory_chunk) (addr: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args': list mreg) (src': mreg)
         (s: node)
  | BSstore2 (addr1 addr2: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args1': list mreg) (src1': mreg)
         (mv2: moves) (args2': list mreg) (src2': mreg)
         (s: node)
  | BScall (sg: signature) (ros: reg + ident) (args: list reg) (res: reg)
         (mv1: moves) (ros': mreg + ident) (mv2: moves) (s: node)
  | BStailcall (sg: signature) (ros: reg + ident) (args: list reg)
         (mv1: moves) (ros': mreg + ident)
  | BSbuiltin (ef: external_function)
         (args: list (builtin_arg reg)) (res: builtin_res reg)
         (mv1: moves) (args': list (builtin_arg loc)) (res': builtin_res mreg)
         (mv2: moves) (s: node)
  | BScond (cond: condition) (args: list reg)
         (mv: moves) (args': list mreg) (s1 s2: node)
  | BSjumptable (arg: reg)
         (mv: moves) (arg': mreg) (tbl: list node)
  | BSreturn (arg: option reg)
         (mv: moves).Inductive block_shape: Type :=
  | BSnop (mv: moves) (s: node)
  | BSmove (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSmakelong (src1 src2: reg) (dst: reg) (mv: moves) (s: node)
  | BSlowlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BShighlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSop (op: operation) (args: list reg) (res: reg)
         (mv1: moves) (args': list mreg) (res': mreg)
         (mv2: moves) (s: node)
  | BSopdead (op: operation) (args: list reg) (res: reg)
         (mv: moves) (s: node)
  | BSload (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSloaddead (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv: moves) (s: node)
  | BSload2 (addr1 addr2: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args1': list mreg) (dst1': mreg)
         (mv2: moves) (args2': list mreg) (dst2': mreg)
         (mv3: moves) (s: node)
  | BSload2_1 (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSload2_2 (addr addr': addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSstore (chunk: memory_chunk) (addr: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args': list mreg) (src': mreg)
         (s: node)
  | BSstore2 (addr1 addr2: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args1': list mreg) (src1': mreg)
         (mv2: moves) (args2': list mreg) (src2': mreg)
         (s: node)
  | BScall (sg: signature) (ros: reg + ident) (args: list reg) (res: reg)
         (mv1: moves) (ros': mreg + ident) (mv2: moves) (s: node)
  | BStailcall (sg: signature) (ros: reg + ident) (args: list reg)
         (mv1: moves) (ros': mreg + ident)
  | BSbuiltin (ef: external_function)
         (args: list (builtin_arg reg)) (res: builtin_res reg)
         (mv1: moves) (args': list (builtin_arg loc)) (res': builtin_res mreg)
         (mv2: moves) (s: node)
  | BScond (cond: condition) (args: list reg)
         (mv: moves) (args': list mreg) (s1 s2: node)
  | BSjumptable (arg: reg)
         (mv: moves) (arg': mreg) (tbl: list node)
  | BSreturn (arg: option reg)
         (mv: moves).Inductive block_shape: Type :=
  | BSnop (mv: moves) (s: node)
  | BSmove (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSmakelong (src1 src2: reg) (dst: reg) (mv: moves) (s: node)
  | BSlowlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BShighlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSop (op: operation) (args: list reg) (res: reg)
         (mv1: moves) (args': list mreg) (res': mreg)
         (mv2: moves) (s: node)
  | BSopdead (op: operation) (args: list reg) (res: reg)
         (mv: moves) (s: node)
  | BSload (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSloaddead (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv: moves) (s: node)
  | BSload2 (addr1 addr2: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args1': list mreg) (dst1': mreg)
         (mv2: moves) (args2': list mreg) (dst2': mreg)
         (mv3: moves) (s: node)
  | BSload2_1 (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSload2_2 (addr addr': addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSstore (chunk: memory_chunk) (addr: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args': list mreg) (src': mreg)
         (s: node)
  | BSstore2 (addr1 addr2: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args1': list mreg) (src1': mreg)
         (mv2: moves) (args2': list mreg) (src2': mreg)
         (s: node)
  | BScall (sg: signature) (ros: reg + ident) (args: list reg) (res: reg)
         (mv1: moves) (ros': mreg + ident) (mv2: moves) (s: node)
  | BStailcall (sg: signature) (ros: reg + ident) (args: list reg)
         (mv1: moves) (ros': mreg + ident)
  | BSbuiltin (ef: external_function)
         (args: list (builtin_arg reg)) (res: builtin_res reg)
         (mv1: moves) (args': list (builtin_arg loc)) (res': builtin_res mreg)
         (mv2: moves) (s: node)
  | BScond (cond: condition) (args: list reg)
         (mv: moves) (args': list mreg) (s1 s2: node)
  | BSjumptable (arg: reg)
         (mv: moves) (arg': mreg) (tbl: list node)
  | BSreturn (arg: option reg)
         (mv: moves).Inductive block_shape: Type :=
  | BSnop (mv: moves) (s: node)
  | BSmove (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSmakelong (src1 src2: reg) (dst: reg) (mv: moves) (s: node)
  | BSlowlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BShighlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSop (op: operation) (args: list reg) (res: reg)
         (mv1: moves) (args': list mreg) (res': mreg)
         (mv2: moves) (s: node)
  | BSopdead (op: operation) (args: list reg) (res: reg)
         (mv: moves) (s: node)
  | BSload (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSloaddead (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv: moves) (s: node)
  | BSload2 (addr1 addr2: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args1': list mreg) (dst1': mreg)
         (mv2: moves) (args2': list mreg) (dst2': mreg)
         (mv3: moves) (s: node)
  | BSload2_1 (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSload2_2 (addr addr': addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSstore (chunk: memory_chunk) (addr: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args': list mreg) (src': mreg)
         (s: node)
  | BSstore2 (addr1 addr2: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args1': list mreg) (src1': mreg)
         (mv2: moves) (args2': list mreg) (src2': mreg)
         (s: node)
  | BScall (sg: signature) (ros: reg + ident) (args: list reg) (res: reg)
         (mv1: moves) (ros': mreg + ident) (mv2: moves) (s: node)
  | BStailcall (sg: signature) (ros: reg + ident) (args: list reg)
         (mv1: moves) (ros': mreg + ident)
  | BSbuiltin (ef: external_function)
         (args: list (builtin_arg reg)) (res: builtin_res reg)
         (mv1: moves) (args': list (builtin_arg loc)) (res': builtin_res mreg)
         (mv2: moves) (s: node)
  | BScond (cond: condition) (args: list reg)
         (mv: moves) (args': list mreg) (s1 s2: node)
  | BSjumptable (arg: reg)
         (mv: moves) (arg': mreg) (tbl: list node)
  | BSreturn (arg: option reg)
         (mv: moves).Inductive block_shape: Type :=
  | BSnop (mv: moves) (s: node)
  | BSmove (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSmakelong (src1 src2: reg) (dst: reg) (mv: moves) (s: node)
  | BSlowlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BShighlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSop (op: operation) (args: list reg) (res: reg)
         (mv1: moves) (args': list mreg) (res': mreg)
         (mv2: moves) (s: node)
  | BSopdead (op: operation) (args: list reg) (res: reg)
         (mv: moves) (s: node)
  | BSload (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSloaddead (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv: moves) (s: node)
  | BSload2 (addr1 addr2: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args1': list mreg) (dst1': mreg)
         (mv2: moves) (args2': list mreg) (dst2': mreg)
         (mv3: moves) (s: node)
  | BSload2_1 (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSload2_2 (addr addr': addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSstore (chunk: memory_chunk) (addr: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args': list mreg) (src': mreg)
         (s: node)
  | BSstore2 (addr1 addr2: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args1': list mreg) (src1': mreg)
         (mv2: moves) (args2': list mreg) (src2': mreg)
         (s: node)
  | BScall (sg: signature) (ros: reg + ident) (args: list reg) (res: reg)
         (mv1: moves) (ros': mreg + ident) (mv2: moves) (s: node)
  | BStailcall (sg: signature) (ros: reg + ident) (args: list reg)
         (mv1: moves) (ros': mreg + ident)
  | BSbuiltin (ef: external_function)
         (args: list (builtin_arg reg)) (res: builtin_res reg)
         (mv1: moves) (args': list (builtin_arg loc)) (res': builtin_res mreg)
         (mv2: moves) (s: node)
  | BScond (cond: condition) (args: list reg)
         (mv: moves) (args': list mreg) (s1 s2: node)
  | BSjumptable (arg: reg)
         (mv: moves) (arg': mreg) (tbl: list node)
  | BSreturn (arg: option reg)
         (mv: moves).Inductive block_shape: Type :=
  | BSnop (mv: moves) (s: node)
  | BSmove (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSmakelong (src1 src2: reg) (dst: reg) (mv: moves) (s: node)
  | BSlowlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BShighlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSop (op: operation) (args: list reg) (res: reg)
         (mv1: moves) (args': list mreg) (res': mreg)
         (mv2: moves) (s: node)
  | BSopdead (op: operation) (args: list reg) (res: reg)
         (mv: moves) (s: node)
  | BSload (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSloaddead (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv: moves) (s: node)
  | BSload2 (addr1 addr2: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args1': list mreg) (dst1': mreg)
         (mv2: moves) (args2': list mreg) (dst2': mreg)
         (mv3: moves) (s: node)
  | BSload2_1 (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSload2_2 (addr addr': addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSstore (chunk: memory_chunk) (addr: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args': list mreg) (src': mreg)
         (s: node)
  | BSstore2 (addr1 addr2: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args1': list mreg) (src1': mreg)
         (mv2: moves) (args2': list mreg) (src2': mreg)
         (s: node)
  | BScall (sg: signature) (ros: reg + ident) (args: list reg) (res: reg)
         (mv1: moves) (ros': mreg + ident) (mv2: moves) (s: node)
  | BStailcall (sg: signature) (ros: reg + ident) (args: list reg)
         (mv1: moves) (ros': mreg + ident)
  | BSbuiltin (ef: external_function)
         (args: list (builtin_arg reg)) (res: builtin_res reg)
         (mv1: moves) (args': list (builtin_arg loc)) (res': builtin_res mreg)
         (mv2: moves) (s: node)
  | BScond (cond: condition) (args: list reg)
         (mv: moves) (args': list mreg) (s1 s2: node)
  | BSjumptable (arg: reg)
         (mv: moves) (arg': mreg) (tbl: list node)
  | BSreturn (arg: option reg)
         (mv: moves).Inductive block_shape: Type :=
  | BSnop (mv: moves) (s: node)
  | BSmove (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSmakelong (src1 src2: reg) (dst: reg) (mv: moves) (s: node)
  | BSlowlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BShighlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSop (op: operation) (args: list reg) (res: reg)
         (mv1: moves) (args': list mreg) (res': mreg)
         (mv2: moves) (s: node)
  | BSopdead (op: operation) (args: list reg) (res: reg)
         (mv: moves) (s: node)
  | BSload (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSloaddead (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv: moves) (s: node)
  | BSload2 (addr1 addr2: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args1': list mreg) (dst1': mreg)
         (mv2: moves) (args2': list mreg) (dst2': mreg)
         (mv3: moves) (s: node)
  | BSload2_1 (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSload2_2 (addr addr': addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSstore (chunk: memory_chunk) (addr: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args': list mreg) (src': mreg)
         (s: node)
  | BSstore2 (addr1 addr2: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args1': list mreg) (src1': mreg)
         (mv2: moves) (args2': list mreg) (src2': mreg)
         (s: node)
  | BScall (sg: signature) (ros: reg + ident) (args: list reg) (res: reg)
         (mv1: moves) (ros': mreg + ident) (mv2: moves) (s: node)
  | BStailcall (sg: signature) (ros: reg + ident) (args: list reg)
         (mv1: moves) (ros': mreg + ident)
  | BSbuiltin (ef: external_function)
         (args: list (builtin_arg reg)) (res: builtin_res reg)
         (mv1: moves) (args': list (builtin_arg loc)) (res': builtin_res mreg)
         (mv2: moves) (s: node)
  | BScond (cond: condition) (args: list reg)
         (mv: moves) (args': list mreg) (s1 s2: node)
  | BSjumptable (arg: reg)
         (mv: moves) (arg': mreg) (tbl: list node)
  | BSreturn (arg: option reg)
         (mv: moves).Inductive block_shape: Type :=
  | BSnop (mv: moves) (s: node)
  | BSmove (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSmakelong (src1 src2: reg) (dst: reg) (mv: moves) (s: node)
  | BSlowlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BShighlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSop (op: operation) (args: list reg) (res: reg)
         (mv1: moves) (args': list mreg) (res': mreg)
         (mv2: moves) (s: node)
  | BSopdead (op: operation) (args: list reg) (res: reg)
         (mv: moves) (s: node)
  | BSload (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSloaddead (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv: moves) (s: node)
  | BSload2 (addr1 addr2: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args1': list mreg) (dst1': mreg)
         (mv2: moves) (args2': list mreg) (dst2': mreg)
         (mv3: moves) (s: node)
  | BSload2_1 (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSload2_2 (addr addr': addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSstore (chunk: memory_chunk) (addr: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args': list mreg) (src': mreg)
         (s: node)
  | BSstore2 (addr1 addr2: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args1': list mreg) (src1': mreg)
         (mv2: moves) (args2': list mreg) (src2': mreg)
         (s: node)
  | BScall (sg: signature) (ros: reg + ident) (args: list reg) (res: reg)
         (mv1: moves) (ros': mreg + ident) (mv2: moves) (s: node)
  | BStailcall (sg: signature) (ros: reg + ident) (args: list reg)
         (mv1: moves) (ros': mreg + ident)
  | BSbuiltin (ef: external_function)
         (args: list (builtin_arg reg)) (res: builtin_res reg)
         (mv1: moves) (args': list (builtin_arg loc)) (res': builtin_res mreg)
         (mv2: moves) (s: node)
  | BScond (cond: condition) (args: list reg)
         (mv: moves) (args': list mreg) (s1 s2: node)
  | BSjumptable (arg: reg)
         (mv: moves) (arg': mreg) (tbl: list node)
  | BSreturn (arg: option reg)
         (mv: moves).Inductive block_shape: Type :=
  | BSnop (mv: moves) (s: node)
  | BSmove (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSmakelong (src1 src2: reg) (dst: reg) (mv: moves) (s: node)
  | BSlowlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BShighlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSop (op: operation) (args: list reg) (res: reg)
         (mv1: moves) (args': list mreg) (res': mreg)
         (mv2: moves) (s: node)
  | BSopdead (op: operation) (args: list reg) (res: reg)
         (mv: moves) (s: node)
  | BSload (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSloaddead (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv: moves) (s: node)
  | BSload2 (addr1 addr2: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args1': list mreg) (dst1': mreg)
         (mv2: moves) (args2': list mreg) (dst2': mreg)
         (mv3: moves) (s: node)
  | BSload2_1 (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSload2_2 (addr addr': addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSstore (chunk: memory_chunk) (addr: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args': list mreg) (src': mreg)
         (s: node)
  | BSstore2 (addr1 addr2: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args1': list mreg) (src1': mreg)
         (mv2: moves) (args2': list mreg) (src2': mreg)
         (s: node)
  | BScall (sg: signature) (ros: reg + ident) (args: list reg) (res: reg)
         (mv1: moves) (ros': mreg + ident) (mv2: moves) (s: node)
  | BStailcall (sg: signature) (ros: reg + ident) (args: list reg)
         (mv1: moves) (ros': mreg + ident)
  | BSbuiltin (ef: external_function)
         (args: list (builtin_arg reg)) (res: builtin_res reg)
         (mv1: moves) (args': list (builtin_arg loc)) (res': builtin_res mreg)
         (mv2: moves) (s: node)
  | BScond (cond: condition) (args: list reg)
         (mv: moves) (args': list mreg) (s1 s2: node)
  | BSjumptable (arg: reg)
         (mv: moves) (arg': mreg) (tbl: list node)
  | BSreturn (arg: option reg)
         (mv: moves).Inductive block_shape: Type :=
  | BSnop (mv: moves) (s: node)
  | BSmove (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSmakelong (src1 src2: reg) (dst: reg) (mv: moves) (s: node)
  | BSlowlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BShighlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSop (op: operation) (args: list reg) (res: reg)
         (mv1: moves) (args': list mreg) (res': mreg)
         (mv2: moves) (s: node)
  | BSopdead (op: operation) (args: list reg) (res: reg)
         (mv: moves) (s: node)
  | BSload (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSloaddead (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv: moves) (s: node)
  | BSload2 (addr1 addr2: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args1': list mreg) (dst1': mreg)
         (mv2: moves) (args2': list mreg) (dst2': mreg)
         (mv3: moves) (s: node)
  | BSload2_1 (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSload2_2 (addr addr': addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSstore (chunk: memory_chunk) (addr: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args': list mreg) (src': mreg)
         (s: node)
  | BSstore2 (addr1 addr2: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args1': list mreg) (src1': mreg)
         (mv2: moves) (args2': list mreg) (src2': mreg)
         (s: node)
  | BScall (sg: signature) (ros: reg + ident) (args: list reg) (res: reg)
         (mv1: moves) (ros': mreg + ident) (mv2: moves) (s: node)
  | BStailcall (sg: signature) (ros: reg + ident) (args: list reg)
         (mv1: moves) (ros': mreg + ident)
  | BSbuiltin (ef: external_function)
         (args: list (builtin_arg reg)) (res: builtin_res reg)
         (mv1: moves) (args': list (builtin_arg loc)) (res': builtin_res mreg)
         (mv2: moves) (s: node)
  | BScond (cond: condition) (args: list reg)
         (mv: moves) (args': list mreg) (s1 s2: node)
  | BSjumptable (arg: reg)
         (mv: moves) (arg': mreg) (tbl: list node)
  | BSreturn (arg: option reg)
         (mv: moves).Inductive block_shape: Type :=
  | BSnop (mv: moves) (s: node)
  | BSmove (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSmakelong (src1 src2: reg) (dst: reg) (mv: moves) (s: node)
  | BSlowlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BShighlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSop (op: operation) (args: list reg) (res: reg)
         (mv1: moves) (args': list mreg) (res': mreg)
         (mv2: moves) (s: node)
  | BSopdead (op: operation) (args: list reg) (res: reg)
         (mv: moves) (s: node)
  | BSload (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSloaddead (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv: moves) (s: node)
  | BSload2 (addr1 addr2: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args1': list mreg) (dst1': mreg)
         (mv2: moves) (args2': list mreg) (dst2': mreg)
         (mv3: moves) (s: node)
  | BSload2_1 (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSload2_2 (addr addr': addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSstore (chunk: memory_chunk) (addr: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args': list mreg) (src': mreg)
         (s: node)
  | BSstore2 (addr1 addr2: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args1': list mreg) (src1': mreg)
         (mv2: moves) (args2': list mreg) (src2': mreg)
         (s: node)
  | BScall (sg: signature) (ros: reg + ident) (args: list reg) (res: reg)
         (mv1: moves) (ros': mreg + ident) (mv2: moves) (s: node)
  | BStailcall (sg: signature) (ros: reg + ident) (args: list reg)
         (mv1: moves) (ros': mreg + ident)
  | BSbuiltin (ef: external_function)
         (args: list (builtin_arg reg)) (res: builtin_res reg)
         (mv1: moves) (args': list (builtin_arg loc)) (res': builtin_res mreg)
         (mv2: moves) (s: node)
  | BScond (cond: condition) (args: list reg)
         (mv: moves) (args': list mreg) (s1 s2: node)
  | BSjumptable (arg: reg)
         (mv: moves) (arg': mreg) (tbl: list node)
  | BSreturn (arg: option reg)
         (mv: moves).Inductive block_shape: Type :=
  | BSnop (mv: moves) (s: node)
  | BSmove (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSmakelong (src1 src2: reg) (dst: reg) (mv: moves) (s: node)
  | BSlowlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BShighlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSop (op: operation) (args: list reg) (res: reg)
         (mv1: moves) (args': list mreg) (res': mreg)
         (mv2: moves) (s: node)
  | BSopdead (op: operation) (args: list reg) (res: reg)
         (mv: moves) (s: node)
  | BSload (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSloaddead (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv: moves) (s: node)
  | BSload2 (addr1 addr2: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args1': list mreg) (dst1': mreg)
         (mv2: moves) (args2': list mreg) (dst2': mreg)
         (mv3: moves) (s: node)
  | BSload2_1 (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSload2_2 (addr addr': addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSstore (chunk: memory_chunk) (addr: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args': list mreg) (src': mreg)
         (s: node)
  | BSstore2 (addr1 addr2: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args1': list mreg) (src1': mreg)
         (mv2: moves) (args2': list mreg) (src2': mreg)
         (s: node)
  | BScall (sg: signature) (ros: reg + ident) (args: list reg) (res: reg)
         (mv1: moves) (ros': mreg + ident) (mv2: moves) (s: node)
  | BStailcall (sg: signature) (ros: reg + ident) (args: list reg)
         (mv1: moves) (ros': mreg + ident)
  | BSbuiltin (ef: external_function)
         (args: list (builtin_arg reg)) (res: builtin_res reg)
         (mv1: moves) (args': list (builtin_arg loc)) (res': builtin_res mreg)
         (mv2: moves) (s: node)
  | BScond (cond: condition) (args: list reg)
         (mv: moves) (args': list mreg) (s1 s2: node)
  | BSjumptable (arg: reg)
         (mv: moves) (arg': mreg) (tbl: list node)
  | BSreturn (arg: option reg)
         (mv: moves).Inductive block_shape: Type :=
  | BSnop (mv: moves) (s: node)
  | BSmove (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSmakelong (src1 src2: reg) (dst: reg) (mv: moves) (s: node)
  | BSlowlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BShighlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSop (op: operation) (args: list reg) (res: reg)
         (mv1: moves) (args': list mreg) (res': mreg)
         (mv2: moves) (s: node)
  | BSopdead (op: operation) (args: list reg) (res: reg)
         (mv: moves) (s: node)
  | BSload (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSloaddead (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv: moves) (s: node)
  | BSload2 (addr1 addr2: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args1': list mreg) (dst1': mreg)
         (mv2: moves) (args2': list mreg) (dst2': mreg)
         (mv3: moves) (s: node)
  | BSload2_1 (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSload2_2 (addr addr': addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSstore (chunk: memory_chunk) (addr: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args': list mreg) (src': mreg)
         (s: node)
  | BSstore2 (addr1 addr2: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args1': list mreg) (src1': mreg)
         (mv2: moves) (args2': list mreg) (src2': mreg)
         (s: node)
  | BScall (sg: signature) (ros: reg + ident) (args: list reg) (res: reg)
         (mv1: moves) (ros': mreg + ident) (mv2: moves) (s: node)
  | BStailcall (sg: signature) (ros: reg + ident) (args: list reg)
         (mv1: moves) (ros': mreg + ident)
  | BSbuiltin (ef: external_function)
         (args: list (builtin_arg reg)) (res: builtin_res reg)
         (mv1: moves) (args': list (builtin_arg loc)) (res': builtin_res mreg)
         (mv2: moves) (s: node)
  | BScond (cond: condition) (args: list reg)
         (mv: moves) (args': list mreg) (s1 s2: node)
  | BSjumptable (arg: reg)
         (mv: moves) (arg': mreg) (tbl: list node)
  | BSreturn (arg: option reg)
         (mv: moves).Inductive block_shape: Type :=
  | BSnop (mv: moves) (s: node)
  | BSmove (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSmakelong (src1 src2: reg) (dst: reg) (mv: moves) (s: node)
  | BSlowlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BShighlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSop (op: operation) (args: list reg) (res: reg)
         (mv1: moves) (args': list mreg) (res': mreg)
         (mv2: moves) (s: node)
  | BSopdead (op: operation) (args: list reg) (res: reg)
         (mv: moves) (s: node)
  | BSload (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSloaddead (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv: moves) (s: node)
  | BSload2 (addr1 addr2: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args1': list mreg) (dst1': mreg)
         (mv2: moves) (args2': list mreg) (dst2': mreg)
         (mv3: moves) (s: node)
  | BSload2_1 (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSload2_2 (addr addr': addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSstore (chunk: memory_chunk) (addr: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args': list mreg) (src': mreg)
         (s: node)
  | BSstore2 (addr1 addr2: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args1': list mreg) (src1': mreg)
         (mv2: moves) (args2': list mreg) (src2': mreg)
         (s: node)
  | BScall (sg: signature) (ros: reg + ident) (args: list reg) (res: reg)
         (mv1: moves) (ros': mreg + ident) (mv2: moves) (s: node)
  | BStailcall (sg: signature) (ros: reg + ident) (args: list reg)
         (mv1: moves) (ros': mreg + ident)
  | BSbuiltin (ef: external_function)
         (args: list (builtin_arg reg)) (res: builtin_res reg)
         (mv1: moves) (args': list (builtin_arg loc)) (res': builtin_res mreg)
         (mv2: moves) (s: node)
  | BScond (cond: condition) (args: list reg)
         (mv: moves) (args': list mreg) (s1 s2: node)
  | BSjumptable (arg: reg)
         (mv: moves) (arg': mreg) (tbl: list node)
  | BSreturn (arg: option reg)
         (mv: moves).Inductive block_shape: Type :=
  | BSnop (mv: moves) (s: node)
  | BSmove (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSmakelong (src1 src2: reg) (dst: reg) (mv: moves) (s: node)
  | BSlowlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BShighlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSop (op: operation) (args: list reg) (res: reg)
         (mv1: moves) (args': list mreg) (res': mreg)
         (mv2: moves) (s: node)
  | BSopdead (op: operation) (args: list reg) (res: reg)
         (mv: moves) (s: node)
  | BSload (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSloaddead (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv: moves) (s: node)
  | BSload2 (addr1 addr2: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args1': list mreg) (dst1': mreg)
         (mv2: moves) (args2': list mreg) (dst2': mreg)
         (mv3: moves) (s: node)
  | BSload2_1 (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSload2_2 (addr addr': addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSstore (chunk: memory_chunk) (addr: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args': list mreg) (src': mreg)
         (s: node)
  | BSstore2 (addr1 addr2: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args1': list mreg) (src1': mreg)
         (mv2: moves) (args2': list mreg) (src2': mreg)
         (s: node)
  | BScall (sg: signature) (ros: reg + ident) (args: list reg) (res: reg)
         (mv1: moves) (ros': mreg + ident) (mv2: moves) (s: node)
  | BStailcall (sg: signature) (ros: reg + ident) (args: list reg)
         (mv1: moves) (ros': mreg + ident)
  | BSbuiltin (ef: external_function)
         (args: list (builtin_arg reg)) (res: builtin_res reg)
         (mv1: moves) (args': list (builtin_arg loc)) (res': builtin_res mreg)
         (mv2: moves) (s: node)
  | BScond (cond: condition) (args: list reg)
         (mv: moves) (args': list mreg) (s1 s2: node)
  | BSjumptable (arg: reg)
         (mv: moves) (arg': mreg) (tbl: list node)
  | BSreturn (arg: option reg)
         (mv: moves).Inductive block_shape: Type :=
  | BSnop (mv: moves) (s: node)
  | BSmove (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSmakelong (src1 src2: reg) (dst: reg) (mv: moves) (s: node)
  | BSlowlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BShighlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSop (op: operation) (args: list reg) (res: reg)
         (mv1: moves) (args': list mreg) (res': mreg)
         (mv2: moves) (s: node)
  | BSopdead (op: operation) (args: list reg) (res: reg)
         (mv: moves) (s: node)
  | BSload (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSloaddead (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv: moves) (s: node)
  | BSload2 (addr1 addr2: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args1': list mreg) (dst1': mreg)
         (mv2: moves) (args2': list mreg) (dst2': mreg)
         (mv3: moves) (s: node)
  | BSload2_1 (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSload2_2 (addr addr': addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSstore (chunk: memory_chunk) (addr: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args': list mreg) (src': mreg)
         (s: node)
  | BSstore2 (addr1 addr2: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args1': list mreg) (src1': mreg)
         (mv2: moves) (args2': list mreg) (src2': mreg)
         (s: node)
  | BScall (sg: signature) (ros: reg + ident) (args: list reg) (res: reg)
         (mv1: moves) (ros': mreg + ident) (mv2: moves) (s: node)
  | BStailcall (sg: signature) (ros: reg + ident) (args: list reg)
         (mv1: moves) (ros': mreg + ident)
  | BSbuiltin (ef: external_function)
         (args: list (builtin_arg reg)) (res: builtin_res reg)
         (mv1: moves) (args': list (builtin_arg loc)) (res': builtin_res mreg)
         (mv2: moves) (s: node)
  | BScond (cond: condition) (args: list reg)
         (mv: moves) (args': list mreg) (s1 s2: node)
  | BSjumptable (arg: reg)
         (mv: moves) (arg': mreg) (tbl: list node)
  | BSreturn (arg: option reg)
         (mv: moves).Inductive block_shape: Type :=
  | BSnop (mv: moves) (s: node)
  | BSmove (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSmakelong (src1 src2: reg) (dst: reg) (mv: moves) (s: node)
  | BSlowlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BShighlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSop (op: operation) (args: list reg) (res: reg)
         (mv1: moves) (args': list mreg) (res': mreg)
         (mv2: moves) (s: node)
  | BSopdead (op: operation) (args: list reg) (res: reg)
         (mv: moves) (s: node)
  | BSload (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSloaddead (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv: moves) (s: node)
  | BSload2 (addr1 addr2: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args1': list mreg) (dst1': mreg)
         (mv2: moves) (args2': list mreg) (dst2': mreg)
         (mv3: moves) (s: node)
  | BSload2_1 (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSload2_2 (addr addr': addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSstore (chunk: memory_chunk) (addr: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args': list mreg) (src': mreg)
         (s: node)
  | BSstore2 (addr1 addr2: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args1': list mreg) (src1': mreg)
         (mv2: moves) (args2': list mreg) (src2': mreg)
         (s: node)
  | BScall (sg: signature) (ros: reg + ident) (args: list reg) (res: reg)
         (mv1: moves) (ros': mreg + ident) (mv2: moves) (s: node)
  | BStailcall (sg: signature) (ros: reg + ident) (args: list reg)
         (mv1: moves) (ros': mreg + ident)
  | BSbuiltin (ef: external_function)
         (args: list (builtin_arg reg)) (res: builtin_res reg)
         (mv1: moves) (args': list (builtin_arg loc)) (res': builtin_res mreg)
         (mv2: moves) (s: node)
  | BScond (cond: condition) (args: list reg)
         (mv: moves) (args': list mreg) (s1 s2: node)
  | BSjumptable (arg: reg)
         (mv: moves) (arg': mreg) (tbl: list node)
  | BSreturn (arg: option reg)
         (mv: moves).Inductive block_shape: Type :=
  | BSnop (mv: moves) (s: node)
  | BSmove (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSmakelong (src1 src2: reg) (dst: reg) (mv: moves) (s: node)
  | BSlowlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BShighlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSop (op: operation) (args: list reg) (res: reg)
         (mv1: moves) (args': list mreg) (res': mreg)
         (mv2: moves) (s: node)
  | BSopdead (op: operation) (args: list reg) (res: reg)
         (mv: moves) (s: node)
  | BSload (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSloaddead (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv: moves) (s: node)
  | BSload2 (addr1 addr2: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args1': list mreg) (dst1': mreg)
         (mv2: moves) (args2': list mreg) (dst2': mreg)
         (mv3: moves) (s: node)
  | BSload2_1 (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSload2_2 (addr addr': addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSstore (chunk: memory_chunk) (addr: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args': list mreg) (src': mreg)
         (s: node)
  | BSstore2 (addr1 addr2: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args1': list mreg) (src1': mreg)
         (mv2: moves) (args2': list mreg) (src2': mreg)
         (s: node)
  | BScall (sg: signature) (ros: reg + ident) (args: list reg) (res: reg)
         (mv1: moves) (ros': mreg + ident) (mv2: moves) (s: node)
  | BStailcall (sg: signature) (ros: reg + ident) (args: list reg)
         (mv1: moves) (ros': mreg + ident)
  | BSbuiltin (ef: external_function)
         (args: list (builtin_arg reg)) (res: builtin_res reg)
         (mv1: moves) (args': list (builtin_arg loc)) (res': builtin_res mreg)
         (mv2: moves) (s: node)
  | BScond (cond: condition) (args: list reg)
         (mv: moves) (args': list mreg) (s1 s2: node)
  | BSjumptable (arg: reg)
         (mv: moves) (arg': mreg) (tbl: list node)
  | BSreturn (arg: option reg)
         (mv: moves).Inductive block_shape: Type :=
  | BSnop (mv: moves) (s: node)
  | BSmove (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSmakelong (src1 src2: reg) (dst: reg) (mv: moves) (s: node)
  | BSlowlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BShighlong (src: reg) (dst: reg) (mv: moves) (s: node)
  | BSop (op: operation) (args: list reg) (res: reg)
         (mv1: moves) (args': list mreg) (res': mreg)
         (mv2: moves) (s: node)
  | BSopdead (op: operation) (args: list reg) (res: reg)
         (mv: moves) (s: node)
  | BSload (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSloaddead (chunk: memory_chunk) (addr: addressing) (args: list reg) (dst: reg)
         (mv: moves) (s: node)
  | BSload2 (addr1 addr2: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args1': list mreg) (dst1': mreg)
         (mv2: moves) (args2': list mreg) (dst2': mreg)
         (mv3: moves) (s: node)
  | BSload2_1 (addr: addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSload2_2 (addr addr': addressing) (args: list reg) (dst: reg)
         (mv1: moves) (args': list mreg) (dst': mreg)
         (mv2: moves) (s: node)
  | BSstore (chunk: memory_chunk) (addr: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args': list mreg) (src': mreg)
         (s: node)
  | BSstore2 (addr1 addr2: addressing) (args: list reg) (src: reg)
         (mv1: moves) (args1': list mreg) (src1': mreg)
         (mv2: moves) (args2': list mreg) (src2': mreg)
         (s: node)
  | BScall (sg: signature) (ros: reg + ident) (args: list reg) (res: reg)
         (mv1: moves) (ros': mreg + ident) (mv2: moves) (s: node)
  | BStailcall (sg: signature) (ros: reg + ident) (args: list reg)
         (mv1: moves) (ros': mreg + ident)
  | BSbuiltin (ef: external_function)
         (args: list (builtin_arg reg)) (res: builtin_res reg)
         (mv1: moves) (args': list (builtin_arg loc)) (res': builtin_res mreg)
         (mv2: moves) (s: node)
  | BScond (cond: condition) (args: list reg)
         (mv: moves) (args': list mreg) (s1 s2: node)
  | BSjumptable (arg: reg)
         (mv: moves) (arg': mreg) (tbl: list node)
  | BSreturn (arg: option reg)
         (mv: moves).(** Classify operations into moves, 64-bit split integer operations, and other
  arithmetic/logical operations. *)

Inductive operation_kind {A: Type}: operation -> list A -> Type :=
  | operation_Omove: forall arg, operation_kind Omove (arg :: nil)
  | operation_Omakelong: forall arg1 arg2, operation_kind Omakelong (arg1 :: arg2 :: nil)
  | operation_Olowlong: forall arg, operation_kind Olowlong (arg :: nil)
  | operation_Ohighlong: forall arg, operation_kind Ohighlong (arg :: nil)
  | operation_other: forall op args, operation_kind op args.(** Classify operations into moves, 64-bit split integer operations, and other
  arithmetic/logical operations. *)

Inductive operation_kind {A: Type}: operation -> list A -> Type :=
  | operation_Omove: forall arg, operation_kind Omove (arg :: nil)
  | operation_Omakelong: forall arg1 arg2, operation_kind Omakelong (arg1 :: arg2 :: nil)
  | operation_Olowlong: forall arg, operation_kind Olowlong (arg :: nil)
  | operation_Ohighlong: forall arg, operation_kind Ohighlong (arg :: nil)
  | operation_other: forall op args, operation_kind op args.(** Classify operations into moves, 64-bit split integer operations, and other
  arithmetic/logical operations. *)

Inductive operation_kind {A: Type}: operation -> list A -> Type :=
  | operation_Omove: forall arg, operation_kind Omove (arg :: nil)
  | operation_Omakelong: forall arg1 arg2, operation_kind Omakelong (arg1 :: arg2 :: nil)
  | operation_Olowlong: forall arg, operation_kind Olowlong (arg :: nil)
  | operation_Ohighlong: forall arg, operation_kind Ohighlong (arg :: nil)
  | operation_other: forall op args, operation_kind op args.(** Classify operations into moves, 64-bit split integer operations, and other
  arithmetic/logical operations. *)

Inductive operation_kind {A: Type}: operation -> list A -> Type :=
  | operation_Omove: forall arg, operation_kind Omove (arg :: nil)
  | operation_Omakelong: forall arg1 arg2, operation_kind Omakelong (arg1 :: arg2 :: nil)
  | operation_Olowlong: forall arg, operation_kind Olowlong (arg :: nil)
  | operation_Ohighlong: forall arg, operation_kind Ohighlong (arg :: nil)
  | operation_other: forall op args, operation_kind op args.(** Classify operations into moves, 64-bit split integer operations, and other
  arithmetic/logical operations. *)

Inductive operation_kind {A: Type}: operation -> list A -> Type :=
  | operation_Omove: forall arg, operation_kind Omove (arg :: nil)
  | operation_Omakelong: forall arg1 arg2, operation_kind Omakelong (arg1 :: arg2 :: nil)
  | operation_Olowlong: forall arg, operation_kind Olowlong (arg :: nil)
  | operation_Ohighlong: forall arg, operation_kind Ohighlong (arg :: nil)
  | operation_other: forall op args, operation_kind op args.(** Classify operations into moves, 64-bit split integer operations, and other
  arithmetic/logical operations. *)

Inductive operation_kind {A: Type}: operation -> list A -> Type :=
  | operation_Omove: forall arg, operation_kind Omove (arg :: nil)
  | operation_Omakelong: forall arg1 arg2, operation_kind Omakelong (arg1 :: arg2 :: nil)
  | operation_Olowlong: forall arg, operation_kind Olowlong (arg :: nil)
  | operation_Ohighlong: forall arg, operation_kind Ohighlong (arg :: nil)
  | operation_other: forall op args, operation_kind op args.Definition classify_operation {A: Type} (op: operation) (args: list A) : operation_kind op args :=
  match op, args with
  | Omove, arg::nil => operation_Omove arg
  | Omakelong, arg1::arg2::nil => operation_Omakelong arg1 arg2
  | Olowlong, arg::nil => operation_Olowlong arg
  | Ohighlong, arg::nil => operation_Ohighlong arg
  | op, args => operation_other op args
  end.(** Extract the move instructions at the beginning of block [b].
  Return the list of moves and the suffix of [b] after the moves.
  Two versions are provided: [extract_moves], which extracts only
  "true" moves, and [extract_moves_ext], which also extracts
  the [makelong], [lowlong] and [highlong] operations over 64-bit integers.
*)

Fixpoint extract_moves (accu: moves) (b: bblock) {struct b} : moves * bblock :=
  match b with
  | Lgetstack sl ofs ty dst :: b' =>
      extract_moves (MV (S sl ofs ty) (R dst) :: accu) b'
  | Lsetstack src sl ofs ty :: b' =>
      extract_moves (MV (R src) (S sl ofs ty) :: accu) b'
  | Lop op args res :: b' =>
      match is_move_operation op args with
      | Some arg =>
          extract_moves (MV (R arg) (R res) :: accu) b'
      | None =>
          (List.rev accu, b)
      end
  | _ =>
      (List.rev accu, b)
  end.Fixpoint extract_moves_ext (accu: moves) (b: bblock) {struct b} : moves * bblock :=
  match b with
  | Lgetstack sl ofs ty dst :: b' =>
      extract_moves_ext (MV (S sl ofs ty) (R dst) :: accu) b'
  | Lsetstack src sl ofs ty :: b' =>
      extract_moves_ext (MV (R src) (S sl ofs ty) :: accu) b'
  | Lop op args res :: b' =>
      match classify_operation op args with
      | operation_Omove arg =>
          extract_moves_ext (MV (R arg) (R res) :: accu) b'
      | operation_Omakelong arg1 arg2 =>
          extract_moves_ext (MVmakelong arg1 arg2 res :: accu) b'
      | operation_Olowlong arg =>
          extract_moves_ext (MVlowlong arg res :: accu) b'
      | operation_Ohighlong arg =>
          extract_moves_ext (MVhighlong arg res :: accu) b'
      | operation_other _ _ =>
          (List.rev accu, b)
      end
  | _ =>
      (List.rev accu, b)
  end.Definition check_succ (s: node) (b: LTL.bblock) : bool :=
  match b with
  | Lbranch s' :: _ => peq s s'
  | _ => false
  end.Notation "'do' X <- A ; B" := (match A with Some X => B | None => None end)
         (at level 200, X ident, A at level 100, B at level 200)
         : option_monad_scope.Notation "'assertion' A ; B" := (if A then B else None)
         (at level 200, A at level 100, B at level 200)
         : option_monad_scope.(** Check RTL instruction [i] against LTL basic block [b].
  On success, return [Some] with a [block_shape] describing the correspondence.
  On error, return [None]. *)

Definition pair_Iop_block (op: operation) (args: list reg) (res: reg) (s: node) (b: LTL.bblock) :=
  let (mv1, b1) := extract_moves nil b in
  match b1 with
  | Lop op' args' res' :: b2 =>
      let (mv2, b3) := extract_moves nil b2 in
      assertion (eq_operation op op');
      assertion (check_succ s b3);
      Some(BSop op args res mv1 args' res' mv2 s)
  | _ =>
      assertion (check_succ s b1);
      Some(BSopdead op args res mv1 s)
  end.Definition pair_instr_block
               (i: RTL.instruction) (b: LTL.bblock) : option block_shape :=
  match i with
  | Inop s =>
      let (mv, b1) := extract_moves nil b in
      assertion (check_succ s b1); Some(BSnop mv s)
  | Iop op args res s =>
      match classify_operation op args with
      | operation_Omove arg =>
          let (mv, b1) := extract_moves nil b in
          assertion (check_succ s b1); Some(BSmove arg res mv s)
      | operation_Omakelong arg1 arg2 =>
          if Archi.splitlong then
           (let (mv, b1) := extract_moves nil b in
            assertion (check_succ s b1); Some(BSmakelong arg1 arg2 res mv s))
          else
            pair_Iop_block op args res s b
      | operation_Olowlong arg =>
          if Archi.splitlong then
           (let (mv, b1) := extract_moves nil b in
            assertion (check_succ s b1); Some(BSlowlong arg res mv s))
          else
            pair_Iop_block op args res s b
      | operation_Ohighlong arg =>
          if Archi.splitlong then
           (let (mv, b1) := extract_moves nil b in
            assertion (check_succ s b1); Some(BShighlong arg res mv s))
          else
            pair_Iop_block op args res s b
      | operation_other _ _ =>
          pair_Iop_block op args res s b
      end
  | Iload chunk addr args dst s =>
      let (mv1, b1) := extract_moves nil b in
      match b1 with
      | Lload chunk' addr' args' dst' :: b2 =>
          if chunk_eq chunk Mint64 && Archi.splitlong then
            assertion (chunk_eq chunk' Mint32);
            let (mv2, b3) := extract_moves nil b2 in
            match b3 with
            | Lload chunk'' addr'' args'' dst'' :: b4 =>
                let (mv3, b5) := extract_moves nil b4 in
                assertion (chunk_eq chunk'' Mint32);
                assertion (eq_addressing addr addr');
                assertion (option_eq eq_addressing (offset_addressing addr 4) (Some addr''));
                assertion (check_succ s b5);
                Some(BSload2 addr addr'' args dst mv1 args' dst' mv2 args'' dst'' mv3 s)
            | _ =>
                assertion (check_succ s b3);
                if (eq_addressing addr addr') then
                  Some(BSload2_1 addr args dst mv1 args' dst' mv2 s)
                else
                 (assertion (option_eq eq_addressing (offset_addressing addr 4) (Some addr'));
                  Some(BSload2_2 addr addr' args dst mv1 args' dst' mv2 s))
            end
          else (
            let (mv2, b3) := extract_moves nil b2 in
            assertion (chunk_eq chunk chunk');
            assertion (eq_addressing addr addr');
            assertion (check_succ s b3);
            Some(BSload chunk addr args dst mv1 args' dst' mv2 s))
      | _ =>
          assertion (check_succ s b1);
          Some(BSloaddead chunk addr args dst mv1 s)
      end
  | Istore chunk addr args src s =>
      let (mv1, b1) := extract_moves nil b in
      match b1 with
      | Lstore chunk' addr' args' src' :: b2 =>
          if chunk_eq chunk Mint64 && Archi.splitlong then
            let (mv2, b3) := extract_moves nil b2 in
            match b3 with
            | Lstore chunk'' addr'' args'' src'' :: b4 =>
                assertion (chunk_eq chunk' Mint32);
                assertion (chunk_eq chunk'' Mint32);
                assertion (eq_addressing addr addr');
                assertion (option_eq eq_addressing (offset_addressing addr 4) (Some addr''));
                assertion (check_succ s b4);
                Some(BSstore2 addr addr'' args src mv1 args' src' mv2 args'' src'' s)
            | _ => None
            end
          else (
            assertion (chunk_eq chunk chunk');
            assertion (eq_addressing addr addr');
            assertion (check_succ s b2);
            Some(BSstore chunk addr args src mv1 args' src' s))
      | _ => None
      end
  | Icall sg ros args res s =>
      let (mv1, b1) := extract_moves_ext nil b in
      match b1 with
      | Lcall sg' ros' :: b2 =>
          let (mv2, b3) := extract_moves_ext nil b2 in
          assertion (signature_eq sg sg');
          assertion (check_succ s b3);
          Some(BScall sg ros args res mv1 ros' mv2 s)
      | _ => None
      end
  | Itailcall sg ros args =>
      let (mv1, b1) := extract_moves_ext nil b in
      match b1 with
      | Ltailcall sg' ros' :: b2 =>
          assertion (signature_eq sg sg');
          Some(BStailcall sg ros args mv1 ros')
      | _ => None
      end
  | Ibuiltin ef args res s =>
      let (mv1, b1) := extract_moves nil b in
      match b1 with
      | Lbuiltin ef' args' res' :: b2 =>
          let (mv2, b3) := extract_moves nil b2 in
          assertion (external_function_eq ef ef');
          assertion (check_succ s b3);
          Some(BSbuiltin ef args res mv1 args' res' mv2 s)
      | _ => None
      end
  | Icond cond args s1 s2 =>
      let (mv1, b1) := extract_moves nil b in
      match b1 with
      | Lcond cond' args' s1' s2' :: b2 =>
          assertion (eq_condition cond cond');
          assertion (peq s1 s1');
          assertion (peq s2 s2');
          Some(BScond cond args mv1 args' s1 s2)
      | _ => None
      end
  | Ijumptable arg tbl =>
      let (mv1, b1) := extract_moves nil b in
      match b1 with
      | Ljumptable arg' tbl' :: b2 =>
          assertion (list_eq_dec peq tbl tbl');
          Some(BSjumptable arg mv1 arg' tbl)
      | _ => None
      end
  | Ireturn arg =>
      let (mv1, b1) := extract_moves_ext nil b in
      match b1 with
      | Lreturn :: b2 => Some(BSreturn arg mv1)
      | _ => None
      end
  end.(** Check all instructions of the RTL function [f1] against the corresponding
  basic blocks of LTL function [f2].  Return a map from CFG nodes to
  [block_shape] info. *)

Definition pair_codes (f1: RTL.function) (f2: LTL.function) : PTree.t block_shape :=
  PTree.combine
    (fun opti optb => do i <- opti; do b <- optb; pair_instr_block i b)
    (RTL.fn_code f1) (LTL.fn_code f2).(** * Representing sets of equations between RTL registers and LTL locations. *)

(** The Rideau-Leroy validation algorithm manipulates sets of equations of
  the form [pseudoreg = location [kind]], meaning:
- if [kind = Full], the value of [location] in the generated LTL code is
  the same as (or more defined than) the value of [pseudoreg] in the original
  RTL code;
- if [kind = Low], the value of [location] in the generated LTL code is
  the same as (or more defined than) the low 32 bits of the 64-bit
  integer value of [pseudoreg] in the original RTL code;
- if [kind = High], the value of [location] in the generated LTL code is
  the same as (or more defined than) the high 32 bits of the 64-bit
  integer value of [pseudoreg] in the original RTL code.
*)

Inductive equation_kind : Type := Full | Low | High.(** * Representing sets of equations between RTL registers and LTL locations. *)

(** The Rideau-Leroy validation algorithm manipulates sets of equations of
  the form [pseudoreg = location [kind]], meaning:
- if [kind = Full], the value of [location] in the generated LTL code is
  the same as (or more defined than) the value of [pseudoreg] in the original
  RTL code;
- if [kind = Low], the value of [location] in the generated LTL code is
  the same as (or more defined than) the low 32 bits of the 64-bit
  integer value of [pseudoreg] in the original RTL code;
- if [kind = High], the value of [location] in the generated LTL code is
  the same as (or more defined than) the high 32 bits of the 64-bit
  integer value of [pseudoreg] in the original RTL code.
*)

Inductive equation_kind : Type := Full | Low | High.(** * Representing sets of equations between RTL registers and LTL locations. *)

(** The Rideau-Leroy validation algorithm manipulates sets of equations of
  the form [pseudoreg = location [kind]], meaning:
- if [kind = Full], the value of [location] in the generated LTL code is
  the same as (or more defined than) the value of [pseudoreg] in the original
  RTL code;
- if [kind = Low], the value of [location] in the generated LTL code is
  the same as (or more defined than) the low 32 bits of the 64-bit
  integer value of [pseudoreg] in the original RTL code;
- if [kind = High], the value of [location] in the generated LTL code is
  the same as (or more defined than) the high 32 bits of the 64-bit
  integer value of [pseudoreg] in the original RTL code.
*)

Inductive equation_kind : Type := Full | Low | High.(** * Representing sets of equations between RTL registers and LTL locations. *)

(** The Rideau-Leroy validation algorithm manipulates sets of equations of
  the form [pseudoreg = location [kind]], meaning:
- if [kind = Full], the value of [location] in the generated LTL code is
  the same as (or more defined than) the value of [pseudoreg] in the original
  RTL code;
- if [kind = Low], the value of [location] in the generated LTL code is
  the same as (or more defined than) the low 32 bits of the 64-bit
  integer value of [pseudoreg] in the original RTL code;
- if [kind = High], the value of [location] in the generated LTL code is
  the same as (or more defined than) the high 32 bits of the 64-bit
  integer value of [pseudoreg] in the original RTL code.
*)

Inductive equation_kind : Type := Full | Low | High.Record equation := Eq {
  ekind: equation_kind;
  ereg: reg;
  eloc: loc
}.Record equation := Eq {
  ekind: equation_kind;
  ereg: reg;
  eloc: loc
}.Record equation := Eq {
  ekind: equation_kind;
  ereg: reg;
  eloc: loc
}.Record equation := Eq {
  ekind: equation_kind;
  ereg: reg;
  eloc: loc
}.Record equation := Eq {
  ekind: equation_kind;
  ereg: reg;
  eloc: loc
}.Definition t := equation_kind.Definition index (x: t) :=
    match x with Full => 1%positive | Low => 2%positive | High => 3%positive end.

Lemma index_inj: forall x y, index x = index y -> x = y.