diff options
62 files changed, 26547 insertions, 2405 deletions
diff --git a/aarch64/Asm.v b/aarch64/Asm.v index 38cf8259..8d3d4ff7 100644 --- a/aarch64/Asm.v +++ b/aarch64/Asm.v @@ -10,13 +10,20 @@ (* *) (* *********************************************************************) -(** Abstract syntax and semantics for AArch64 assembly language *) +(** Abstract syntax and semantics for AArch64 assembly language + +W.r.t Asmblock, this is a "flat" syntax and semantics of "aarch64" assembly: + - without the basic block structure + - without the hierarchy of instructions. + +*) Require Import Coqlib Zbits Maps. Require Import AST Integers Floats. Require Import Values Memory Events Globalenvs Smallstep. Require Import Locations Conventions. Require Stacklayout. +Require Import OptionMonad. (** * Abstract syntax *) @@ -43,6 +50,9 @@ Coercion RR1: ireg >-> iregsp. Lemma ireg_eq: forall (x y: ireg), {x=y} + {x<>y}. Proof. decide equality. Defined. +Lemma iregsp_eq: forall (x y: iregsp), {x=y} + {x<>y}. +Proof. decide equality; apply ireg_eq. Defined. + (** In assembly files, [Dn] denotes the low 64-bit of a vector register, and [Sn] the low 32 bits. *) @@ -66,21 +76,29 @@ Inductive crbit: Type := Lemma crbit_eq: forall (x y: crbit), {x=y} + {x<>y}. Proof. decide equality. Defined. +Inductive dreg : Type := + | IR: iregsp -> dreg (**r 64- or 32-bit integer registers *) + | FR: freg -> dreg. (**r double- or single-precision float registers *) + (** We model the following registers of the ARM architecture. *) Inductive preg: Type := - | IR: ireg -> preg (**r 64- or 32-bit integer registers *) - | FR: freg -> preg (**r double- or single-precision float registers *) - | CR: crbit -> preg (**r bits in the condition register *) - | SP: preg (**r register X31 used as stack pointer *) - | PC: preg. (**r program counter *) - -Coercion IR: ireg >-> preg. -Coercion FR: freg >-> preg. + | DR: dreg -> preg (** see dreg **) + | CR: crbit -> preg (**r bits in the condition register *) + | PC: preg. (**r program counter *) + +(* XXX: ireg no longer coerces to preg *) +Coercion IR: iregsp >-> dreg. +Coercion FR: freg >-> dreg. +Coercion DR: dreg >-> preg. +Definition SP:preg := XSP. Coercion CR: crbit >-> preg. +Lemma dreg_eq: forall (x y: dreg), {x=y} + {x<>y}. +Proof. decide equality. apply iregsp_eq. apply freg_eq. Defined. + Lemma preg_eq: forall (x y: preg), {x=y} + {x<>y}. -Proof. decide equality. apply ireg_eq. apply freg_eq. apply crbit_eq. Defined. +Proof. decide equality. apply dreg_eq. apply crbit_eq. Defined. Module PregEq. Definition t := preg. @@ -92,8 +110,6 @@ Module Pregmap := EMap(PregEq). Definition preg_of_iregsp (r: iregsp) : preg := match r with RR1 r => IR r | XSP => SP end. -Coercion preg_of_iregsp: iregsp >-> preg. - (** Conventional name for return address ([RA]) *) Notation "'RA'" := X30 (only parsing) : asm. @@ -307,9 +323,30 @@ Definition code := list instruction. Record function : Type := mkfunction { fn_sig: signature; fn_code: code }. Definition fundef := AST.fundef function. Definition program := AST.program fundef unit. +Definition genv := Genv.t fundef unit. + +(** The two functions below axiomatize how the linker processes + symbolic references [symbol + offset]. It computes the + difference between the address and the PC, and splits it into: + - 12 low bits usable as an offset in an addressing mode; + - 21 high bits usable as argument to the ADRP instruction. + + In CompCert's model, we cannot really describe PC-relative addressing, + but we can claim that the address of [symbol + offset] decomposes + as the sum of + - a low part, usable as an offset in an addressing mode; + - a high part, usable as argument to the ADRP instruction. *) + +Parameter symbol_low: genv -> ident -> ptrofs -> val. +Parameter symbol_high: genv -> ident -> ptrofs -> val. + +Axiom symbol_high_low: + forall (ge: genv) (id: ident) (ofs: ptrofs), + Val.addl (symbol_high ge id ofs) (symbol_low ge id ofs) = Genv.symbol_address ge id ofs. (** * Operational semantics *) + (** The semantics operates over a single mapping from registers (type [preg]) to values. We maintain (but do not enforce) the convention that integer registers are mapped to values of @@ -317,22 +354,19 @@ Definition program := AST.program fundef unit. and condition bits to either [Vzero] or [Vone]. *) Definition regset := Pregmap.t val. -Definition genv := Genv.t fundef unit. (** The value of an [ireg0] is either the value of the integer register, or 0. *) -Definition ir0w (rs: regset) (r: ireg0) : val := - match r with RR0 r => rs (IR r) | XZR => Vint Int.zero end. -Definition ir0x (rs: regset) (r: ireg0) : val := - match r with RR0 r => rs (IR r) | XZR => Vlong Int64.zero end. +Definition ir0 (is:isize) (rs: regset) (r: ireg0) : val := + match r with RR0 r => rs (IR r) | XZR => if is (* is W *) then Vint Int.zero else Vlong Int64.zero end. (** Concise notations for accessing and updating the values of registers. *) Notation "a # b" := (a b) (at level 1, only parsing) : asm. Notation "a # b <- c" := (Pregmap.set b c a) (at level 1, b at next level) : asm. -Notation "a ## b" := (ir0w a b) (at level 1, only parsing) : asm. -Notation "a ### b" := (ir0x a b) (at level 1, only parsing) : asm. +Notation "a ## b" := (ir0 W a b) (at level 1, only parsing) : asm. +Notation "a ### b" := (ir0 X a b) (at level 1, only parsing) : asm. Open Scope asm. @@ -366,84 +400,70 @@ Fixpoint set_res (res: builtin_res preg) (v: val) (rs: regset) : regset := | BR_splitlong hi lo => set_res lo (Val.loword v) (set_res hi (Val.hiword v) rs) end. -(** The two functions below axiomatize how the linker processes - symbolic references [symbol + offset]. It computes the - difference between the address and the PC, and splits it into: - - 12 low bits usable as an offset in an addressing mode; - - 21 high bits usable as argument to the ADRP instruction. - - In CompCert's model, we cannot really describe PC-relative addressing, - but we can claim that the address of [symbol + offset] decomposes - as the sum of - - a low part, usable as an offset in an addressing mode; - - a high part, usable as argument to the ADRP instruction. *) - -Parameter symbol_low: genv -> ident -> ptrofs -> val. -Parameter symbol_high: genv -> ident -> ptrofs -> val. +(** The semantics is purely small-step and defined as a function + from the current state (a register set + a memory state) + to either [Next rs' m'] where [rs'] and [m'] are the updated register + set and memory state after execution of the instruction at [rs#PC], + or [Stuck] if the processor is stuck. *) -Axiom symbol_high_low: - forall (ge: genv) (id: ident) (ofs: ptrofs), - Val.addl (symbol_high ge id ofs) (symbol_low ge id ofs) = Genv.symbol_address ge id ofs. +Record state: Type := State { _rs: regset; _m: mem }. +Definition outcome := option state. +Definition Next rs m: outcome := Some (State rs m). +Definition Stuck: outcome := None. -Section RELSEM. -Variable ge: genv. +(* a few lemma on comparisons of unsigned (e.g. pointers) -(** Looking up instructions in a code sequence by position. *) +TODO: these lemma are a copy/paste of kvx/Asmvliw.v (sharing to improve!) +*) -Fixpoint find_instr (pos: Z) (c: code) {struct c} : option instruction := - match c with - | nil => None - | i :: il => if zeq pos 0 then Some i else find_instr (pos - 1) il - end. +Definition Val_cmpu_bool cmp v1 v2: option bool := + Val.cmpu_bool (fun _ _ => true) cmp v1 v2. -(** Position corresponding to a label *) +Lemma Val_cmpu_bool_correct (m:mem) (cmp: comparison) (v1 v2: val) b: + (Val.cmpu_bool (Mem.valid_pointer m) cmp v1 v2) = Some b + -> (Val_cmpu_bool cmp v1 v2) = Some b. +Proof. + intros; eapply Val.cmpu_bool_lessdef; (econstructor 1 || eauto). +Qed. -Definition is_label (lbl: label) (instr: instruction) : bool := - match instr with - | Plabel lbl' => if peq lbl lbl' then true else false - | _ => false - end. +Definition Val_cmpu cmp v1 v2 := Val.of_optbool (Val_cmpu_bool cmp v1 v2). -Lemma is_label_correct: - forall lbl instr, - if is_label lbl instr then instr = Plabel lbl else instr <> Plabel lbl. +Lemma Val_cmpu_correct (m:mem) (cmp: comparison) (v1 v2: val): + Val.lessdef (Val.cmpu (Mem.valid_pointer m) cmp v1 v2) + (Val_cmpu cmp v1 v2). Proof. - intros. destruct instr; simpl; try discriminate. destruct (peq lbl lbl0); congruence. + unfold Val.cmpu, Val_cmpu. + remember (Val.cmpu_bool (Mem.valid_pointer m) cmp v1 v2) as ob. + destruct ob; simpl. + - erewrite Val_cmpu_bool_correct; eauto. + econstructor. + - econstructor. Qed. -Fixpoint label_pos (lbl: label) (pos: Z) (c: code) {struct c} : option Z := - match c with - | nil => None - | instr :: c' => - if is_label lbl instr then Some (pos + 1) else label_pos lbl (pos + 1) c' - end. - -(** The semantics is purely small-step and defined as a function - from the current state (a register set + a memory state) - to either [Next rs' m'] where [rs'] and [m'] are the updated register - set and memory state after execution of the instruction at [rs#PC], - or [Stuck] if the processor is stuck. *) +Definition Val_cmplu_bool (cmp: comparison) (v1 v2: val) + := (Val.cmplu_bool (fun _ _ => true) cmp v1 v2). -Inductive outcome: Type := - | Next: regset -> mem -> outcome - | Stuck: outcome. +Lemma Val_cmplu_bool_correct (m:mem) (cmp: comparison) (v1 v2: val) b: + (Val.cmplu_bool (Mem.valid_pointer m) cmp v1 v2) = Some b + -> (Val_cmplu_bool cmp v1 v2) = Some b. +Proof. + intros; eapply Val.cmplu_bool_lessdef; (econstructor 1 || eauto). +Qed. -(** Manipulations over the [PC] register: continuing with the next - instruction ([nextinstr]) or branching to a label ([goto_label]). *) +Definition Val_cmplu cmp v1 v2 := Val.of_optbool (Val_cmplu_bool cmp v1 v2). -Definition nextinstr (rs: regset) := - rs#PC <- (Val.offset_ptr rs#PC Ptrofs.one). - -Definition goto_label (f: function) (lbl: label) (rs: regset) (m: mem) := - match label_pos lbl 0 (fn_code f) with - | None => Stuck - | Some pos => - match rs#PC with - | Vptr b ofs => Next (rs#PC <- (Vptr b (Ptrofs.repr pos))) m - | _ => Stuck - end - end. +Lemma Val_cmplu_correct (m:mem) (cmp: comparison) (v1 v2: val): + Val.lessdef (Val.maketotal (Val.cmplu (Mem.valid_pointer m) cmp v1 v2)) + (Val_cmplu cmp v1 v2). +Proof. + unfold Val.cmplu, Val_cmplu. + remember (Val.cmplu_bool (Mem.valid_pointer m) cmp v1 v2) as ob. + destruct ob as [b|]; simpl. + - erewrite Val_cmplu_bool_correct; eauto. + simpl. econstructor. + - econstructor. +Qed. (** Testing a condition *) @@ -513,10 +533,10 @@ Definition eval_testcond (c: testcond) (rs: regset) : option bool := (** Integer "is zero?" test *) -Definition eval_testzero (sz: isize) (v: val) (m: mem): option bool := +Definition eval_testzero (sz: isize) (v: val): option bool := match sz with - | W => Val.cmpu_bool (Mem.valid_pointer m) Ceq v (Vint Int.zero) - | X => Val.cmplu_bool (Mem.valid_pointer m) Ceq v (Vlong Int64.zero) + | W => Val_cmpu_bool Ceq v (Vint Int.zero) + | X => Val_cmplu_bool Ceq v (Vlong Int64.zero) end. (** Integer "bit is set?" test *) @@ -527,48 +547,19 @@ Definition eval_testbit (sz: isize) (v: val) (n: int): option bool := | X => Val.cmpl_bool Cne (Val.andl v (Vlong (Int64.shl' Int64.one n))) (Vlong Int64.zero) end. -(** Evaluating an addressing mode *) - -Definition eval_addressing (a: addressing) (rs: regset): val := - match a with - | ADimm base n => Val.addl rs#base (Vlong n) - | ADreg base r => Val.addl rs#base rs#r - | ADlsl base r n => Val.addl rs#base (Val.shll rs#r (Vint n)) - | ADsxt base r n => Val.addl rs#base (Val.shll (Val.longofint rs#r) (Vint n)) - | ADuxt base r n => Val.addl rs#base (Val.shll (Val.longofintu rs#r) (Vint n)) - | ADadr base id ofs => Val.addl rs#base (symbol_low ge id ofs) - | ADpostincr base n => Vundef (* not modeled yet *) - end. - -(** Auxiliaries for memory accesses *) - -Definition exec_load (chunk: memory_chunk) (transf: val -> val) - (a: addressing) (r: preg) (rs: regset) (m: mem) := - match Mem.loadv chunk m (eval_addressing a rs) with - | None => Stuck - | Some v => Next (nextinstr (rs#r <- (transf v))) m - end. - -Definition exec_store (chunk: memory_chunk) - (a: addressing) (v: val) - (rs: regset) (m: mem) := - match Mem.storev chunk m (eval_addressing a rs) v with - | None => Stuck - | Some m' => Next (nextinstr rs) m' - end. (** Comparisons *) -Definition compare_int (rs: regset) (v1 v2: val) (m: mem) := +Definition compare_int (rs: regset) (v1 v2: val) := rs#CN <- (Val.negative (Val.sub v1 v2)) - #CZ <- (Val.cmpu (Mem.valid_pointer m) Ceq v1 v2) - #CC <- (Val.cmpu (Mem.valid_pointer m) Cge v1 v2) + #CZ <- (Val_cmpu Ceq v1 v2) + #CC <- (Val_cmpu Cge v1 v2) #CV <- (Val.sub_overflow v1 v2). -Definition compare_long (rs: regset) (v1 v2: val) (m: mem) := +Definition compare_long (rs: regset) (v1 v2: val) := rs#CN <- (Val.negativel (Val.subl v1 v2)) - #CZ <- (Val.maketotal (Val.cmplu (Mem.valid_pointer m) Ceq v1 v2)) - #CC <- (Val.maketotal (Val.cmplu (Mem.valid_pointer m) Cge v1 v2)) + #CZ <- (Val_cmplu Ceq v1 v2) + #CC <- (Val_cmplu Cge v1 v2) #CV <- (Val.subl_overflow v1 v2). (** Semantics of [fcmp] instructions: @@ -669,18 +660,153 @@ Definition float64_of_bits (v: val): val := | _ => Vundef end. -(** Execution of a single instruction [i] in initial state - [rs] and [m]. Return updated state. For instructions - that correspond to actual AArch64 instructions, the cases are - straightforward transliterations of the informal descriptions - given in the ARMv8 reference manuals. For pseudo-instructions, - refer to the informal descriptions given above. - - Note that we set to [Vundef] the registers used as temporaries by - the expansions of the pseudo-instructions, so that the code we - generate cannot use those registers to hold values that must - survive the execution of the pseudo-instruction. -*) + +(** Translation of the LTL/Linear/Mach view of machine registers + to the AArch64 view. Note that no LTL register maps to [X16], + [X18], nor [X30]. + [X18] is reserved as the platform register and never used by the + code generated by CompCert. + [X30] is used for the return address, and can also be used as temporary. + [X16] can be used as temporary. *) + +Definition dreg_of (r: mreg) : dreg := + match r with + | R0 => X0 | R1 => X1 | R2 => X2 | R3 => X3 + | R4 => X4 | R5 => X5 | R6 => X6 | R7 => X7 + | R8 => X8 | R9 => X9 | R10 => X10 | R11 => X11 + | R12 => X12 | R13 => X13 | R14 => X14 | R15 => X15 + | R17 => X17 | R19 => X19 + | R20 => X20 | R21 => X21 | R22 => X22 | R23 => X23 + | R24 => X24 | R25 => X25 | R26 => X26 | R27 => X27 + | R28 => X28 | R29 => X29 + | F0 => D0 | F1 => D1 | F2 => D2 | F3 => D3 + | F4 => D4 | F5 => D5 | F6 => D6 | F7 => D7 + | F8 => D8 | F9 => D9 | F10 => D10 | F11 => D11 + | F12 => D12 | F13 => D13 | F14 => D14 | F15 => D15 + | F16 => D16 | F17 => D17 | F18 => D18 | F19 => D19 + | F20 => D20 | F21 => D21 | F22 => D22 | F23 => D23 + | F24 => D24 | F25 => D25 | F26 => D26 | F27 => D27 + | F28 => D28 | F29 => D29 | F30 => D30 | F31 => D31 + end. + +Definition preg_of (r: mreg) : preg := + dreg_of r. + +(** Undefine all registers except SP and callee-save registers *) + +Definition undef_caller_save_regs (rs: regset) : regset := + fun r => + if preg_eq r SP + || In_dec preg_eq r (List.map preg_of (List.filter is_callee_save all_mregs)) + then rs r + else Vundef. + +(** Extract the values of the arguments of an external call. + We exploit the calling conventions from module [Conventions], except that + we use AArch64 registers instead of locations. *) + +Inductive extcall_arg (rs: regset) (m: mem): loc -> val -> Prop := + | extcall_arg_reg: forall r, + extcall_arg rs m (R r) (rs (preg_of r)) + | extcall_arg_stack: forall ofs ty bofs v, + bofs = Stacklayout.fe_ofs_arg + 4 * ofs -> + Mem.loadv (chunk_of_type ty) m + (Val.offset_ptr rs#SP (Ptrofs.repr bofs)) = Some v -> + extcall_arg rs m (Locations.S Outgoing ofs ty) v. + +Inductive extcall_arg_pair (rs: regset) (m: mem): rpair loc -> val -> Prop := + | extcall_arg_one: forall l v, + extcall_arg rs m l v -> + extcall_arg_pair rs m (One l) v + | extcall_arg_twolong: forall hi lo vhi vlo, + extcall_arg rs m hi vhi -> + extcall_arg rs m lo vlo -> + extcall_arg_pair rs m (Twolong hi lo) (Val.longofwords vhi vlo). + +Definition extcall_arguments + (rs: regset) (m: mem) (sg: signature) (args: list val) : Prop := + list_forall2 (extcall_arg_pair rs m) (loc_arguments sg) args. + +Definition loc_external_result (sg: signature) : rpair preg := + map_rpair preg_of (loc_result sg). + +(** Looking up instructions in a code sequence by position. *) + +Fixpoint find_instr (pos: Z) (c: code) {struct c} : option instruction := + match c with + | nil => None + | i :: il => if zeq pos 0 then Some i else find_instr (pos - 1) il + end. + +(** Position corresponding to a label *) + +Definition is_label (lbl: label) (instr: instruction) : bool := + match instr with + | Plabel lbl' => if peq lbl lbl' then true else false + | _ => false + end. + +Lemma is_label_correct: + forall lbl instr, + if is_label lbl instr then instr = Plabel lbl else instr <> Plabel lbl. +Proof. + intros. destruct instr; simpl; try discriminate. destruct (peq lbl lbl0); congruence. +Qed. + +Fixpoint label_pos (lbl: label) (pos: Z) (c: code) {struct c} : option Z := + match c with + | nil => None + | instr :: c' => + if is_label lbl instr then Some pos else label_pos lbl (pos + 1) c' + end. + +Definition nextinstr (rs: regset) := + rs#PC <- (Val.offset_ptr rs#PC Ptrofs.one). + +Definition goto_label (f: function) (lbl: label) (rs: regset) (m: mem) := + match label_pos lbl 0 (fn_code f) with + | None => Stuck + | Some pos => + match rs#PC with + | Vptr b ofs => Next (rs#PC <- (Vptr b (Ptrofs.repr pos))) m + | _ => Stuck + end + end. + +Section RELSEM. + +Variable ge: genv. + +(** Evaluating an addressing mode *) + +Definition eval_addressing (a: addressing) (rs: regset): val := + match a with + | ADimm base n => Val.addl rs#base (Vlong n) + | ADreg base r => Val.addl rs#base rs#r + | ADlsl base r n => Val.addl rs#base (Val.shll rs#r (Vint n)) + | ADsxt base r n => Val.addl rs#base (Val.shll (Val.longofint rs#r) (Vint n)) + | ADuxt base r n => Val.addl rs#base (Val.shll (Val.longofintu rs#r) (Vint n)) + | ADadr base id ofs => Val.addl rs#base (symbol_low ge id ofs) + | ADpostincr base n => Vundef (* not modeled yet *) + end. + +(** Auxiliaries for memory accesses *) + +Definition exec_load (chunk: memory_chunk) (transf: val -> val) + (a: addressing) (r: preg) (rs: regset) (m: mem) := + match Mem.loadv chunk m (eval_addressing a rs) with + | None => Stuck + | Some v => Next (nextinstr (rs#r <- (transf v))) m + end. + +Definition exec_store (chunk: memory_chunk) + (a: addressing) (v: val) + (rs: regset) (m: mem) := + match Mem.storev chunk m (eval_addressing a rs) v with + | None => Stuck + | Some m' => Next (nextinstr rs) m' + end. + Definition exec_instr (f: function) (i: instruction) (rs: regset) (m: mem) : outcome := match i with @@ -704,13 +830,13 @@ Definition exec_instr (f: function) (i: instruction) (rs: regset) (m: mem) : out | Pret r => Next (rs#PC <- (rs#r)) m | Pcbnz sz r lbl => - match eval_testzero sz rs#r m with + match eval_testzero sz rs#r with | Some true => Next (nextinstr rs) m | Some false => goto_label f lbl rs m | None => Stuck end | Pcbz sz r lbl => - match eval_testzero sz rs#r m with + match eval_testzero sz rs#r with | Some true => goto_label f lbl rs m | Some false => Next (nextinstr rs) m | None => Stuck @@ -778,13 +904,13 @@ Definition exec_instr (f: function) (i: instruction) (rs: regset) (m: mem) : out | Psubimm X rd r1 n => Next (nextinstr (rs#rd <- (Val.subl rs#r1 (Vlong (Int64.repr n))))) m | Pcmpimm W r1 n => - Next (nextinstr (compare_int rs rs#r1 (Vint (Int.repr n)) m)) m + Next (nextinstr (compare_int rs rs#r1 (Vint (Int.repr n)))) m | Pcmpimm X r1 n => - Next (nextinstr (compare_long rs rs#r1 (Vlong (Int64.repr n)) m)) m + Next (nextinstr (compare_long rs rs#r1 (Vlong (Int64.repr n)))) m | Pcmnimm W r1 n => - Next (nextinstr (compare_int rs rs#r1 (Vint (Int.neg (Int.repr n))) m)) m + Next (nextinstr (compare_int rs rs#r1 (Vint (Int.neg (Int.repr n))))) m | Pcmnimm X r1 n => - Next (nextinstr (compare_long rs rs#r1 (Vlong (Int64.neg (Int64.repr n))) m)) m + Next (nextinstr (compare_long rs rs#r1 (Vlong (Int64.neg (Int64.repr n))))) m (** Move integer register *) | Pmov rd r1 => Next (nextinstr (rs#rd <- (rs#r1))) m @@ -802,9 +928,9 @@ Definition exec_instr (f: function) (i: instruction) (rs: regset) (m: mem) : out | Porrimm X rd r1 n => Next (nextinstr (rs#rd <- (Val.orl rs###r1 (Vlong (Int64.repr n))))) m | Ptstimm W r1 n => - Next (nextinstr (compare_int rs (Val.and rs#r1 (Vint (Int.repr n))) (Vint Int.zero) m)) m + Next (nextinstr (compare_int rs (Val.and rs#r1 (Vint (Int.repr n))) (Vint Int.zero))) m | Ptstimm X r1 n => - Next (nextinstr (compare_long rs (Val.andl rs#r1 (Vlong (Int64.repr n))) (Vlong Int64.zero) m)) m + Next (nextinstr (compare_long rs (Val.andl rs#r1 (Vlong (Int64.repr n))) (Vlong Int64.zero))) m (** Move wide immediate *) | Pmovz W rd n pos => Next (nextinstr (rs#rd <- (Vint (Int.repr (Z.shiftl n pos))))) m @@ -850,22 +976,22 @@ Definition exec_instr (f: function) (i: instruction) (rs: regset) (m: mem) : out | Psub X rd r1 r2 s => Next (nextinstr (rs#rd <- (Val.subl rs###r1 (eval_shift_op_long rs#r2 s)))) m | Pcmp W r1 r2 s => - Next (nextinstr (compare_int rs rs##r1 (eval_shift_op_int rs#r2 s) m)) m + Next (nextinstr (compare_int rs rs##r1 (eval_shift_op_int rs#r2 s))) m | Pcmp X r1 r2 s => - Next (nextinstr (compare_long rs rs###r1 (eval_shift_op_long rs#r2 s) m)) m + Next (nextinstr (compare_long rs rs###r1 (eval_shift_op_long rs#r2 s))) m | Pcmn W r1 r2 s => - Next (nextinstr (compare_int rs rs##r1 (Val.neg (eval_shift_op_int rs#r2 s)) m)) m + Next (nextinstr (compare_int rs rs##r1 (Val.neg (eval_shift_op_int rs#r2 s)))) m | Pcmn X r1 r2 s => - Next (nextinstr (compare_long rs rs###r1 (Val.negl (eval_shift_op_long rs#r2 s)) m)) m + Next (nextinstr (compare_long rs rs###r1 (Val.negl (eval_shift_op_long rs#r2 s)))) m (** Integer arithmetic, extending register *) | Paddext rd r1 r2 x => Next (nextinstr (rs#rd <- (Val.addl rs#r1 (eval_extend rs#r2 x)))) m | Psubext rd r1 r2 x => Next (nextinstr (rs#rd <- (Val.subl rs#r1 (eval_extend rs#r2 x)))) m | Pcmpext r1 r2 x => - Next (nextinstr (compare_long rs rs#r1 (eval_extend rs#r2 x) m)) m + Next (nextinstr (compare_long rs rs#r1 (eval_extend rs#r2 x))) m | Pcmnext r1 r2 x => - Next (nextinstr (compare_long rs rs#r1 (Val.negl (eval_extend rs#r2 x)) m)) m + Next (nextinstr (compare_long rs rs#r1 (Val.negl (eval_extend rs#r2 x)))) m (** Logical, shifted register *) | Pand W rd r1 r2 s => Next (nextinstr (rs#rd <- (Val.and rs##r1 (eval_shift_op_int rs#r2 s)))) m @@ -892,9 +1018,9 @@ Definition exec_instr (f: function) (i: instruction) (rs: regset) (m: mem) : out | Porn X rd r1 r2 s => Next (nextinstr (rs#rd <- (Val.orl rs###r1 (Val.notl (eval_shift_op_long rs#r2 s))))) m | Ptst W r1 r2 s => - Next (nextinstr (compare_int rs (Val.and rs##r1 (eval_shift_op_int rs#r2 s)) (Vint Int.zero) m)) m + Next (nextinstr (compare_int rs (Val.and rs##r1 (eval_shift_op_int rs#r2 s)) (Vint Int.zero))) m | Ptst X r1 r2 s => - Next (nextinstr (compare_long rs (Val.andl rs###r1 (eval_shift_op_long rs#r2 s)) (Vlong Int64.zero) m)) m + Next (nextinstr (compare_long rs (Val.andl rs###r1 (eval_shift_op_long rs#r2 s)) (Vlong Int64.zero))) m (** Variable shifts *) | Pasrv W rd r1 r2 => Next (nextinstr (rs#rd <- (Val.shr rs#r1 rs#r2))) m @@ -1118,80 +1244,9 @@ Definition exec_instr (f: function) (i: instruction) (rs: regset) (m: mem) : out Stuck end. -(** Translation of the LTL/Linear/Mach view of machine registers - to the AArch64 view. Note that no LTL register maps to [X16], - [X18], nor [X30]. - [X18] is reserved as the platform register and never used by the - code generated by CompCert. - [X30] is used for the return address, and can also be used as temporary. - [X16] can be used as temporary. *) - -Definition preg_of (r: mreg) : preg := - match r with - | R0 => X0 | R1 => X1 | R2 => X2 | R3 => X3 - | R4 => X4 | R5 => X5 | R6 => X6 | R7 => X7 - | R8 => X8 | R9 => X9 | R10 => X10 | R11 => X11 - | R12 => X12 | R13 => X13 | R14 => X14 | R15 => X15 - | R17 => X17 | R19 => X19 - | R20 => X20 | R21 => X21 | R22 => X22 | R23 => X23 - | R24 => X24 | R25 => X25 | R26 => X26 | R27 => X27 - | R28 => X28 | R29 => X29 - | F0 => D0 | F1 => D1 | F2 => D2 | F3 => D3 - | F4 => D4 | F5 => D5 | F6 => D6 | F7 => D7 - | F8 => D8 | F9 => D9 | F10 => D10 | F11 => D11 - | F12 => D12 | F13 => D13 | F14 => D14 | F15 => D15 - | F16 => D16 | F17 => D17 | F18 => D18 | F19 => D19 - | F20 => D20 | F21 => D21 | F22 => D22 | F23 => D23 - | F24 => D24 | F25 => D25 | F26 => D26 | F27 => D27 - | F28 => D28 | F29 => D29 | F30 => D30 | F31 => D31 - end. - -(** Undefine all registers except SP and callee-save registers *) - -Definition undef_caller_save_regs (rs: regset) : regset := - fun r => - if preg_eq r SP - || In_dec preg_eq r (List.map preg_of (List.filter is_callee_save all_mregs)) - then rs r - else Vundef. - -(** Extract the values of the arguments of an external call. - We exploit the calling conventions from module [Conventions], except that - we use AArch64 registers instead of locations. *) - -Inductive extcall_arg (rs: regset) (m: mem): loc -> val -> Prop := - | extcall_arg_reg: forall r, - extcall_arg rs m (R r) (rs (preg_of r)) - | extcall_arg_stack: forall ofs ty bofs v, - bofs = Stacklayout.fe_ofs_arg + 4 * ofs -> - Mem.loadv (chunk_of_type ty) m - (Val.offset_ptr rs#SP (Ptrofs.repr bofs)) = Some v -> - extcall_arg rs m (Locations.S Outgoing ofs ty) v. - -Inductive extcall_arg_pair (rs: regset) (m: mem): rpair loc -> val -> Prop := - | extcall_arg_one: forall l v, - extcall_arg rs m l v -> - extcall_arg_pair rs m (One l) v - | extcall_arg_twolong: forall hi lo vhi vlo, - extcall_arg rs m hi vhi -> - extcall_arg rs m lo vlo -> - extcall_arg_pair rs m (Twolong hi lo) (Val.longofwords vhi vlo). - -Definition extcall_arguments - (rs: regset) (m: mem) (sg: signature) (args: list val) : Prop := - list_forall2 (extcall_arg_pair rs m) (loc_arguments sg) args. - -Definition loc_external_result (sg: signature) : rpair preg := - map_rpair preg_of (loc_result sg). - -(** Execution of the instruction at [rs#PC]. *) - -Inductive state: Type := - | State: regset -> mem -> state. - Inductive step: state -> trace -> state -> Prop := | exec_step_internal: - forall b ofs f i rs m rs' m', + forall b ofs (f:function) i rs m rs' m', rs PC = Vptr b ofs -> Genv.find_funct_ptr ge b = Some (Internal f) -> find_instr (Ptrofs.unsigned ofs) f.(fn_code) = Some i -> @@ -1302,11 +1357,11 @@ Qed. Definition data_preg (r: preg) : bool := match r with - | IR X16 => false - | IR X30 => false - | IR _ => true - | FR _ => true + | DR (IR X16) => false + | DR (IR X30) => false + | DR (IR _) => true + | DR (FR _) => true | CR _ => false - | SP => true + (* | SP => true; subsumed by IR (iregsp) *) | PC => false end. diff --git a/aarch64/Asmblock.v b/aarch64/Asmblock.v new file mode 100644 index 00000000..5da7e20a --- /dev/null +++ b/aarch64/Asmblock.v @@ -0,0 +1,1554 @@ +(* *************************************************************) +(* *) +(* The Compcert verified compiler *) +(* *) +(* Sylvain Boulmé Grenoble-INP, VERIMAG *) +(* Justus Fasse UGA, VERIMAG *) +(* Xavier Leroy INRIA Paris-Rocquencourt *) +(* David Monniaux CNRS, VERIMAG *) +(* Cyril Six Kalray *) +(* Léo Gourdin UGA, VERIMAG *) +(* *) +(* Copyright Kalray. Copyright VERIMAG. All rights reserved. *) +(* This file is distributed under the terms of the INRIA *) +(* Non-Commercial License Agreement. *) +(* *) +(* *************************************************************) + + +(* Asmblock language for aarch64 + +WORK IN PROGRESS: we want to define an Asmblock syntax, with an Asmblock semantics +(e.g. we don't need the parallel semantics of Asmvliw) + + +NOTE: this file is inspired from + - aarch64/Asm.v + - kvx/Asmvliw.v (only the Asmblock syntax) + - kvx/Asmblock.v +*) + + +(** Abstract syntax and semantics for AArch64 assembly language *) + +Require Import Coqlib Zbits Maps. +Require Import AST Integers Floats. +Require Import Values Memory Events Globalenvs Smallstep. +Require Import Locations Conventions. +Require Stacklayout. +Require Import OptionMonad Asm. +Require Export Asm. + +Local Open Scope option_monad_scope. + +(** * Abstract syntax *) + +(* First task: splitting the big [instruction] type below into CFI and basic instructions. + Actually a finer splitting in order to regroup "similar" instructions could be much better for automation of the scheduler proof! + e.g. "similar" means identical "interface" w.r.t. pseudo-registers when translated to AbstractBB, + or with a "similar" semantics. + + see example of loads below. +*) + +(** Control Flow instructions + +*) +Inductive cf_instruction : Type := + | Pb (lbl: label) (**r branch *) + | Pbc (c: testcond) (lbl: label) (**r conditional branch *) + | Pbl (id: ident) (sg: signature) (**r jump to function and link *) + | Pbs (id: ident) (sg: signature) (**r jump to function *) + | Pblr (r: ireg) (sg: signature) (**r indirect jump and link *) + | Pbr (r: ireg) (sg: signature) (**r indirect jump *) + | Pret (r: ireg) (**r return *) + | Pcbnz (sz: isize) (r: ireg) (lbl: label) (**r branch if not zero *) + | Pcbz (sz: isize) (r: ireg) (lbl: label) (**r branch if zero *) + | Ptbnz (sz: isize) (r: ireg) (n: int) (lbl: label) (**r branch if bit n is not zero *) + | Ptbz (sz: isize) (r: ireg) (n: int) (lbl: label) (**r branch if bit n is zero *) + (** Pseudo-instructions *) + | Pbtbl (r1: ireg) (tbl: list label) (**r N-way branch through a jump table *) + . + +(* +A builtin is considered as a control-flow instruction, because it could emit a trace (cf. Machblock semantics). +Here, we do not need to have builtins alone in basic-blocks (on the contrary to KVX bundles). +*) + +Inductive control: Type := + | PCtlFlow (i: cf_instruction) + (** Pseudo-instructions *) + | Pbuiltin (ef: external_function) + (args: list (builtin_arg dreg)) (res: builtin_res dreg) (**r built-in function (pseudo) *) + . + +Coercion PCtlFlow: cf_instruction >-> control. + +(** Basic instructions *) + +(* Loads waiting for (rd: dreg) (a: addressing) + * XXX Use dreg because exec_load is defined in terms of it, thus allowing us to + * treat integer and floating point loads the same. *) +Inductive load_rd_a: Type := + (* Integer load *) + | Pldrw (**r load int32 *) + | Pldrw_a (**r load int32 as any32 *) + | Pldrx (**r load int64 *) + | Pldrx_a (**r load int64 as any64 *) + | Pldrb (sz: isize) (**r load int8, zero-extend *) + | Pldrsb (sz: isize) (**r load int8, sign-extend *) + | Pldrh (sz: isize) (**r load int16, zero-extend *) + | Pldrsh (sz: isize) (**r load int16, sign-extend *) + | Pldrzw (**r load int32, zero-extend to int64 *) + | Pldrsw (**r load int32, sign-extend to int64 *) + (* Floating-point load *) + | Pldrs (**r load float32 (single precision) *) + | Pldrd (**r load float64 (double precision) *) + | Pldrd_a (**r load float64 as any64 *) + . + +(* Actually, Pldp is not used in the aarch64/Asm semantics! + +Thus we skip this particular case: + +Inductive ld_instruction: Type := + | PLd_rd_a (ld: load_rd_a) (rd: ireg) (a: addressing) + | Pldp (rd1 rd2: ireg) (a: addressing) (**r load two int64 *) + . + +Coercion PLoad: ld_instruction >-> basic. + +*) + +Inductive store_rs_a : Type := + (* Integer store *) + | Pstrw (**r store int32 *) + | Pstrw_a (**r store int32 as any32 *) + | Pstrx (**r store int64 *) + | Pstrx_a (**r store int64 as any64 *) + | Pstrb (**r store int8 *) + | Pstrh (**r store int16 *) + (* Floating-point store *) + | Pstrs (**r store float32 *) + | Pstrd (**r store float64 *) + | Pstrd_a (**r store float64 as any64 *) + . +(* Actually, Pstp is not used in the aarch64/Asm semantics! + * Thus we skip this particular case: + * Inductive st_instruction : Type := + * | PSt_rs_a (st : store_rs_a) (rs : ireg) (a : addressing) + * | Pstp (rs1 rs2: ireg) (a: addressing) (**r store two int64 *) + * . + * Coercion PStore : st_instruction >-> basic. + *) + +Inductive arith_p : Type := + (** PC-relative addressing *) + | Padrp (id: ident) (ofs: ptrofs) (**r set [rd] to high address of [id + ofs] *) + (** Move wide immediate *) + | Pmovz (sz: isize) (n: Z) (pos: Z) (**r move [n << pos] to [rd] *) + | Pmovn (sz: isize) (n: Z) (pos: Z) (**r move [NOT(n << pos)] to [rd] *) + (** Floating-point move *) + | Pfmovimms (f: float32) (**r load float32 constant *) + | Pfmovimmd (f: float) (**r load float64 constant *) +. + +Inductive arith_comparison_p : Type := + (** Floating-point comparison *) + | Pfcmp0 (sz: fsize) (**r compare [r1] and [+0.0] *) + (** Integer arithmetic, immediate *) + | Pcmpimm (sz: isize) (n: Z) (**r compare *) + | Pcmnimm (sz: isize) (n: Z) (**r compare negative *) + (** Logical, immediate *) + | Ptstimm (sz: isize) (n: Z) (**r and, then set flags *) +. + +Inductive arith_pp : Type := + (** Move integer register *) + | Pmov + (** Move wide immediate *) + (* XXX: has to have the same register supplied both times *) + | Pmovk (sz: isize) (n: Z) (pos: Z) (**r insert 16 bits of [n] at [pos] in rd *) + (** PC-relative addressing *) + | Paddadr (id: ident) (ofs: ptrofs) (**r add the low address of [id + ofs] *) + (** Bit-field operations *) + | Psbfiz (sz: isize) (r: int) (s: Z) (**r sign extend and shift left *) + | Psbfx (sz: isize) (r: int) (s: Z) (**r shift right and sign extend *) + | Pubfiz (sz: isize) (r: int) (s: Z) (**r zero extend and shift left *) + | Pubfx (sz: isize) (r: int) (s: Z) (**r shift right and zero extend *) +(* Bit operations are not used in the aarch64/asm semantics + (** Bit operations *) + | Pcls (sz: isize) (**r count leading sign bits *) + | Pclz (sz: isize) (**r count leading zero bits *) + | Prev (sz: isize) (**r reverse bytes *) + | Prev16 (sz: isize) (**r reverse bytes in each 16-bit word *) +*) + (** Floating-point move *) + | Pfmov + (** Floating-point conversions *) + | Pfcvtds (**r convert float32 to float64 *) + | Pfcvtsd (**r convert float64 to float32 *) + (** Floating-point arithmetic *) + | Pfabs (sz: fsize) (**r absolute value *) + | Pfneg (sz: fsize) (**r negation *) + (* Pfsqrt is not used in the semantics of aarch64/asm + | Pfsqrt (sz: fsize) (**r square root *) *) + (** Floating-point conversions *) + | Pscvtf (fsz: fsize) (isz: isize) (**r convert signed int to float *) + | Pucvtf (fsz: fsize) (isz: isize) (**r convert unsigned int to float *) + | Pfcvtzs (isz: isize) (fsz: fsize) (**r convert float to signed int *) + | Pfcvtzu (isz: isize) (fsz: fsize) (**r convert float to unsigned int *) + (** Integer arithmetic, immediate *) + | Paddimm (sz: isize) (n: Z) (**r addition *) + | Psubimm (sz: isize) (n: Z) (**r subtraction *) +. + +Inductive arith_comparison_r0r : Type := + (** Integer arithmetic, shifted register *) + | Pcmp (is:isize) (s: shift_op) (**r compare *) + | Pcmn (is:isize) (s: shift_op) (**r compare negative *) + (** Logical, shifted register *) + | Ptst (is:isize) (s: shift_op) (**r and, then set flags *) +. + +Inductive arith_comparison_pp : Type := + (** Integer arithmetic, extending register *) + | Pcmpext (x: extend_op) (**r int64-int32 cmp *) + | Pcmnext (x: extend_op) (**r int64-int32 cmn *) + (** Floating-point comparison *) + | Pfcmp (sz: fsize) (**r compare [r1] and [r2] *) +. + +Inductive arith_ppp : Type := + (** Variable shifts *) + | Pasrv (sz: isize) (**r arithmetic right shift *) + | Plslv (sz: isize) (**r left shift *) + | Plsrv (sz: isize) (**r logical right shift *) + | Prorv (sz: isize) (**r rotate right *) + (** Integer multiply/divide *) + | Psmulh (**r signed multiply high *) + | Pumulh (**r unsigned multiply high *) + | Psdiv (sz: isize) (**r signed division *) + | Pudiv (sz: isize) (**r unsigned division *) + (** Integer arithmetic, extending register *) + | Paddext (x: extend_op) (**r int64-int32 add *) + | Psubext (x: extend_op) (**r int64-int32 sub *) + (** Floating-point arithmetic *) + | Pfadd (sz: fsize) (**r addition *) + | Pfdiv (sz: fsize) (**r division *) + | Pfmul (sz: fsize) (**r multiplication *) + | Pfsub (sz: fsize) (**r subtraction *) +. + +Inductive arith_rr0r : Type := + (** Integer arithmetic, shifted register *) + | Padd (sz:isize) (s: shift_op) (**r addition *) + | Psub (sz:isize) (s: shift_op) (**r subtraction *) + (** Logical, shifted register *) + | Pand (sz:isize) (s: shift_op) (**r and *) + | Pbic (sz:isize) (s: shift_op) (**r and-not *) + | Peon (sz:isize) (s: shift_op) (**r xor-not *) + | Peor (sz:isize) (s: shift_op) (**r xor *) + | Porr (sz:isize) (s: shift_op) (**r or *) + | Porn (sz:isize) (s: shift_op) (**r or-not *) +. + + +Inductive arith_rr0 : Type := + (** Logical, immediate *) + | Pandimm (sz: isize) (n: Z) (**r and *) + | Peorimm (sz: isize) (n: Z) (**r xor *) + | Porrimm (sz: isize) (n: Z) (**r or *) +. + +Inductive arith_arrrr0 : Type := + (** Integer multiply/divide *) + | Pmadd (sz: isize) (**r multiply-add *) + | Pmsub (sz: isize) (**r multiply-sub *) +. + +(* Currently not used by the semantics of aarch64/Asm + * Inductive arith_apppp : Type := + * (** Floating-point arithmetic *) + * | Pfmadd (sz: fsize) (**r [rd = r3 + r1 * r2] *) + * | Pfmsub (sz: fsize) (**r [rd = r3 - r1 * r2] *) + * . + + * Inductive arith_aapppp : Type := + * (** Floating-point arithmetic *) + * | Pfnmadd (sz: fsize) (**r [rd = - r3 - r1 * r2] *) + * | Pfnmsub (sz: fsize) (**r [rd = - r3 + r1 * r2] *) + * . *) + +(* Notes on the naming scheme used here: + * R: ireg + * R0: ireg0 + * Rsp: iregsp + * F: freg + * W/X: Occur in conjunction with R0, says whether an ireg0 should be evaluated + * as W regsiter (32 bit) or X register (64 bit) + * S/D: Used for completeness sake. Only used for copying an integer register + * to a floating point register. Could be removed. + * A: These instructions perform an additional arithmetic operation + XXX Does this interpretation match the use in kvx/Asmvliw? + * Comparison: For these instructions the first register is not the target. + * Instead, the condition register is mutated. + *) +Inductive ar_instruction : Type := + | PArithP (i : arith_p) (rd : dreg) + | PArithPP (i : arith_pp) (rd rs : dreg) + | PArithPPP (i : arith_ppp) (rd r1 r2 : dreg) + | PArithRR0R (i : arith_rr0r) (rd : ireg) (r1 : ireg0) (r2 : ireg) + | PArithRR0 (i : arith_rr0) (rd : ireg) (r1 : ireg0) + | PArithARRRR0 (i : arith_arrrr0) (rd r1 r2 : ireg) (r3 : ireg0) + (* Pfmadd and Pfmsub are currently not used by the semantics of aarch64/Asm + | PArithAPPPP (i : arith_apppp) (rd r1 r2 r3 : preg) *) + (* Pfnmadd and Pfnmsub are currently not used by the semantics of aarch64/Asm + | PArithAAPPPP (i : arith_aapppp) (rd r1 r2 r3 : preg) *) + | PArithComparisonPP (i : arith_comparison_pp) (r1 r2 : dreg) + | PArithComparisonR0R (i : arith_comparison_r0r) (r1 : ireg0) (r2 : ireg) + | PArithComparisonP (i : arith_comparison_p) (r1 : dreg) + (* Instructions without indirection sine they would be the only ones *) + (* PArithCP: Pcsetm is commented out by aarch64/Asm, so Pcset is alone *) + | Pcset (rd : ireg) (c : testcond) (**r set to 1/0 if cond is true/false *) + (* PArithFR0 *) + | Pfmovi (fsz : fsize) (rd : freg) (r1 : ireg0) (**r copy int reg to FP reg *) + (* PArithCPPP *) + | Pcsel (rd r1 r2 : dreg) (c : testcond) (**r int/float conditional move *) + (* PArithAFFF *) + | Pfnmul (fsz : fsize) (rd r1 r2 : freg) (**r multiply-negate *) +. + +Inductive basic : Type := + | PArith (i: ar_instruction) (**r TODO *) + | PLoad (ld: load_rd_a) (rd: dreg) (a: addressing) (**r TODO *) + | PStore (st: store_rs_a) (r: dreg) (a: addressing) (**r TODO *) + | Pallocframe (sz: Z) (linkofs: ptrofs) (**r allocate new stack frame *) + | Pfreeframe (sz: Z) (linkofs: ptrofs) (**r deallocate stack frame and restore previous frame *) + | Ploadsymbol (rd: ireg) (id: ident) (**r load the address of [id] *) + | Pcvtsw2x (rd: ireg) (r1: ireg) (**r sign-extend 32-bit int to 64-bit *) + | Pcvtuw2x (rd: ireg) (r1: ireg) (**r zero-extend 32-bit int to 64-bit *) + | Pcvtx2w (rd: ireg) (**r retype a 64-bit int as a 32-bit int *) +(* NOT USED IN THE SEMANTICS ! + | Pnop (**r no operation *) + | Pcfi_adjust (ofs: int) (**r .cfi_adjust debug directive *) + | Pcfi_rel_offset (ofs: int) (**r .cfi_rel_offset debug directive *) +*) +. + +Inductive instruction : Type := + | PBasic (i: basic) + | PControl (i: control). + +Coercion PBasic: basic >-> instruction. +Coercion PControl: control >-> instruction. + +(** * Definition of a bblock + +A bblock must contain at least one instruction. + +This choice simplifies the definition of [find_bblock] below: +indeed, each address of a code block identifies at most one bblock. +*) + +Definition non_empty_body (body: list basic): bool := + match body with + | nil => false + | _ => true + end. + +Definition non_empty_exit (exit: option control): bool := + match exit with + | None => false + | _ => true + end. + +Definition non_empty_bblockb (body: list basic) (exit: option control): bool := non_empty_body body || non_empty_exit exit. + +(** A bblock is well-formed if he contains at least one instruction. *) + +Record bblock := mk_bblock { + header: list label; + body: list basic; + exit: option control; + correct: Is_true (non_empty_bblockb body exit) +}. + +(* FIXME? redundant with definition in Machblock *) +Definition length_opt {A} (o: option A) : nat := + match o with + | Some o => 1 + | None => 0 + end. + +Program Definition no_header (bb : bblock) := {| header := nil; body := body bb; exit := exit bb |}. +Next Obligation. + destruct bb; cbn. assumption. +Defined. + +Program Definition stick_header (h : list label) (bb : bblock) := {| header := h; body := body bb; exit := exit bb |}. +Next Obligation. + destruct bb; cbn. assumption. +Defined. + +(* This notion of size induces the notion of "valid" code address given by [find_bblock] + + The result is in Z to be compatible with operations on PC. +*) +Definition size (b:bblock): Z := Z.of_nat (length (header b) + length (body b) + length_opt (exit b)). + +Definition bblocks := list bblock. + +Fixpoint size_blocks (l: bblocks): Z := + match l with + | nil => 0 + | b :: l => + (size b) + (size_blocks l) + end + . + +Record function : Type := mkfunction { fn_sig: signature; fn_blocks: bblocks }. +Definition fundef := AST.fundef function. +Definition program := AST.program fundef unit. + +(* TODO: ORIGINAL ABSTRACT SYNTAX OF INSTRUCTIONS THAT NEEDS TO BE ADAPTED ! + +Inductive instruction: Type := + (** Branches *) + | Pb (lbl: label) (**r branch *) + | Pbc (c: testcond) (lbl: label) (**r conditional branch *) + | Pbl (id: ident) (sg: signature) (**r jump to function and link *) + | Pbs (id: ident) (sg: signature) (**r jump to function *) + | Pblr (r: ireg) (sg: signature) (**r indirect jump and link *) + | Pbr (r: ireg) (sg: signature) (**r indirect jump *) + | Pret (r: ireg) (**r return *) + | Pcbnz (sz: isize) (r: ireg) (lbl: label) (**r branch if not zero *) + | Pcbz (sz: isize) (r: ireg) (lbl: label) (**r branch if zero *) + | Ptbnz (sz: isize) (r: ireg) (n: int) (lbl: label) (**r branch if bit n is not zero *) + | Ptbz (sz: isize) (r: ireg) (n: int) (lbl: label) (**r branch if bit n is zero *) + (** Memory loads and stores *) + | Pldrw (rd: ireg) (a: addressing) (**r load int32 *) + | Pldrw_a (rd: ireg) (a: addressing) (**r load int32 as any32 *) + | Pldrx (rd: ireg) (a: addressing) (**r load int64 *) + | Pldrx_a (rd: ireg) (a: addressing) (**r load int64 as any64 *) + | Pldrb (sz: isize) (rd: ireg) (a: addressing) (**r load int8, zero-extend *) + | Pldrsb (sz: isize) (rd: ireg) (a: addressing) (**r load int8, sign-extend *) + | Pldrh (sz: isize) (rd: ireg) (a: addressing) (**r load int16, zero-extend *) + | Pldrsh (sz: isize) (rd: ireg) (a: addressing) (**r load int16, sign-extend *) + | Pldrzw (rd: ireg) (a: addressing) (**r load int32, zero-extend to int64 *) + | Pldrsw (rd: ireg) (a: addressing) (**r load int32, sign-extend to int64 *) + | Pldp (rd1 rd2: ireg) (a: addressing) (**r load two int64 *) + | Pstrw (rs: ireg) (a: addressing) (**r store int32 *) + | Pstrw_a (rs: ireg) (a: addressing) (**r store int32 as any32 *) + | Pstrx (rs: ireg) (a: addressing) (**r store int64 *) + | Pstrx_a (rs: ireg) (a: addressing) (**r store int64 as any64 *) + | Pstrb (rs: ireg) (a: addressing) (**r store int8 *) + | Pstrh (rs: ireg) (a: addressing) (**r store int16 *) + | Pstp (rs1 rs2: ireg) (a: addressing) (**r store two int64 *) + (** Integer arithmetic, immediate *) + | Paddimm (sz: isize) (rd: iregsp) (r1: iregsp) (n: Z) (**r addition *) + | Psubimm (sz: isize) (rd: iregsp) (r1: iregsp) (n: Z) (**r subtraction *) + | Pcmpimm (sz: isize) (r1: ireg) (n: Z) (**r compare *) + | Pcmnimm (sz: isize) (r1: ireg) (n: Z) (**r compare negative *) + (** Move integer register *) + | Pmov (rd: iregsp) (r1: iregsp) + (** Logical, immediate *) + | Pandimm (sz: isize) (rd: ireg) (r1: ireg0) (n: Z) (**r and *) + | Peorimm (sz: isize) (rd: ireg) (r1: ireg0) (n: Z) (**r xor *) + | Porrimm (sz: isize) (rd: ireg) (r1: ireg0) (n: Z) (**r or *) + | Ptstimm (sz: isize) (r1: ireg) (n: Z) (**r and, then set flags *) + (** Move wide immediate *) + | Pmovz (sz: isize) (rd: ireg) (n: Z) (pos: Z) (**r move [n << pos] to [rd] *) + | Pmovn (sz: isize) (rd: ireg) (n: Z) (pos: Z) (**r move [NOT(n << pos)] to [rd] *) + | Pmovk (sz: isize) (rd: ireg) (n: Z) (pos: Z) (**r insert 16 bits of [n] at [pos] in rd *) + (** PC-relative addressing *) + | Padrp (rd: ireg) (id: ident) (ofs: ptrofs) (**r set [rd] to high address of [id + ofs] *) + | Paddadr (rd: ireg) (r1: ireg) (id: ident) (ofs: ptrofs) (**r add the low address of [id + ofs] *) + (** Bit-field operations *) + | Psbfiz (sz: isize) (rd: ireg) (r1: ireg) (r: int) (s: Z) (**r sign extend and shift left *) + | Psbfx (sz: isize) (rd: ireg) (r1: ireg) (r: int) (s: Z) (**r shift right and sign extend *) + | Pubfiz (sz: isize) (rd: ireg) (r1: ireg) (r: int) (s: Z) (**r zero extend and shift left *) + | Pubfx (sz: isize) (rd: ireg) (r1: ireg) (r: int) (s: Z) (**r shift right and zero extend *) + (** Integer arithmetic, shifted register *) + | Padd (sz: isize) (rd: ireg) (r1: ireg0) (r2: ireg) (s: shift_op) (**r addition *) + | Psub (sz: isize) (rd: ireg) (r1: ireg0) (r2: ireg) (s: shift_op) (**r subtraction *) + | Pcmp (sz: isize) (r1: ireg0) (r2: ireg) (s: shift_op) (**r compare *) + | Pcmn (sz: isize) (r1: ireg0) (r2: ireg) (s: shift_op) (**r compare negative *) + (** Integer arithmetic, extending register *) + | Paddext (rd: iregsp) (r1: iregsp) (r2: ireg) (x: extend_op) (**r int64-int32 add *) + | Psubext (rd: iregsp) (r1: iregsp) (r2: ireg) (x: extend_op) (**r int64-int32 sub *) + | Pcmpext (r1: ireg) (r2: ireg) (x: extend_op) (**r int64-int32 cmp *) + | Pcmnext (r1: ireg) (r2: ireg) (x: extend_op) (**r int64-int32 cmn *) + (** Logical, shifted register *) + | Pand (sz: isize) (rd: ireg) (r1: ireg0) (r2: ireg) (s: shift_op) (**r and *) + | Pbic (sz: isize) (rd: ireg) (r1: ireg0) (r2: ireg) (s: shift_op) (**r and-not *) + | Peon (sz: isize) (rd: ireg) (r1: ireg0) (r2: ireg) (s: shift_op) (**r xor-not *) + | Peor (sz: isize) (rd: ireg) (r1: ireg0) (r2: ireg) (s: shift_op) (**r xor *) + | Porr (sz: isize) (rd: ireg) (r1: ireg0) (r2: ireg) (s: shift_op) (**r or *) + | Porn (sz: isize) (rd: ireg) (r1: ireg0) (r2: ireg) (s: shift_op) (**r or-not *) + | Ptst (sz: isize) (r1: ireg0) (r2: ireg) (s: shift_op) (**r and, then set flags *) + (** Variable shifts *) + | Pasrv (sz: isize) (rd: ireg) (r1 r2: ireg) (**r arithmetic right shift *) + | Plslv (sz: isize) (rd: ireg) (r1 r2: ireg) (**r left shift *) + | Plsrv (sz: isize) (rd: ireg) (r1 r2: ireg) (**r logical right shift *) + | Prorv (sz: isize) (rd: ireg) (r1 r2: ireg) (**r rotate right *) + (** Bit operations *) + | Pcls (sz: isize) (rd r1: ireg) (**r count leading sign bits *) + | Pclz (sz: isize) (rd r1: ireg) (**r count leading zero bits *) + | Prev (sz: isize) (rd r1: ireg) (**r reverse bytes *) + | Prev16 (sz: isize) (rd r1: ireg) (**r reverse bytes in each 16-bit word *) + (** Conditional data processing *) + | Pcsel (rd: ireg) (r1 r2: ireg) (c: testcond) (**r int conditional move *) + | Pcset (rd: ireg) (c: testcond) (**r set to 1/0 if cond is true/false *) +(* + | Pcsetm (rd: ireg) (c: testcond) (**r set to -1/0 if cond is true/false *) +*) + (** Integer multiply/divide *) + | Pmadd (sz: isize) (rd: ireg) (r1 r2: ireg) (r3: ireg0) (**r multiply-add *) + | Pmsub (sz: isize) (rd: ireg) (r1 r2: ireg) (r3: ireg0) (**r multiply-sub *) + | Psmulh (rd: ireg) (r1 r2: ireg) (**r signed multiply high *) + | Pumulh (rd: ireg) (r1 r2: ireg) (**r unsigned multiply high *) + | Psdiv (sz: isize) (rd: ireg) (r1 r2: ireg) (**r signed division *) + | Pudiv (sz: isize) (rd: ireg) (r1 r2: ireg) (**r unsigned division *) + (** Floating-point loads and stores *) + | Pldrs (rd: freg) (a: addressing) (**r load float32 (single precision) *) + | Pldrd (rd: freg) (a: addressing) (**r load float64 (double precision) *) + | Pldrd_a (rd: freg) (a: addressing) (**r load float64 as any64 *) + | Pstrs (rs: freg) (a: addressing) (**r store float32 *) + | Pstrd (rs: freg) (a: addressing) (**r store float64 *) + | Pstrd_a (rs: freg) (a: addressing) (**r store float64 as any64 *) + (** Floating-point move *) + | Pfmov (rd r1: freg) + | Pfmovimms (rd: freg) (f: float32) (**r load float32 constant *) + | Pfmovimmd (rd: freg) (f: float) (**r load float64 constant *) + | Pfmovi (fsz: fsize) (rd: freg) (r1: ireg0) (**r copy int reg to FP reg *) + (** Floating-point conversions *) + | Pfcvtds (rd r1: freg) (**r convert float32 to float64 *) + | Pfcvtsd (rd r1: freg) (**r convert float64 to float32 *) + | Pfcvtzs (isz: isize) (fsz: fsize) (rd: ireg) (r1: freg) (**r convert float to signed int *) + | Pfcvtzu (isz: isize) (fsz: fsize) (rd: ireg) (r1: freg) (**r convert float to unsigned int *) + | Pscvtf (fsz: fsize) (isz: isize) (rd: freg) (r1: ireg) (**r convert signed int to float *) + | Pucvtf (fsz: fsize) (isz: isize) (rd: freg) (r1: ireg) (**r convert unsigned int to float *) + (** Floating-point arithmetic *) + | Pfabs (sz: fsize) (rd r1: freg) (**r absolute value *) + | Pfneg (sz: fsize) (rd r1: freg) (**r negation *) + | Pfsqrt (sz: fsize) (rd r1: freg) (**r square root *) + | Pfadd (sz: fsize) (rd r1 r2: freg) (**r addition *) + | Pfdiv (sz: fsize) (rd r1 r2: freg) (**r division *) + | Pfmul (sz: fsize) (rd r1 r2: freg) (**r multiplication *) + | Pfnmul (sz: fsize) (rd r1 r2: freg) (**r multiply-negate *) + | Pfsub (sz: fsize) (rd r1 r2: freg) (**r subtraction *) + | Pfmadd (sz: fsize) (rd r1 r2 r3: freg) (**r [rd = r3 + r1 * r2] *) + | Pfmsub (sz: fsize) (rd r1 r2 r3: freg) (**r [rd = r3 - r1 * r2] *) + | Pfnmadd (sz: fsize) (rd r1 r2 r3: freg) (**r [rd = - r3 - r1 * r2] *) + | Pfnmsub (sz: fsize) (rd r1 r2 r3: freg) (**r [rd = - r3 + r1 * r2] *) + (** Floating-point comparison *) + | Pfcmp (sz: fsize) (r1 r2: freg) (**r compare [r1] and [r2] *) + | Pfcmp0 (sz: fsize) (r1: freg) (**r compare [r1] and [+0.0] *) + (** Floating-point conditional select *) + | Pfsel (rd r1 r2: freg) (cond: testcond) + (** Pseudo-instructions *) + | Pallocframe (sz: Z) (linkofs: ptrofs) (**r allocate new stack frame *) + | Pfreeframe (sz: Z) (linkofs: ptrofs) (**r deallocate stack frame and restore previous frame *) + | Plabel (lbl: label) (**r define a code label *) + | Ploadsymbol (rd: ireg) (id: ident) (**r load the address of [id] *) + | Pcvtsw2x (rd: ireg) (r1: ireg) (**r sign-extend 32-bit int to 64-bit *) + | Pcvtuw2x (rd: ireg) (r1: ireg) (**r zero-extend 32-bit int to 64-bit *) + | Pcvtx2w (rd: ireg) (**r retype a 64-bit int as a 32-bit int *) + | Pbtbl (r1: ireg) (tbl: list label) (**r N-way branch through a jump table *) + | Pbuiltin (ef: external_function) + (args: list (builtin_arg preg)) (res: builtin_res preg) (**r built-in function (pseudo) *) + | Pnop (**r no operation *) + | Pcfi_adjust (ofs: int) (**r .cfi_adjust debug directive *) + | Pcfi_rel_offset (ofs: int) (**r .cfi_rel_offset debug directive *) +. +*) + + +(** * Operational semantics *) + +(** See "Parameters" of the same names in Asm.v *) +Record aarch64_linker: Type := { + symbol_low: ident -> ptrofs -> val; + symbol_high: ident -> ptrofs -> val +}. + +Definition genv := Genv.t fundef unit. + +Section RELSEM. + +Variable lk: aarch64_linker. +Variable ge: genv. + +(** Evaluating an addressing mode *) + +Definition eval_addressing (a: addressing) (rs: regset): val := + match a with + | ADimm base n => Val.addl rs#base (Vlong n) + | ADreg base r => Val.addl rs#base rs#r + | ADlsl base r n => Val.addl rs#base (Val.shll rs#r (Vint n)) + | ADsxt base r n => Val.addl rs#base (Val.shll (Val.longofint rs#r) (Vint n)) + | ADuxt base r n => Val.addl rs#base (Val.shll (Val.longofintu rs#r) (Vint n)) + | ADadr base id ofs => Val.addl rs#base (symbol_low lk id ofs) + | ADpostincr base n => Vundef (* not modeled yet *) + end. + +(** Auxiliaries for memory accesses *) + +Definition exec_load (chunk: memory_chunk) (transf: val -> val) + (a: addressing) (r: dreg) (rs: regset) (m: mem) := + SOME v <- Mem.loadv chunk m (eval_addressing a rs) IN + Next (rs#r <- (transf v)) m. + +Definition exec_store (chunk: memory_chunk) + (a: addressing) (v: val) + (rs: regset) (m: mem) := + SOME m' <- Mem.storev chunk m (eval_addressing a rs) v IN + Next rs m'. + + +(** execution of loads +*) + +Definition chunk_load_rd_a (ld: load_rd_a): memory_chunk := + match ld with + | Pldrw => Mint32 + | Pldrw_a => Many32 + | Pldrx => Mint64 + | Pldrx_a => Many64 + | Pldrb _ => Mint8unsigned + | Pldrsb _ => Mint8signed + | Pldrh _ => Mint16unsigned + | Pldrsh _ => Mint16signed + | Pldrzw => Mint32 + | Pldrsw => Mint32 + | Pldrs => Mfloat32 + | Pldrd => Mfloat64 + | Pldrd_a => Many64 + end. + +Definition chunk_store_rs_a (st: store_rs_a) : memory_chunk := + match st with + | Pstrw => Mint32 + | Pstrw_a => Many32 + | Pstrx => Mint64 + | Pstrx_a => Many64 + | Pstrb => Mint8unsigned + | Pstrh => Mint16unsigned + | Pstrs => Mfloat32 + | Pstrd => Mfloat64 + | Pstrd_a => Many64 + end. + +Definition interp_load_rd_a (ld: load_rd_a): val -> val := + match ld with + | Pldrb X => Val.longofintu + | Pldrsb X => Val.longofint + | Pldrh X => Val.longofintu + | Pldrsh X => Val.longofint + | Pldrzw => Val.longofintu + | Pldrsw => Val.longofint + (* Changed to exhaustive list because I tend to forgot all the places I need + * to check when changing things. *) + | Pldrb W | Pldrsb W | Pldrh W | Pldrsh W + | Pldrw | Pldrw_a | Pldrx | Pldrx_a + | Pldrs | Pldrd | Pldrd_a => fun v => v + end. + +(** TODO: redundant w.r.t Machblock ?? *) +Lemma in_dec (lbl: label) (l: list label): { List.In lbl l } + { ~(List.In lbl l) }. +Proof. + apply List.in_dec. + apply Pos.eq_dec. +Qed. + +(** Note: copy-paste from Machblock *) +Definition is_label (lbl: label) (bb: bblock) : bool := + if in_dec lbl (header bb) then true else false. + +Lemma is_label_correct_true lbl bb: + List.In lbl (header bb) <-> is_label lbl bb = true. +Proof. + unfold is_label; destruct (in_dec lbl (header bb)); simpl; intuition. +Qed. + +Lemma is_label_correct_false lbl bb: + ~(List.In lbl (header bb)) <-> is_label lbl bb = false. +Proof. + unfold is_label; destruct (in_dec lbl (header bb)); simpl; intuition. +Qed. + +(** convert a label into a position in the code *) +Fixpoint label_pos (lbl: label) (pos: Z) (lb: bblocks) {struct lb} : option Z := + match lb with + | nil => None + | b :: lb' => if is_label lbl b then Some pos else label_pos lbl (pos + (size b)) lb' + end. + +Definition goto_label (f: function) (lbl: label) (rs: regset) (m: mem) := + SOME pos <- label_pos lbl 0 (fn_blocks f) IN + match rs#PC with + | Vptr b ofs => Next (rs#PC <- (Vptr b (Ptrofs.repr pos))) m + | _ => Stuck + end. + +(** Evaluating a branch + +Warning: PC is assumed to be already pointing on the next instruction ! + +*) + +Definition eval_branch (f: function) (lbl: label) (rs: regset) (m: mem) (ores: option bool) := + SOME res <- ores IN + if res then goto_label f lbl rs m else Next rs m. + +Definition eval_neg_branch (f: function) (lbl: label) (rs: regset) (m: mem) (ores: option bool) := + SOME res <- ores IN + if res then Next rs m else goto_label f lbl rs m. + +Definition exec_cfi (f: function) (cfi: cf_instruction) (rs: regset) (m: mem) : outcome := + match cfi with + (** Branches *) + | Pb lbl => + goto_label f lbl rs m + | Pbc cond lbl => + eval_branch f lbl rs m (eval_testcond cond rs) + | Pbl id sg => + Next (rs#RA <- (rs#PC) #PC <- (Genv.symbol_address ge id Ptrofs.zero)) m + | Pbs id sg => + Next (rs#PC <- (Genv.symbol_address ge id Ptrofs.zero)) m + | Pblr r sg => + Next (rs#RA <- (rs#PC) #PC <- (rs#r)) m + | Pbr r sg => + Next (rs#PC <- (rs#r)) m + | Pret r => + Next (rs#PC <- (rs#r)) m + | Pcbnz sz r lbl => + eval_neg_branch f lbl rs m (eval_testzero sz rs#r) + | Pcbz sz r lbl => + eval_branch f lbl rs m (eval_testzero sz rs#r) + | Ptbnz sz r n lbl => + eval_branch f lbl rs m (eval_testbit sz rs#r n) + | Ptbz sz r n lbl => + eval_neg_branch f lbl rs m (eval_testbit sz rs#r n) + (** Pseudo-instructions *) + | Pbtbl r tbl => + match (rs#X16 <- Vundef)#r with + | Vint n => + SOME lbl <- list_nth_z tbl (Int.unsigned n) IN + goto_label f lbl (rs#X16 <- Vundef #X17 <- Vundef) m + | _ => Stuck + end + end. + +Definition arith_eval_p (i : arith_p) : val := + match i with + | Padrp id ofs => symbol_high lk id ofs + (** Move wide immediate *) + | Pmovz W n pos => Vint (Int.repr (Z.shiftl n pos)) + | Pmovz X n pos => Vlong (Int64.repr (Z.shiftl n pos)) + | Pmovn W n pos => Vint (Int.repr (Z.lnot (Z.shiftl n pos))) + | Pmovn X n pos => Vlong (Int64.repr (Z.lnot (Z.shiftl n pos))) + (** Floating-point move *) + | Pfmovimms f => Vsingle f + | Pfmovimmd f => Vfloat f + end. + +Definition if_opt_bool_val (c: option bool) v1 v2: val := + match c with + | Some true => v1 + | Some false => v2 + | None => Vundef + end. + +Definition arith_eval_pp i v := + match i with + | Pmov => v + | Pmovk W n pos => insert_in_int v n pos 16 + | Pmovk X n pos => insert_in_long v n pos 16 + | Paddadr id ofs => Val.addl v (symbol_low lk id ofs) + | Psbfiz W r s => Val.shl (Val.sign_ext s v) (Vint r) + | Psbfiz X r s => Val.shll (Val.sign_ext_l s v) (Vint r) + | Psbfx W r s => Val.sign_ext s (Val.shr v (Vint r)) + | Psbfx X r s => Val.sign_ext_l s (Val.shrl v (Vint r)) + | Pubfiz W r s => Val.shl (Val.zero_ext s v) (Vint r) + | Pubfiz X r s => Val.shll (Val.zero_ext_l s v) (Vint r) + | Pubfx W r s => Val.zero_ext s (Val.shru v (Vint r)) + | Pubfx X r s => Val.zero_ext_l s (Val.shrlu v (Vint r)) + | Pfmov => v + | Pfcvtds => Val.floatofsingle v + | Pfcvtsd => Val.singleoffloat v + | Pfabs S => Val.absfs v + | Pfabs D => Val.absf v + | Pfneg S => Val.negfs v + | Pfneg D => Val.negf v + | Pfcvtzs W S => Val.maketotal (Val.intofsingle v) + | Pfcvtzs W D => Val.maketotal (Val.intoffloat v) + | Pfcvtzs X S => Val.maketotal (Val.longofsingle v) + | Pfcvtzs X D => Val.maketotal (Val.longoffloat v) + | Pfcvtzu W S => Val.maketotal (Val.intuofsingle v) + | Pfcvtzu W D => Val.maketotal (Val.intuoffloat v) + | Pfcvtzu X S => Val.maketotal (Val.longuofsingle v) + | Pfcvtzu X D => Val.maketotal (Val.longuoffloat v) + | Paddimm W n => Val.add v (Vint (Int.repr n)) + | Paddimm X n => Val.addl v (Vlong (Int64.repr n)) + | Psubimm W n => Val.sub v (Vint (Int.repr n)) + | Psubimm X n => Val.subl v (Vlong (Int64.repr n)) + | Pscvtf S W => Val.maketotal (Val.singleofint v) + | Pscvtf D W => Val.maketotal (Val.floatofint v) + | Pscvtf S X => Val.maketotal (Val.singleoflong v) + | Pscvtf D X => Val.maketotal (Val.floatoflong v) + | Pucvtf S W => Val.maketotal (Val.singleofintu v) + | Pucvtf D W => Val.maketotal (Val.floatofintu v) + | Pucvtf S X => Val.maketotal (Val.singleoflongu v) + | Pucvtf D X => Val.maketotal (Val.floatoflongu v) + end. + +Definition arith_eval_ppp i v1 v2 := + match i with + | Pasrv W => Val.shr v1 v2 + | Pasrv X => Val.shrl v1 v2 + | Plslv W => Val.shl v1 v2 + | Plslv X => Val.shll v1 v2 + | Plsrv W => Val.shru v1 v2 + | Plsrv X => Val.shrlu v1 v2 + | Prorv W => Val.ror v1 v2 + | Prorv X => Val.rorl v1 v2 + | Psmulh => Val.mullhs v1 v2 + | Pumulh => Val.mullhu v1 v2 + | Psdiv W => Val.maketotal (Val.divs v1 v2) + | Psdiv X => Val.maketotal (Val.divls v1 v2) + | Pudiv W => Val.maketotal (Val.divu v1 v2) + | Pudiv X => Val.maketotal (Val.divlu v1 v2) + | Paddext x => Val.addl v1 (eval_extend v2 x) + | Psubext x => Val.subl v1 (eval_extend v2 x) + | Pfadd S => Val.addfs v1 v2 + | Pfadd D => Val.addf v1 v2 + | Pfdiv S => Val.divfs v1 v2 + | Pfdiv D => Val.divf v1 v2 + | Pfmul S => Val.mulfs v1 v2 + | Pfmul D => Val.mulf v1 v2 + | Pfsub S => Val.subfs v1 v2 + | Pfsub D => Val.subf v1 v2 + end. + +Definition arith_rr0r_isize (i: arith_rr0r) := + match i with + | Padd is _ => is + | Psub is _ => is + | Pand is _ => is + | Pbic is _ => is + | Peon is _ => is + | Peor is _ => is + | Porr is _ => is + | Porn is _ => is + end. + +(* obtain v1 by [ir0 (arith_rr0r_isize i) rs s1] *) +Definition arith_eval_rr0r i v1 v2 := + match i with + | Padd W s => Val.add v1 (eval_shift_op_int v2 s) + | Padd X s => Val.addl v1 (eval_shift_op_long v2 s) + | Psub W s => Val.sub v1 (eval_shift_op_int v2 s) + | Psub X s => Val.subl v1 (eval_shift_op_long v2 s) + | Pand W s => Val.and v1 (eval_shift_op_int v2 s) + | Pand X s => Val.andl v1 (eval_shift_op_long v2 s) + | Pbic W s => Val.and v1 (Val.notint (eval_shift_op_int v2 s)) + | Pbic X s => Val.andl v1 (Val.notl (eval_shift_op_long v2 s)) + | Peon W s => Val.xor v1 (Val.notint (eval_shift_op_int v2 s)) + | Peon X s => Val.xorl v1 (Val.notl (eval_shift_op_long v2 s)) + | Peor W s => Val.xor v1 (eval_shift_op_int v2 s) + | Peor X s => Val.xorl v1 (eval_shift_op_long v2 s) + | Porr W s => Val.or v1 (eval_shift_op_int v2 s) + | Porr X s => Val.orl v1 (eval_shift_op_long v2 s) + | Porn W s => Val.or v1 (Val.notint (eval_shift_op_int v2 s)) + | Porn X s => Val.orl v1 (Val.notl (eval_shift_op_long v2 s)) + end. + +Definition arith_rr0_isize (i : arith_rr0) := + match i with + | Pandimm is _ | Peorimm is _ | Porrimm is _ => is + end. + +(* obtain v by [ir0 (arith_rr0_isize i) rs s] *) +Definition arith_eval_rr0 i v := + match i with + | Pandimm W n => Val.and v (Vint (Int.repr n)) + | Pandimm X n => Val.andl v (Vlong (Int64.repr n)) + | Peorimm W n => Val.xor v (Vint (Int.repr n)) + | Peorimm X n => Val.xorl v (Vlong (Int64.repr n)) + | Porrimm W n => Val.or v (Vint (Int.repr n)) + | Porrimm X n => Val.orl v (Vlong (Int64.repr n)) + end. + +Definition arith_arrrr0_isize (i : arith_arrrr0) := + match i with + | Pmadd is | Pmsub is => is + end. + +(* obtain v3 by [ir0 (arith_arrrr0_isize i) rs s3] *) +Definition arith_eval_arrrr0 i v1 v2 v3 := + match i with + | Pmadd W => Val.add v3 (Val.mul v1 v2) + | Pmadd X => Val.addl v3 (Val.mull v1 v2) + | Pmsub W => Val.sub v3 (Val.mul v1 v2) + | Pmsub X => Val.subl v3 (Val.mull v1 v2) + end. + +Definition arith_prepare_comparison_pp i (v1 v2 : val) := + match i with + | Pcmpext x => (v1, (eval_extend v2 x)) + | Pcmnext x => (v1, (Val.negl (eval_extend v2 x))) + | Pfcmp _ => (v1, v2) + end. + +Definition arith_comparison_r0r_isize i := + match i with + | Pcmp is _ => is + | Pcmn is _ => is + | Ptst is _ => is + end. + +Definition arith_prepare_comparison_r0r i v1 v2 := + match i with + | Pcmp W s => (v1, (eval_shift_op_int v2 s)) + | Pcmp X s => (v1, (eval_shift_op_long v2 s)) + | Pcmn W s => (v1, (Val.neg (eval_shift_op_int v2 s))) + | Pcmn X s => (v1, (Val.negl (eval_shift_op_long v2 s))) + | Ptst W s => ((Val.and v1 (eval_shift_op_int v2 s)), (Vint Int.zero)) + | Ptst X s => ((Val.andl v1 (eval_shift_op_long v2 s)), (Vlong Int64.zero)) + end. + +Definition arith_prepare_comparison_p i v := + match i with + | Pcmpimm W n => (v, (Vint (Int.repr n))) + | Pcmpimm X n => (v, (Vlong (Int64.repr n))) + | Pcmnimm W n => (v, (Vint (Int.neg (Int.repr n)))) + | Pcmnimm X n => (v, (Vlong (Int64.neg (Int64.repr n)))) + | Ptstimm W n => ((Val.and v (Vint (Int.repr n))), (Vint Int.zero)) + | Ptstimm X n => ((Val.andl v (Vlong (Int64.repr n))), (Vlong Int64.zero)) + | Pfcmp0 S => (v, (Vsingle Float32.zero)) + | Pfcmp0 D => (v, (Vfloat Float.zero)) + end. + +Definition arith_comparison_pp_compare i := + match i with + | Pcmpext _ | Pcmnext _ => compare_long + | Pfcmp S => compare_single + | Pfcmp D => compare_float + end. + +Definition arith_comparison_p_compare i := + match i with + | Pcmpimm W _ | Pcmnimm W _ | Ptstimm W _ => compare_int + | Pcmpimm X _ | Pcmnimm X _ | Ptstimm X _ => compare_long + | Pfcmp0 S => compare_single + | Pfcmp0 D => compare_float + end. + +Definition exec_arith_instr (ai: ar_instruction) (rs: regset): regset := + match ai with + | PArithP i d => rs#d <- (arith_eval_p i) + | PArithPP i d s => rs#d <- (arith_eval_pp i rs#s) + | PArithPPP i d s1 s2 => rs#d <- (arith_eval_ppp i rs#s1 rs#s2) + + | PArithRR0R i d s1 s2 => rs#d <- (arith_eval_rr0r i (ir0 (arith_rr0r_isize i) rs s1) rs#s2) + + | PArithRR0 i d s => rs#d <- (arith_eval_rr0 i (ir0 (arith_rr0_isize i) rs s)) + + | PArithARRRR0 i d s1 s2 s3 => + rs#d <- (arith_eval_arrrr0 i rs#s1 rs#s2 (ir0 (arith_arrrr0_isize i) rs s3)) + + | PArithComparisonPP i s1 s2 => + let (v1, v2) := arith_prepare_comparison_pp i rs#s1 rs#s2 in + arith_comparison_pp_compare i rs v1 v2 + | PArithComparisonR0R i s1 s2 => + let is := arith_comparison_r0r_isize i in + let (v1, v2) := arith_prepare_comparison_r0r i (ir0 is rs s1) rs#s2 in + (if is (* is W *) then compare_int else compare_long) rs v1 v2 + | PArithComparisonP i s => + let (v1, v2) := arith_prepare_comparison_p i rs#s in + arith_comparison_p_compare i rs v1 v2 + | Pcset d c => rs#d <- (if_opt_bool_val (eval_testcond c rs) (Vint Int.one) (Vint Int.zero)) + | Pfmovi S d s => rs#d <- (float32_of_bits rs##s) + | Pfmovi D d s => rs#d <- (float64_of_bits rs###s) + | Pcsel d s1 s2 c => rs#d <- (if_opt_bool_val (eval_testcond c rs) (rs#s1) (rs#s2)) + | Pfnmul S d s1 s2 => rs#d <- (Val.negfs (Val.mulfs rs#s1 rs#s2)) + | Pfnmul D d s1 s2 => rs#d <- (Val.negf (Val.mulf rs#s1 rs#s2)) + end. + +(* basic exec *) +Definition exec_basic (b: basic) (rs: regset) (m: mem): outcome := + match b with + | PArith ai => Next (exec_arith_instr ai rs) m + | PLoad ld rd a => exec_load (chunk_load_rd_a ld) (interp_load_rd_a ld) a rd rs m + | PStore st r a => exec_store (chunk_store_rs_a st) a rs#r rs m + | Pallocframe sz pos => + let (m1, stk) := Mem.alloc m 0 sz in + let sp := (Vptr stk Ptrofs.zero) in + SOME m2 <- Mem.storev Mint64 m1 (Val.offset_ptr sp pos) rs#SP IN + Next (rs #X29 <- (rs#SP) #SP <- sp #X16 <- Vundef) m2 + | Pfreeframe sz pos => + SOME v <- Mem.loadv Mint64 m (Val.offset_ptr rs#SP pos) IN + match rs#SP with + | Vptr stk ofs => + SOME m' <- Mem.free m stk 0 sz IN + Next (rs#SP <- v #X16 <- Vundef) m' + | _ => Stuck + end + | Ploadsymbol rd id => + Next (rs#rd <- (Genv.symbol_address ge id Ptrofs.zero)) m + | Pcvtsw2x rd r1 => + Next (rs#rd <- (Val.longofint rs#r1)) m + | Pcvtuw2x rd r1 => + Next (rs#rd <- (Val.longofintu rs#r1)) m + | Pcvtx2w rd => + Next (rs#rd <- (Val.loword rs#rd)) m + end. + +(* TODO: ORIGINAL EXECUTION OF INSTRUCTIONS THAT NEEDS TO BE ADAPTED ! + +(** Execution of a single instruction [i] in initial state + [rs] and [m]. Return updated state. For instructions + that correspond to actual AArch64 instructions, the cases are + straightforward transliterations of the informal descriptions + given in the ARMv8 reference manuals. For pseudo-instructions, + refer to the informal descriptions given above. + + Note that we set to [Vundef] the registers used as temporaries by + the expansions of the pseudo-instructions, so that the code we + generate cannot use those registers to hold values that must + survive the execution of the pseudo-instruction. +*) + +Definition exec_instr (f: function) (i: instruction) (rs: regset) (m: mem) : outcome := + match i with + (** Branches *) + | Pb lbl => + goto_label f lbl rs m + | Pbc cond lbl => + match eval_testcond cond rs with + | Some true => goto_label f lbl rs m + | Some false => Next (nextinstr rs) m + | None => Stuck + end + | Pbl id sg => + Next (rs#RA <- (Val.offset_ptr rs#PC Ptrofs.one) #PC <- (Genv.symbol_address ge id Ptrofs.zero)) m + | Pbs id sg => + Next (rs#PC <- (Genv.symbol_address ge id Ptrofs.zero)) m + | Pblr r sg => + Next (rs#RA <- (Val.offset_ptr rs#PC Ptrofs.one) #PC <- (rs#r)) m + | Pbr r sg => + Next (rs#PC <- (rs#r)) m + | Pret r => + Next (rs#PC <- (rs#r)) m + | Pcbnz sz r lbl => + match eval_testzero sz rs#r m with + | Some true => Next (nextinstr rs) m + | Some false => goto_label f lbl rs m + | None => Stuck + end + | Pcbz sz r lbl => + match eval_testzero sz rs#r m with + | Some true => goto_label f lbl rs m + | Some false => Next (nextinstr rs) m + | None => Stuck + end + | Ptbnz sz r n lbl => + match eval_testbit sz rs#r n with + | Some true => goto_label f lbl rs m + | Some false => Next (nextinstr rs) m + | None => Stuck + end + | Ptbz sz r n lbl => + match eval_testbit sz rs#r n with + | Some true => Next (nextinstr rs) m + | Some false => goto_label f lbl rs m + | None => Stuck + end + (** Memory loads and stores *) + | Pldrw rd a => + exec_load Mint32 (fun v => v) a rd rs m + | Pldrw_a rd a => + exec_load Many32 (fun v => v) a rd rs m + | Pldrx rd a => + exec_load Mint64 (fun v => v) a rd rs m + | Pldrx_a rd a => + exec_load Many64 (fun v => v) a rd rs m + | Pldrb W rd a => + exec_load Mint8unsigned (fun v => v) a rd rs m + | Pldrb X rd a => + exec_load Mint8unsigned Val.longofintu a rd rs m + | Pldrsb W rd a => + exec_load Mint8signed (fun v => v) a rd rs m + | Pldrsb X rd a => + exec_load Mint8signed Val.longofint a rd rs m + | Pldrh W rd a => + exec_load Mint16unsigned (fun v => v) a rd rs m + | Pldrh X rd a => + exec_load Mint16unsigned Val.longofintu a rd rs m + | Pldrsh W rd a => + exec_load Mint16signed (fun v => v) a rd rs m + | Pldrsh X rd a => + exec_load Mint16signed Val.longofint a rd rs m + | Pldrzw rd a => + exec_load Mint32 Val.longofintu a rd rs m + | Pldrsw rd a => + exec_load Mint32 Val.longofint a rd rs m + | Pstrw r a => + exec_store Mint32 a rs#r rs m + | Pstrw_a r a => + exec_store Many32 a rs#r rs m + | Pstrx r a => + exec_store Mint64 a rs#r rs m + | Pstrx_a r a => + exec_store Many64 a rs#r rs m + | Pstrb r a => + exec_store Mint8unsigned a rs#r rs m + | Pstrh r a => + exec_store Mint16unsigned a rs#r rs m + (** Integer arithmetic, immediate *) + | Paddimm W rd r1 n => + Next (nextinstr (rs#rd <- (Val.add rs#r1 (Vint (Int.repr n))))) m + | Paddimm X rd r1 n => + Next (nextinstr (rs#rd <- (Val.addl rs#r1 (Vlong (Int64.repr n))))) m + | Psubimm W rd r1 n => + Next (nextinstr (rs#rd <- (Val.sub rs#r1 (Vint (Int.repr n))))) m + | Psubimm X rd r1 n => + Next (nextinstr (rs#rd <- (Val.subl rs#r1 (Vlong (Int64.repr n))))) m + | Pcmpimm W r1 n => + Next (nextinstr (compare_int rs rs#r1 (Vint (Int.repr n)) m)) m + | Pcmpimm X r1 n => + Next (nextinstr (compare_long rs rs#r1 (Vlong (Int64.repr n)) m)) m + | Pcmnimm W r1 n => + Next (nextinstr (compare_int rs rs#r1 (Vint (Int.neg (Int.repr n))) m)) m + | Pcmnimm X r1 n => + Next (nextinstr (compare_long rs rs#r1 (Vlong (Int64.neg (Int64.repr n))) m)) m + (** Move integer register *) + | Pmov rd r1 => + Next (nextinstr (rs#rd <- (rs#r1))) m + (** Logical, immediate *) + | Pandimm W rd r1 n => + Next (nextinstr (rs#rd <- (Val.and rs##r1 (Vint (Int.repr n))))) m + | Pandimm X rd r1 n => + Next (nextinstr (rs#rd <- (Val.andl rs###r1 (Vlong (Int64.repr n))))) m + | Peorimm W rd r1 n => + Next (nextinstr (rs#rd <- (Val.xor rs##r1 (Vint (Int.repr n))))) m + | Peorimm X rd r1 n => + Next (nextinstr (rs#rd <- (Val.xorl rs###r1 (Vlong (Int64.repr n))))) m + | Porrimm W rd r1 n => + Next (nextinstr (rs#rd <- (Val.or rs##r1 (Vint (Int.repr n))))) m + | Porrimm X rd r1 n => + Next (nextinstr (rs#rd <- (Val.orl rs###r1 (Vlong (Int64.repr n))))) m + | Ptstimm W r1 n => + Next (nextinstr (compare_int rs (Val.and rs#r1 (Vint (Int.repr n))) (Vint Int.zero) m)) m + | Ptstimm X r1 n => + Next (nextinstr (compare_long rs (Val.andl rs#r1 (Vlong (Int64.repr n))) (Vlong Int64.zero) m)) m + (** Move wide immediate *) + | Pmovz W rd n pos => + Next (nextinstr (rs#rd <- (Vint (Int.repr (Z.shiftl n pos))))) m + | Pmovz X rd n pos => + Next (nextinstr (rs#rd <- (Vlong (Int64.repr (Z.shiftl n pos))))) m + | Pmovn W rd n pos => + Next (nextinstr (rs#rd <- (Vint (Int.repr (Z.lnot (Z.shiftl n pos)))))) m + | Pmovn X rd n pos => + Next (nextinstr (rs#rd <- (Vlong (Int64.repr (Z.lnot (Z.shiftl n pos)))))) m + | Pmovk W rd n pos => + Next (nextinstr (rs#rd <- (insert_in_int rs#rd n pos 16))) m + | Pmovk X rd n pos => + Next (nextinstr (rs#rd <- (insert_in_long rs#rd n pos 16))) m + (** PC-relative addressing *) + | Padrp rd id ofs => + Next (nextinstr (rs#rd <- (symbol_high ge id ofs))) m + | Paddadr rd r1 id ofs => + Next (nextinstr (rs#rd <- (Val.addl rs#r1 (symbol_low ge id ofs)))) m + (** Bit-field operations *) + | Psbfiz W rd r1 r s => + Next (nextinstr (rs#rd <- (Val.shl (Val.sign_ext s rs#r1) (Vint r)))) m + | Psbfiz X rd r1 r s => + Next (nextinstr (rs#rd <- (Val.shll (Val.sign_ext_l s rs#r1) (Vint r)))) m + | Psbfx W rd r1 r s => + Next (nextinstr (rs#rd <- (Val.sign_ext s (Val.shr rs#r1 (Vint r))))) m + | Psbfx X rd r1 r s => + Next (nextinstr (rs#rd <- (Val.sign_ext_l s (Val.shrl rs#r1 (Vint r))))) m + | Pubfiz W rd r1 r s => + Next (nextinstr (rs#rd <- (Val.shl (Val.zero_ext s rs#r1) (Vint r)))) m + | Pubfiz X rd r1 r s => + Next (nextinstr (rs#rd <- (Val.shll (Val.zero_ext_l s rs#r1) (Vint r)))) m + | Pubfx W rd r1 r s => + Next (nextinstr (rs#rd <- (Val.zero_ext s (Val.shru rs#r1 (Vint r))))) m + | Pubfx X rd r1 r s => + Next (nextinstr (rs#rd <- (Val.zero_ext_l s (Val.shrlu rs#r1 (Vint r))))) m + (** Integer arithmetic, shifted register *) + | Padd W rd r1 r2 s => + Next (nextinstr (rs#rd <- (Val.add rs##r1 (eval_shift_op_int rs#r2 s)))) m + | Padd X rd r1 r2 s => + Next (nextinstr (rs#rd <- (Val.addl rs###r1 (eval_shift_op_long rs#r2 s)))) m + | Psub W rd r1 r2 s => + Next (nextinstr (rs#rd <- (Val.sub rs##r1 (eval_shift_op_int rs#r2 s)))) m + | Psub X rd r1 r2 s => + Next (nextinstr (rs#rd <- (Val.subl rs###r1 (eval_shift_op_long rs#r2 s)))) m + | Pcmp W r1 r2 s => + Next (nextinstr (compare_int rs rs##r1 (eval_shift_op_int rs#r2 s) m)) m + | Pcmp X r1 r2 s => + Next (nextinstr (compare_long rs rs###r1 (eval_shift_op_long rs#r2 s) m)) m + | Pcmn W r1 r2 s => + Next (nextinstr (compare_int rs rs##r1 (Val.neg (eval_shift_op_int rs#r2 s)) m)) m + | Pcmn X r1 r2 s => + Next (nextinstr (compare_long rs rs###r1 (Val.negl (eval_shift_op_long rs#r2 s)) m)) m + (** Integer arithmetic, extending register *) + | Paddext rd r1 r2 x => + Next (nextinstr (rs#rd <- (Val.addl rs#r1 (eval_extend rs#r2 x)))) m + | Psubext rd r1 r2 x => + Next (nextinstr (rs#rd <- (Val.subl rs#r1 (eval_extend rs#r2 x)))) m + | Pcmpext r1 r2 x => + Next (nextinstr (compare_long rs rs#r1 (eval_extend rs#r2 x) m)) m + | Pcmnext r1 r2 x => + Next (nextinstr (compare_long rs rs#r1 (Val.negl (eval_extend rs#r2 x)) m)) m + (** Logical, shifted register *) + | Pand W rd r1 r2 s => + Next (nextinstr (rs#rd <- (Val.and rs##r1 (eval_shift_op_int rs#r2 s)))) m + | Pand X rd r1 r2 s => + Next (nextinstr (rs#rd <- (Val.andl rs###r1 (eval_shift_op_long rs#r2 s)))) m + | Pbic W rd r1 r2 s => + Next (nextinstr (rs#rd <- (Val.and rs##r1 (Val.notint (eval_shift_op_int rs#r2 s))))) m + | Pbic X rd r1 r2 s => + Next (nextinstr (rs#rd <- (Val.andl rs###r1 (Val.notl (eval_shift_op_long rs#r2 s))))) m + | Peon W rd r1 r2 s => + Next (nextinstr (rs#rd <- (Val.xor rs##r1 (Val.notint (eval_shift_op_int rs#r2 s))))) m + | Peon X rd r1 r2 s => + Next (nextinstr (rs#rd <- (Val.xorl rs###r1 (Val.notl (eval_shift_op_long rs#r2 s))))) m + | Peor W rd r1 r2 s => + Next (nextinstr (rs#rd <- (Val.xor rs##r1 (eval_shift_op_int rs#r2 s)))) m + | Peor X rd r1 r2 s => + Next (nextinstr (rs#rd <- (Val.xorl rs###r1 (eval_shift_op_long rs#r2 s)))) m + | Porr W rd r1 r2 s => + Next (nextinstr (rs#rd <- (Val.or rs##r1 (eval_shift_op_int rs#r2 s)))) m + | Porr X rd r1 r2 s => + Next (nextinstr (rs#rd <- (Val.orl rs###r1 (eval_shift_op_long rs#r2 s)))) m + | Porn W rd r1 r2 s => + Next (nextinstr (rs#rd <- (Val.or rs##r1 (Val.notint (eval_shift_op_int rs#r2 s))))) m + | Porn X rd r1 r2 s => + Next (nextinstr (rs#rd <- (Val.orl rs###r1 (Val.notl (eval_shift_op_long rs#r2 s))))) m + | Ptst W r1 r2 s => + Next (nextinstr (compare_int rs (Val.and rs##r1 (eval_shift_op_int rs#r2 s)) (Vint Int.zero) m)) m + | Ptst X r1 r2 s => + Next (nextinstr (compare_long rs (Val.andl rs###r1 (eval_shift_op_long rs#r2 s)) (Vlong Int64.zero) m)) m + (** Variable shifts *) + | Pasrv W rd r1 r2 => + Next (nextinstr (rs#rd <- (Val.shr rs#r1 rs#r2))) m + | Pasrv X rd r1 r2 => + Next (nextinstr (rs#rd <- (Val.shrl rs#r1 rs#r2))) m + | Plslv W rd r1 r2 => + Next (nextinstr (rs#rd <- (Val.shl rs#r1 rs#r2))) m + | Plslv X rd r1 r2 => + Next (nextinstr (rs#rd <- (Val.shll rs#r1 rs#r2))) m + | Plsrv W rd r1 r2 => + Next (nextinstr (rs#rd <- (Val.shru rs#r1 rs#r2))) m + | Plsrv X rd r1 r2 => + Next (nextinstr (rs#rd <- (Val.shrlu rs#r1 rs#r2))) m + | Prorv W rd r1 r2 => + Next (nextinstr (rs#rd <- (Val.ror rs#r1 rs#r2))) m + | Prorv X rd r1 r2 => + Next (nextinstr (rs#rd <- (Val.rorl rs#r1 rs#r2))) m + (** Conditional data processing *) + | Pcsel rd r1 r2 cond => + let v := + match eval_testcond cond rs with + | Some true => rs#r1 + | Some false => rs#r2 + | None => Vundef + end in + Next (nextinstr (rs#rd <- v)) m + | Pcset rd cond => + let v := + match cond rs with + | Some true => Vint Int.one + | Some false => Vint Int.zero + | None => Vundef + end in + Next (nextinstr (rs#rd <- v)) m + (** Integer multiply/divide *) + | Pmadd W rd r1 r2 r3 => + Next (nextinstr (rs#rd <- (Val.add rs##r3 (Val.mul rs#r1 rs#r2)))) m + | Pmadd X rd r1 r2 r3 => + Next (nextinstr (rs#rd <- (Val.addl rs###r3 (Val.mull rs#r1 rs#r2)))) m + | Pmsub W rd r1 r2 r3 => + Next (nextinstr (rs#rd <- (Val.sub rs##r3 (Val.mul rs#r1 rs#r2)))) m + | Pmsub X rd r1 r2 r3 => + Next (nextinstr (rs#rd <- (Val.subl rs###r3 (Val.mull rs#r1 rs#r2)))) m + | Psmulh rd r1 r2 => + Next (nextinstr (rs#rd <- (Val.mullhs rs#r1 rs#r2))) m + | Pumulh rd r1 r2 => + Next (nextinstr (rs#rd <- (Val.mullhu rs#r1 rs#r2))) m + | Psdiv W rd r1 r2 => + Next (nextinstr (rs#rd <- (Val.maketotal (Val.divs rs#r1 rs#r2)))) m + | Psdiv X rd r1 r2 => + Next (nextinstr (rs#rd <- (Val.maketotal (Val.divls rs#r1 rs#r2)))) m + | Pudiv W rd r1 r2 => + Next (nextinstr (rs#rd <- (Val.maketotal (Val.divu rs#r1 rs#r2)))) m + | Pudiv X rd r1 r2 => + Next (nextinstr (rs#rd <- (Val.maketotal (Val.divlu rs#r1 rs#r2)))) m + (** Floating-point loads and stores *) + | Pldrs rd a => + exec_load Mfloat32 (fun v => v) a rd rs m + | Pldrd rd a => + exec_load Mfloat64 (fun v => v) a rd rs m + | Pldrd_a rd a => + exec_load Many64 (fun v => v) a rd rs m + | Pstrs r a => + exec_store Mfloat32 a rs#r rs m + | Pstrd r a => + exec_store Mfloat64 a rs#r rs m + | Pstrd_a r a => + exec_store Many64 a rs#r rs m + (** Floating-point move *) + | Pfmov rd r1 => + Next (nextinstr (rs#rd <- (rs#r1))) m + | Pfmovimms rd f => + Next (nextinstr (rs#rd <- (Vsingle f))) m + | Pfmovimmd rd f => + Next (nextinstr (rs#rd <- (Vfloat f))) m + | Pfmovi S rd r1 => + Next (nextinstr (rs#rd <- (float32_of_bits rs##r1))) m + | Pfmovi D rd r1 => + Next (nextinstr (rs#rd <- (float64_of_bits rs###r1))) m + (** Floating-point conversions *) + | Pfcvtds rd r1 => + Next (nextinstr (rs#rd <- (Val.floatofsingle rs#r1))) m + | Pfcvtsd rd r1 => + Next (nextinstr (rs#rd <- (Val.singleoffloat rs#r1))) m + | Pfcvtzs W S rd r1 => + Next (nextinstr (rs#rd <- (Val.maketotal (Val.intofsingle rs#r1)))) m + | Pfcvtzs W D rd r1 => + Next (nextinstr (rs#rd <- (Val.maketotal (Val.intoffloat rs#r1)))) m + | Pfcvtzs X S rd r1 => + Next (nextinstr (rs#rd <- (Val.maketotal (Val.longofsingle rs#r1)))) m + | Pfcvtzs X D rd r1 => + Next (nextinstr (rs#rd <- (Val.maketotal (Val.longoffloat rs#r1)))) m + | Pfcvtzu W S rd r1 => + Next (nextinstr (rs#rd <- (Val.maketotal (Val.intuofsingle rs#r1)))) m + | Pfcvtzu W D rd r1 => + Next (nextinstr (rs#rd <- (Val.maketotal (Val.intuoffloat rs#r1)))) m + | Pfcvtzu X S rd r1 => + Next (nextinstr (rs#rd <- (Val.maketotal (Val.longuofsingle rs#r1)))) m + | Pfcvtzu X D rd r1 => + Next (nextinstr (rs#rd <- (Val.maketotal (Val.longuoffloat rs#r1)))) m + | Pscvtf S W rd r1 => + Next (nextinstr (rs#rd <- (Val.maketotal (Val.singleofint rs#r1)))) m + | Pscvtf D W rd r1 => + Next (nextinstr (rs#rd <- (Val.maketotal (Val.floatofint rs#r1)))) m + | Pscvtf S X rd r1 => + Next (nextinstr (rs#rd <- (Val.maketotal (Val.singleoflong rs#r1)))) m + | Pscvtf D X rd r1 => + Next (nextinstr (rs#rd <- (Val.maketotal (Val.floatoflong rs#r1)))) m + | Pucvtf S W rd r1 => + Next (nextinstr (rs#rd <- (Val.maketotal (Val.singleofintu rs#r1)))) m + | Pucvtf D W rd r1 => + Next (nextinstr (rs#rd <- (Val.maketotal (Val.floatofintu rs#r1)))) m + | Pucvtf S X rd r1 => + Next (nextinstr (rs#rd <- (Val.maketotal (Val.singleoflongu rs#r1)))) m + | Pucvtf D X rd r1 => + Next (nextinstr (rs#rd <- (Val.maketotal (Val.floatoflongu rs#r1)))) m + (** Floating-point arithmetic *) + | Pfabs S rd r1 => + Next (nextinstr (rs#rd <- (Val.absfs rs#r1))) m + | Pfabs D rd r1 => + Next (nextinstr (rs#rd <- (Val.absf rs#r1))) m + | Pfneg S rd r1 => + Next (nextinstr (rs#rd <- (Val.negfs rs#r1))) m + | Pfneg D rd r1 => + Next (nextinstr (rs#rd <- (Val.negf rs#r1))) m + | Pfadd S rd r1 r2 => + Next (nextinstr (rs#rd <- (Val.addfs rs#r1 rs#r2))) m + | Pfadd D rd r1 r2 => + Next (nextinstr (rs#rd <- (Val.addf rs#r1 rs#r2))) m + | Pfdiv S rd r1 r2 => + Next (nextinstr (rs#rd <- (Val.divfs rs#r1 rs#r2))) m + | Pfdiv D rd r1 r2 => + Next (nextinstr (rs#rd <- (Val.divf rs#r1 rs#r2))) m + | Pfmul S rd r1 r2 => + Next (nextinstr (rs#rd <- (Val.mulfs rs#r1 rs#r2))) m + | Pfmul D rd r1 r2 => + Next (nextinstr (rs#rd <- (Val.mulf rs#r1 rs#r2))) m + | Pfnmul S rd r1 r2 => + Next (nextinstr (rs#rd <- (Val.negfs (Val.mulfs rs#r1 rs#r2)))) m + | Pfnmul D rd r1 r2 => + Next (nextinstr (rs#rd <- (Val.negf (Val.mulf rs#r1 rs#r2)))) m + | Pfsub S rd r1 r2 => + Next (nextinstr (rs#rd <- (Val.subfs rs#r1 rs#r2))) m + | Pfsub D rd r1 r2 => + Next (nextinstr (rs#rd <- (Val.subf rs#r1 rs#r2))) m + (** Floating-point comparison *) + | Pfcmp S r1 r2 => + Next (nextinstr (compare_single rs rs#r1 rs#r2)) m + | Pfcmp D r1 r2 => + Next (nextinstr (compare_float rs rs#r1 rs#r2)) m + | Pfcmp0 S r1 => + Next (nextinstr (compare_single rs rs#r1 (Vsingle Float32.zero))) m + | Pfcmp0 D r1 => + Next (nextinstr (compare_float rs rs#r1 (Vfloat Float.zero))) m + (** Floating-point conditional select *) + | Pfsel rd r1 r2 cond => + let v := + match eval_testcond cond rs with + | Some true => rs#r1 + | Some false => rs#r2 + | None => Vundef + end in + Next (nextinstr (rs#rd <- v)) m + (** Pseudo-instructions *) + | Pallocframe sz pos => + let (m1, stk) := Mem.alloc m 0 sz in + let sp := (Vptr stk Ptrofs.zero) in + match Mem.storev Mint64 m1 (Val.offset_ptr sp pos) rs#SP with + | None => Stuck + | Some m2 => Next (nextinstr (rs #X29 <- (rs#SP) #SP <- sp #X16 <- Vundef)) m2 + end + | Pfreeframe sz pos => + match Mem.loadv Mint64 m (Val.offset_ptr rs#SP pos) with + | None => Stuck + | Some v => + match rs#SP with + | Vptr stk ofs => + match Mem.free m stk 0 sz with + | None => Stuck + | Some m' => Next (nextinstr (rs#SP <- v #X16 <- Vundef)) m' + end + | _ => Stuck + end + end + | Plabel lbl => + Next (nextinstr rs) m + | Ploadsymbol rd id => + Next (nextinstr (rs#rd <- (Genv.symbol_address ge id Ptrofs.zero))) m + | Pcvtsw2x rd r1 => + Next (nextinstr (rs#rd <- (Val.longofint rs#r1))) m + | Pcvtuw2x rd r1 => + Next (nextinstr (rs#rd <- (Val.longofintu rs#r1))) m + | Pcvtx2w rd => + Next (nextinstr (rs#rd <- (Val.loword rs#rd))) m + | Pbtbl r tbl => + match (rs#X16 <- Vundef)#r with + | Vint n => + match list_nth_z tbl (Int.unsigned n) with + | None => Stuck + | Some lbl => goto_label f lbl (rs#X16 <- Vundef #X17 <- Vundef) m + end + | _ => Stuck + end + | Pbuiltin ef args res => Stuck (**r treated specially below *) + (** The following instructions and directives are not generated directly + by Asmgen, so we do not model them. *) + | Pldp _ _ _ + | Pstp _ _ _ + | Pcls _ _ _ + | Pclz _ _ _ + | Prev _ _ _ + | Prev16 _ _ _ + | Pfsqrt _ _ _ + | Pfmadd _ _ _ _ _ + | Pfmsub _ _ _ _ _ + | Pfnmadd _ _ _ _ _ + | Pfnmsub _ _ _ _ _ + | Pnop + | Pcfi_adjust _ + | Pcfi_rel_offset _ => + Stuck + end. +*) + +(** execution of the body of a bblock *) +Fixpoint exec_body (body: list basic) (rs: regset) (m: mem): outcome := + match body with + | nil => Next rs m + | bi::body' => + SOME o <- exec_basic bi rs m IN + exec_body body' (_rs o) (_m o) + end. + +Definition incrPC size_b (rs: regset) := + rs#PC <- (Val.offset_ptr rs#PC size_b). + +Definition estep (f: function) cfi size_b (rs: regset) (m: mem) := + exec_cfi f cfi (incrPC size_b rs) m. + +(** execution of the exit instruction of a bblock *) +Inductive exec_exit (f: function) size_b (rs: regset) (m: mem): (option control) -> trace -> regset -> mem -> Prop := + | none_step: + exec_exit f size_b rs m None E0 (incrPC size_b rs) m + | cfi_step (cfi: cf_instruction) rs' m': + exec_cfi f cfi (incrPC size_b rs) m = Next rs' m' -> + exec_exit f size_b rs m (Some (PCtlFlow cfi)) E0 rs' m' + | builtin_step ef args res vargs t vres rs' m': + eval_builtin_args ge (fun (r: dreg) => rs r) rs#SP m args vargs -> + external_call ef ge vargs m t vres m' -> + rs' = incrPC size_b + (set_res (map_builtin_res DR res) vres + (undef_regs (map preg_of (destroyed_by_builtin ef)) rs)) -> + exec_exit f size_b rs m (Some (Pbuiltin ef args res)) t rs' m' + . + +Definition bbstep f cfi size_b bdy rs m := + match exec_body bdy rs m with + | Some (State rs' m') => estep f cfi size_b rs' m' + | Stuck => Stuck + end. + +Definition exec_bblock (f: function) (b: bblock) (rs: regset) (m: mem) (t:trace) (rs':regset) (m':mem): Prop + := exists rs1 m1, exec_body (body b) rs m = Next rs1 m1 /\ exec_exit f (Ptrofs.repr (size b)) rs1 m1 (exit b) t rs' m'. + +Fixpoint find_bblock (pos: Z) (lb: bblocks) {struct lb} : option bblock := + match lb with + | nil => None + | b :: il => + if zlt pos 0 then None (* NOTE: It is impossible to branch inside a block *) + else if zeq pos 0 then Some b + else find_bblock (pos - (size b)) il + end. + +(** Execution of the instruction at [rs PC]. *) + +Inductive step: state -> trace -> state -> Prop := + | exec_step_internal: + forall b ofs f bi rs m t rs' m', + rs PC = Vptr b ofs -> + Genv.find_funct_ptr ge b = Some (Internal f) -> + find_bblock (Ptrofs.unsigned ofs) (fn_blocks f) = Some bi -> + exec_bblock f bi rs m t rs' m' -> + step (State rs m) t (State rs' m') + | exec_step_external: + forall b ef args res rs m t rs' m', + rs PC = Vptr b Ptrofs.zero -> + Genv.find_funct_ptr ge b = Some (External ef) -> + external_call ef ge args m t res m' -> + extcall_arguments rs m (ef_sig ef) args -> + rs' = (set_pair (loc_external_result (ef_sig ef) ) res (undef_caller_save_regs rs))#PC <- (rs RA) -> + step (State rs m) t (State rs' m') + . + + +End RELSEM. + + +(** Execution of whole programs. *) + +Inductive initial_state (p: program): state -> Prop := + | initial_state_intro: forall m0, + Genv.init_mem p = Some m0 -> + let ge := Genv.globalenv p in + let rs0 := + (Pregmap.init Vundef) + # PC <- (Genv.symbol_address ge p.(prog_main) Ptrofs.zero) + # RA <- Vnullptr + # SP <- Vnullptr in + initial_state p (State rs0 m0). + +Inductive final_state: state -> int -> Prop := + | final_state_intro: forall rs m r, + rs#PC = Vnullptr -> + rs#X0 = Vint r -> + final_state (State rs m) r. + +Definition semantics (lk: aarch64_linker) (p: program) := + Semantics (step lk) (initial_state p) final_state (Genv.globalenv p). diff --git a/aarch64/Asmblockdeps.v b/aarch64/Asmblockdeps.v new file mode 100644 index 00000000..bd460209 --- /dev/null +++ b/aarch64/Asmblockdeps.v @@ -0,0 +1,2754 @@ +(* *************************************************************) +(* *) +(* The Compcert verified compiler *) +(* *) +(* Sylvain Boulmé Grenoble-INP, VERIMAG *) +(* David Monniaux CNRS, VERIMAG *) +(* Cyril Six Kalray *) +(* Léo Gourdin UGA, VERIMAG *) +(* *) +(* Copyright Kalray. Copyright VERIMAG. All rights reserved. *) +(* This file is distributed under the terms of the INRIA *) +(* Non-Commercial License Agreement. *) +(* *) +(* *************************************************************) + +(** * Translation from [Asmvliw] to [AbstractBB] *) + +(** We define a specific instance [L] of [AbstractBB] and translate [bblocks] from [Asmvliw] into [L]. + [AbstractBB] will then define two semantics for [L]: a sequential and a parallel one. + We prove a bisimulation between the parallel semantics of [L] and [AsmVLIW]. + We also prove a bisimulation between the sequential semantics of [L] and [Asmblock]. + Then, the checkers on [Asmblock] and [Asmvliw] are deduced from those of [L]. + *) + +Require Import AST. +Require Import Asm Asmblock. +Require Import Asmblockgenproof0 Asmblockprops. +Require Import Values. +Require Import Globalenvs. +Require Import Memory. +Require Import Errors. +Require Import Integers. +Require Import Floats. +Require Import ZArith. +Require Import Coqlib. +Require Import ImpSimuTest. +Require Import Axioms. +Require Import Permutation. +Require Import Events. + +Require Import Lia. + +Open Scope impure. + +(** auxiliary treatments of builtins *) + +Definition has_builtin(bb: bblock): bool := + match exit bb with + | Some (Pbuiltin _ _ _) => true + | _ => false + end. + +Remark builtin_arg_eq_dreg: forall (a b: builtin_arg dreg), {a=b} + {a<>b}. +Proof. + intros. + apply (builtin_arg_eq dreg_eq). +Qed. + +Remark builtin_res_eq_dreg: forall (a b: builtin_res dreg), {a=b} + {a<>b}. +Proof. + intros. + apply (builtin_res_eq dreg_eq). +Qed. + +Definition assert_same_builtin (bb1 bb2: bblock): ?? unit := + match exit bb1 with + | Some (Pbuiltin ef1 lbar1 brr1) => + match exit bb2 with + | Some (Pbuiltin ef2 lbar2 brr2) => + if (external_function_eq ef1 ef2) then + if (list_eq_dec builtin_arg_eq_dreg lbar1 lbar2) then + if (builtin_res_eq_dreg brr1 brr2) then RET tt + else FAILWITH "Different brr in Pbuiltin" + else FAILWITH "Different lbar in Pbuiltin" + else FAILWITH "Different ef in Pbuiltin" + | _ => FAILWITH "Expected a builtin: found something else" (* XXX: on peut raffiner le message d'erreur si nécessaire *) + end + | _ => RET tt (* ok *) + end. + +Lemma assert_same_builtin_correct (bb1 bb2: bblock): + WHEN assert_same_builtin bb1 bb2 ~> _ THEN + has_builtin bb1 = true -> exit bb1 = exit bb2. +Proof. + unfold assert_same_builtin, has_builtin. + destruct (exit bb1) as [[]|]; simpl; try (wlp_simplify; congruence). + destruct (exit bb2) as [[]|]; wlp_simplify. +Qed. +Global Opaque assert_same_builtin. +Local Hint Resolve assert_same_builtin_correct: wlp. + +(** Definition of [L] *) + +Module P<: ImpParam. +Module R := Pos. + +Section IMPPARAM. + +Definition env := Genv.t fundef unit. + +Record genv_wrap := { _genv: env; _fn: function; _lk: aarch64_linker }. +Definition genv := genv_wrap. + +Variable Ge: genv. + +Inductive value_wrap := + | Val (v: val) + | Memstate (m: mem) + | Bool (b: bool) +. + +Definition value := value_wrap. + +Record CRflags := { _CN: val; _CZ:val; _CC: val; _CV: val }. + +Inductive control_op := + (*| Oj_l (l: label)*) + | Ob (l: label) + | Obc (c: testcond) (l: label) + | Obl (id: ident) + | Obs (id: ident) + | Ocbnz (sz: isize) (l: label) + | Ocbz (sz: isize) (l: label) + | Otbnz (sz: isize) (n: int) (l: label) + | Otbz (sz: isize) (n: int) (l: label) + | Obtbl (l: list label) + | OError + | OIncremPC (sz: Z) +. + +Inductive arith_op := + | OArithP (n: arith_p) + | OArithPP (n: arith_pp) + | OArithPPP (n: arith_ppp) + | OArithRR0R (n: arith_rr0r) + | OArithRR0R_XZR (n: arith_rr0r) (vz: val) + | OArithRR0 (n: arith_rr0) + | OArithRR0_XZR (n: arith_rr0) (vz: val) + | OArithARRRR0 (n: arith_arrrr0) + | OArithARRRR0_XZR (n: arith_arrrr0) (vz: val) + | OArithComparisonPP_CN (n: arith_comparison_pp) + | OArithComparisonPP_CZ (n: arith_comparison_pp) + | OArithComparisonPP_CC (n: arith_comparison_pp) + | OArithComparisonPP_CV (n: arith_comparison_pp) + | OArithComparisonR0R_CN (n: arith_comparison_r0r) (is: isize) + | OArithComparisonR0R_CZ (n: arith_comparison_r0r) (is: isize) + | OArithComparisonR0R_CC (n: arith_comparison_r0r) (is: isize) + | OArithComparisonR0R_CV (n: arith_comparison_r0r) (is: isize) + | OArithComparisonR0R_CN_XZR (n: arith_comparison_r0r) (is: isize) (vz: val) + | OArithComparisonR0R_CZ_XZR (n: arith_comparison_r0r) (is: isize) (vz: val) + | OArithComparisonR0R_CC_XZR (n: arith_comparison_r0r) (is: isize) (vz: val) + | OArithComparisonR0R_CV_XZR (n: arith_comparison_r0r) (is: isize) (vz: val) + | OArithComparisonP_CN (n: arith_comparison_p) + | OArithComparisonP_CZ (n: arith_comparison_p) + | OArithComparisonP_CC (n: arith_comparison_p) + | OArithComparisonP_CV (n: arith_comparison_p) + | Ocset (c: testcond) + | Ofmovi (fsz: fsize) + | Ofmovi_XZR (fsz: fsize) + | Ocsel (c: testcond) + | Ofnmul (fsz: fsize) +. + +Inductive store_op := + | Ostore1 (st: store_rs_a) (a: addressing) + | Ostore2 (st: store_rs_a) (a: addressing) + | OstoreU (st: store_rs_a) (a: addressing) +. + +Inductive load_op := + | Oload1 (ld: load_rd_a) (a: addressing) + | Oload2 (ld: load_rd_a) (a: addressing) + | OloadU (ld: load_rd_a) (a: addressing) +. + +Inductive allocf_op := + | OAllocf_SP (sz: Z) (linkofs: ptrofs) + | OAllocf_Mem (sz: Z) (linkofs: ptrofs) +. + +Inductive freef_op := + | OFreef_SP (sz: Z) (linkofs: ptrofs) + | OFreef_Mem (sz: Z) (linkofs: ptrofs) +. + +Inductive op_wrap := + (* arithmetic operation *) + | Arith (op: arith_op) + | Load (ld: load_op) + | Store (st: store_op) + | Allocframe (al: allocf_op) + | Freeframe (fr: freef_op) + | Loadsymbol (id: ident) + | Cvtsw2x + | Cvtuw2x + | Cvtx2w + | Control (co: control_op) + | Constant (v: val) +. + +Definition op:=op_wrap. + +Coercion Arith: arith_op >-> op_wrap. + +Definition v_compare_int (v1 v2: val) : CRflags := + {| _CN := (Val.negative (Val.sub v1 v2)); + _CZ := (Val_cmpu Ceq v1 v2); + _CC := (Val_cmpu Cge v1 v2); + _CV := (Val.sub_overflow v1 v2) |}. + +Definition v_compare_long (v1 v2: val) : CRflags := + {| _CN := (Val.negativel (Val.subl v1 v2)); + _CZ := (Val_cmplu Ceq v1 v2); + _CC := (Val_cmplu Cge v1 v2); + _CV := (Val.subl_overflow v1 v2) |}. + +Definition v_compare_float (v1 v2: val) : CRflags := + match v1, v2 with + | Vfloat f1, Vfloat f2 => + {| _CN := (Val.of_bool (Float.cmp Clt f1 f2)); + _CZ := (Val.of_bool (Float.cmp Ceq f1 f2)); + _CC := (Val.of_bool (negb (Float.cmp Clt f1 f2))); + _CV := (Val.of_bool (negb (Float.ordered f1 f2))) |} + | _, _ => + {| _CN := Vundef; + _CZ := Vundef; + _CC := Vundef; + _CV := Vundef |} + end. + +Definition v_compare_single (v1 v2: val) : CRflags := + match v1, v2 with + | Vsingle f1, Vsingle f2 => + {| _CN := (Val.of_bool (Float32.cmp Clt f1 f2)); + _CZ := (Val.of_bool (Float32.cmp Ceq f1 f2)); + _CC := (Val.of_bool (negb (Float32.cmp Clt f1 f2))); + _CV := (Val.of_bool (negb (Float32.ordered f1 f2))) |} + | _, _ => + {| _CN := Vundef; + _CZ := Vundef; + _CC := Vundef; + _CV := Vundef |} + end. + +Definition arith_eval_comparison_pp (n: arith_comparison_pp) (v1 v2: val) := + let (v1',v2') := arith_prepare_comparison_pp n v1 v2 in + match n with + | Pcmpext _ | Pcmnext _ => v_compare_long v1' v2' + | Pfcmp S => v_compare_single v1' v2' + | Pfcmp D => v_compare_float v1' v2' + end. + +Definition arith_eval_comparison_p (n: arith_comparison_p) (v: val) := + let (v1',v2') := arith_prepare_comparison_p n v in + match n with + | Pcmpimm W _ | Pcmnimm W _ | Ptstimm W _ => v_compare_int v1' v2' + | Pcmpimm X _ | Pcmnimm X _ | Ptstimm X _ => v_compare_long v1' v2' + | Pfcmp0 S => v_compare_single v1' v2' + | Pfcmp0 D => v_compare_float v1' v2' + end. + +Definition arith_eval_comparison_r0r (n: arith_comparison_r0r) (v1 v2: val) (is: isize) := + let (v1',v2') := arith_prepare_comparison_r0r n v1 v2 in + if is then v_compare_int v1' v2' else v_compare_long v1' v2'. + +Definition flags_testcond_value (c: testcond) (vCN vCZ vCC vCV: val) := + match c with + | TCeq => (**r equal *) + match vCZ with + | Vint n => Some (Int.eq n Int.one) + | _ => None + end + | TCne => (**r not equal *) + match vCZ with + | Vint n => Some (Int.eq n Int.zero) + | _ => None + end + | TClo => (**r unsigned less than *) + match vCC with + | Vint n => Some (Int.eq n Int.zero) + | _ => None + end + | TCls => (**r unsigned less or equal *) + match vCC, vCZ with + | Vint c, Vint z => Some (Int.eq c Int.zero || Int.eq z Int.one) + | _, _ => None + end + | TChs => (**r unsigned greater or equal *) + match vCC with + | Vint n => Some (Int.eq n Int.one) + | _ => None + end + | TChi => (**r unsigned greater *) + match vCC, vCZ with + | Vint c, Vint z => Some (Int.eq c Int.one && Int.eq z Int.zero) + | _, _ => None + end + | TClt => (**r signed less than *) + match vCV, vCN with + | Vint o, Vint s => Some (Int.eq (Int.xor o s) Int.one) + | _, _ => None + end + | TCle => (**r signed less or equal *) + match vCV, vCN, vCZ with + | Vint o, Vint s, Vint z => Some (Int.eq (Int.xor o s) Int.one || Int.eq z Int.one) + | _, _, _ => None + end + | TCge => (**r signed greater or equal *) + match vCV, vCN with + | Vint o, Vint s => Some (Int.eq (Int.xor o s) Int.zero) + | _, _ => None + end + | TCgt => (**r signed greater *) + match vCV, vCN, vCZ with + | Vint o, Vint s, Vint z => Some (Int.eq (Int.xor o s) Int.zero && Int.eq z Int.zero) + | _, _, _ => None + end + | TCpl => (**r positive *) + match vCN with + | Vint n => Some (Int.eq n Int.zero) + | _ => None + end + | TCmi => (**r negative *) + match vCN with + | Vint n => Some (Int.eq n Int.one) + | _ => None + end + end. + +Definition cond_eval_is (c: testcond) (v1 v2 vCN vCZ vCC vCV: val) (is: Z) := + let res := flags_testcond_value c vCN vCZ vCC vCV in + match is, res with + | 0, res => Some (Val (if_opt_bool_val res (Vint Int.one) (Vint Int.zero))) + | 1, res => Some (Val (if_opt_bool_val res v1 v2)) + | 2, Some b => Some (Bool (b)) + | _, _ => None + end. + +Definition fmovi_eval (fsz: fsize) (v: val) := + match fsz with + | S => float32_of_bits v + | D => float64_of_bits v + end. + +Definition fmovi_eval_xzr (fsz: fsize) := + match fsz with + | S => float32_of_bits (Vint Int.zero) + | D => float64_of_bits (Vlong Int64.zero) + end. + +Definition fnmul_eval (fsz: fsize) (v1 v2: val) := + match fsz with + | S => Val.negfs (Val.mulfs v1 v2) + | D => Val.negf (Val.mulf v1 v2) + end. + +Definition cflags_eval (c: testcond) (l: list value) (v1 v2: val) (is: Z) := + + match c, l with + | TCeq, [Val vCZ] => cond_eval_is TCeq v1 v2 Vundef vCZ Vundef Vundef is + | TCne, [Val vCZ] => cond_eval_is TCne v1 v2 Vundef vCZ Vundef Vundef is + | TChs, [Val vCC] => cond_eval_is TChs v1 v2 Vundef Vundef vCC Vundef is + | TClo, [Val vCC] => cond_eval_is TClo v1 v2 Vundef Vundef vCC Vundef is + | TCmi, [Val vCN] => cond_eval_is TCmi v1 v2 vCN Vundef Vundef Vundef is + | TCpl, [Val vCN] => cond_eval_is TCpl v1 v2 vCN Vundef Vundef Vundef is + | TChi, [Val vCZ; Val vCC] => cond_eval_is TChi v1 v2 Vundef vCZ vCC Vundef is + | TCls, [Val vCZ; Val vCC] => cond_eval_is TCls v1 v2 Vundef vCZ vCC Vundef is + | TCge, [Val vCN; Val vCV] => cond_eval_is TCge v1 v2 vCN Vundef Vundef vCV is + | TClt, [Val vCN; Val vCV] => cond_eval_is TClt v1 v2 vCN Vundef Vundef vCV is + | TCgt, [Val vCN; Val vCZ; Val vCV] => cond_eval_is TCgt v1 v2 vCN vCZ Vundef vCV is + | TCle, [Val vCN; Val vCZ; Val vCV] => cond_eval_is TCle v1 v2 vCN vCZ Vundef vCV is + | _, _ => None + end. + +Definition arith_op_eval (op: arith_op) (l: list value) := + match op, l with + | OArithP n, [] => Some (Val (arith_eval_p Ge.(_lk) n)) + | OArithPP n, [Val v] => Some (Val (arith_eval_pp Ge.(_lk) n v)) + | OArithPPP n, [Val v1; Val v2] => Some (Val (arith_eval_ppp n v1 v2)) + | OArithRR0R n, [Val v1; Val v2] => Some (Val (arith_eval_rr0r n v1 v2)) + | OArithRR0R_XZR n vz, [Val v] => Some (Val (arith_eval_rr0r n vz v)) + | OArithRR0 n, [Val v] => Some (Val (arith_eval_rr0 n v)) + | OArithRR0_XZR n vz, [] => Some (Val (arith_eval_rr0 n vz)) + | OArithARRRR0 n, [Val v1; Val v2; Val v3] => Some (Val (arith_eval_arrrr0 n v1 v2 v3)) + | OArithARRRR0_XZR n vz, [Val v1; Val v2] => Some (Val (arith_eval_arrrr0 n v1 v2 vz)) + | OArithComparisonPP_CN n, [Val v1; Val v2] => Some (Val ((arith_eval_comparison_pp n v1 v2).(_CN))) + | OArithComparisonPP_CZ n, [Val v1; Val v2] => Some (Val ((arith_eval_comparison_pp n v1 v2).(_CZ))) + | OArithComparisonPP_CC n, [Val v1; Val v2] => Some (Val ((arith_eval_comparison_pp n v1 v2).(_CC))) + | OArithComparisonPP_CV n, [Val v1; Val v2] => Some (Val ((arith_eval_comparison_pp n v1 v2).(_CV))) + | OArithComparisonR0R_CN n is, [Val v1; Val v2] => Some (Val ((arith_eval_comparison_r0r n v1 v2 is).(_CN))) + | OArithComparisonR0R_CZ n is, [Val v1; Val v2] => Some (Val ((arith_eval_comparison_r0r n v1 v2 is).(_CZ))) + | OArithComparisonR0R_CC n is, [Val v1; Val v2] => Some (Val ((arith_eval_comparison_r0r n v1 v2 is).(_CC))) + | OArithComparisonR0R_CV n is, [Val v1; Val v2] => Some (Val ((arith_eval_comparison_r0r n v1 v2 is).(_CV))) + | OArithComparisonR0R_CN_XZR n is vz, [Val v2] => Some (Val ((arith_eval_comparison_r0r n vz v2 is).(_CN))) + | OArithComparisonR0R_CZ_XZR n is vz, [Val v2] => Some (Val ((arith_eval_comparison_r0r n vz v2 is).(_CZ))) + | OArithComparisonR0R_CC_XZR n is vz, [Val v2] => Some (Val ((arith_eval_comparison_r0r n vz v2 is).(_CC))) + | OArithComparisonR0R_CV_XZR n is vz, [Val v2] => Some (Val ((arith_eval_comparison_r0r n vz v2 is).(_CV))) + | OArithComparisonP_CN n, [Val v] => Some (Val ((arith_eval_comparison_p n v).(_CN))) + | OArithComparisonP_CZ n, [Val v] => Some (Val ((arith_eval_comparison_p n v).(_CZ))) + | OArithComparisonP_CC n, [Val v] => Some (Val ((arith_eval_comparison_p n v).(_CC))) + | OArithComparisonP_CV n, [Val v] => Some (Val ((arith_eval_comparison_p n v).(_CV))) + | Ocset c, l => cflags_eval c l Vundef Vundef 0 + | Ofmovi fsz, [Val v] => Some (Val (fmovi_eval fsz v)) + | Ofmovi_XZR fsz, [] => Some (Val (fmovi_eval_xzr fsz)) + | Ocsel c, Val v1 :: Val v2 :: l' => cflags_eval c l' v1 v2 1 + | Ofnmul fsz, [Val v1; Val v2] => Some (Val (fnmul_eval fsz v1 v2)) + | _, _ => None + end. + +Definition call_ll_storev (c: memory_chunk) (m: mem) (v: option val) (vs: val) := + match v with + | Some va => match Mem.storev c m va vs with + | Some m' => Some (Memstate m') + | None => None + end + | None => None (* should never occurs *) + end. + +Definition exec_store1 (n: store_rs_a) (m: mem) (a: addressing) (vr vs: val) := + let v := + match a with + | ADimm _ n => Some (Val.addl vs (Vlong n)) + | ADadr _ id ofs => Some (Val.addl vs (symbol_low Ge.(_lk) id ofs)) + | _ => None + end in + call_ll_storev (chunk_store_rs_a n) m v vr. + +Definition exec_store2 (n: store_rs_a) (m: mem) (a: addressing) (vr vs1 vs2: val) := + let v := + match a with + | ADreg _ _ => Some (Val.addl vs1 vs2) + | ADlsl _ _ n => Some (Val.addl vs1 (Val.shll vs2 (Vint n))) + | ADsxt _ _ n => Some (Val.addl vs1 (Val.shll (Val.longofint vs2) (Vint n))) + | ADuxt _ _ n => Some (Val.addl vs1 (Val.shll (Val.longofintu vs2) (Vint n))) + | _ => None + end in + call_ll_storev (chunk_store_rs_a n) m v vr. + +Definition exec_storeU (n: store_rs_a) (m: mem) (a: addressing) (vr: val) := + call_ll_storev (chunk_store_rs_a n) m None vr. + +Definition goto_label_deps (f: function) (lbl: label) (vpc: val) := + match label_pos lbl 0 (fn_blocks f) with + | None => None + | Some pos => + match vpc with + | Vptr b ofs => Some (Val (Vptr b (Ptrofs.repr pos))) + | _ => None + end + end. + +Definition control_eval (o: control_op) (l: list value) := + let (ge, fn, lk) := Ge in + match o, l with + | Ob lbl, [Val vpc] => goto_label_deps fn lbl vpc + | Obc c lbl, Val vpc :: l' => match cflags_eval c l' Vundef Vundef 2 with + | Some (Bool true) => goto_label_deps fn lbl vpc + | Some (Bool false) => Some (Val vpc) + | _ => None + end + | Obl id, [] => Some (Val (Genv.symbol_address Ge.(_genv) id Ptrofs.zero)) + | Obs id, [] => Some (Val (Genv.symbol_address Ge.(_genv) id Ptrofs.zero)) + | Ocbnz sz lbl, [Val v; Val vpc] => match eval_testzero sz v with + | Some (true) => Some (Val vpc) + | Some (false) => goto_label_deps fn lbl vpc + | None => None + end + | Ocbz sz lbl, [Val v; Val vpc] => match eval_testzero sz v with + | Some (true) => goto_label_deps fn lbl vpc + | Some (false) => Some (Val vpc) + | None => None + end + | Otbnz sz n lbl, [Val v; Val vpc] => match eval_testbit sz v n with + | Some (true) => goto_label_deps fn lbl vpc + | Some (false) => Some (Val vpc) + | None => None + end + | Otbz sz n lbl, [Val v; Val vpc] => match eval_testbit sz v n with + | Some (true) => Some (Val vpc) + | Some (false) => goto_label_deps fn lbl vpc + | None => None + end + | Obtbl tbl, [Val index; Val vpc] => match index with + | Vint n => + match list_nth_z tbl (Int.unsigned n) with + | None => None + | Some lbl => goto_label_deps fn lbl vpc + end + | _ => None + end + | OIncremPC sz, [Val vpc] => Some (Val (Val.offset_ptr vpc (Ptrofs.repr sz))) + | OError, _ => None + | _, _ => None + end. + +Definition store_eval (o: store_op) (l: list value) := + match o, l with + | Ostore1 st a, [Val vr; Val vs; Memstate m] => exec_store1 st m a vr vs + | Ostore2 st a, [Val vr; Val vs1; Val vs2; Memstate m] => exec_store2 st m a vr vs1 vs2 + | OstoreU st a, [Val vr; Memstate m] => exec_storeU st m a vr + | _, _ => None + end. + +Definition call_ll_loadv (c: memory_chunk) (transf: val -> val) (m: mem) (v: option val) := + match v with + | Some va => match Mem.loadv c m va with + | Some v' => Some (Val (transf v')) + | None => None + end + | None => None (* should never occurs *) + end. + +Definition exec_load1 (n: load_rd_a) (m: mem) (a: addressing) (vl: val) := + let v := + match a with + | ADimm _ n => Some (Val.addl vl (Vlong n)) + | ADadr _ id ofs => Some (Val.addl vl (symbol_low Ge.(_lk) id ofs)) + | _ => None + end in + call_ll_loadv (chunk_load_rd_a n) (interp_load_rd_a n) m v. + +Definition exec_load2 (n: load_rd_a) (m: mem) (a: addressing) (vl1 vl2: val) := + let v := + match a with + | ADreg _ _ => Some (Val.addl vl1 vl2) + | ADlsl _ _ n => Some (Val.addl vl1 (Val.shll vl2 (Vint n))) + | ADsxt _ _ n => Some (Val.addl vl1 (Val.shll (Val.longofint vl2) (Vint n))) + | ADuxt _ _ n => Some (Val.addl vl1 (Val.shll (Val.longofintu vl2) (Vint n))) + | _ => None + end in + call_ll_loadv (chunk_load_rd_a n) (interp_load_rd_a n) m v. + +Definition exec_loadU (n: load_rd_a) (m: mem) (a: addressing) := + call_ll_loadv (chunk_load_rd_a n) (interp_load_rd_a n) m None. + +Definition load_eval (o: load_op) (l: list value) := + match o, l with + | Oload1 st a, [Val vs; Memstate m] => exec_load1 st m a vs + | Oload2 st a, [Val vs1; Val vs2; Memstate m] => exec_load2 st m a vs1 vs2 + | OloadU st a, [Memstate m] => exec_loadU st m a + | _, _ => None + end. + +Definition eval_allocf (o: allocf_op) (l: list value) := + match o, l with + | OAllocf_Mem sz linkofs, [Val spv; Memstate m] => + let (m1, stk) := Mem.alloc m 0 sz in + let sp := (Vptr stk Ptrofs.zero) in + call_ll_storev Mint64 m1 (Some (Val.offset_ptr sp linkofs)) spv + | OAllocf_SP sz linkofs, [Val spv; Memstate m] => + let (m1, stk) := Mem.alloc m 0 sz in + let sp := (Vptr stk Ptrofs.zero) in + match call_ll_storev Mint64 m1 (Some (Val.offset_ptr sp linkofs)) spv with + | None => None + | Some ms => Some (Val sp) + end + | _, _ => None + end. + +Definition eval_freef (o: freef_op) (l: list value) := + match o, l with + | OFreef_Mem sz linkofs, [Val spv; Memstate m] => + match call_ll_loadv Mint64 (fun v => v) m (Some (Val.offset_ptr spv linkofs)) with + | None => None + | Some v => + match spv with + | Vptr stk ofs => + match Mem.free m stk 0 sz with + | None => None + | Some m' => Some (Memstate m') + end + | _ => None + end + end + | OFreef_SP sz linkofs, [Val spv; Memstate m] => + match call_ll_loadv Mint64 (fun v => v) m (Some (Val.offset_ptr spv linkofs)) with + | None => None + | Some v => + match spv with + | Vptr stk ofs => + match Mem.free m stk 0 sz with + | None => None + | Some m' => Some (v) + end + | _ => None + end + end + | _, _ => None + end. + +Definition op_eval (op: op) (l:list value) := + match op, l with + | Arith op, l => arith_op_eval op l + | Load o, l => load_eval o l + | Store o, l => store_eval o l + | Allocframe o, l => eval_allocf o l + | Freeframe o, l => eval_freef o l + | Loadsymbol id, [] => Some (Val (Genv.symbol_address Ge.(_genv) id Ptrofs.zero)) + | Cvtsw2x, [Val v] => Some (Val (Val.longofint v)) + | Cvtuw2x, [Val v] => Some (Val (Val.longofintu v)) + | Cvtx2w, [Val v] => Some (Val (Val.loword v)) + | Control o, l => control_eval o l + | Constant v, [] => Some (Val v) + | _, _ => None + end. + +Definition vz_eq (vz1 vz2: val) : ?? bool := + RET (match vz1 with + | Vint i1 => match vz2 with + | Vint i2 => Int.eq i1 i2 + | _ => false + end + | Vlong l1 => match vz2 with + | Vlong l2 => Int64.eq l1 l2 + | _ => false + end + | _ => false + end). + +Lemma vz_eq_correct vz1 vz2: + WHEN vz_eq vz1 vz2 ~> b THEN b = true -> vz1 = vz2. +Proof. + wlp_simplify. + destruct vz1; destruct vz2; trivial; try discriminate. + - eapply f_equal; apply Int.same_if_eq; auto. + - eapply f_equal. apply Int64.same_if_eq; auto. +Qed. +Hint Resolve vz_eq_correct: wlp. + +Definition is_eq (is1 is2: isize) : ?? bool := + RET (match is1 with + | W => match is2 with + | W => true + | _ => false + end + | X => match is2 with + | X => true + | _ => false + end + end). + +Lemma is_eq_correct is1 is2: + WHEN is_eq is1 is2 ~> b THEN b = true -> is1 = is2. +Proof. + wlp_simplify; destruct is1; destruct is2; trivial; try discriminate. +Qed. +Hint Resolve is_eq_correct: wlp. + +(*Definition testcond_eq (c1 c2: testcond) : ?? bool :=*) + (*RET (match c1 with*) + (*| TCeq => match c2 with*) + (*| TCeq => true*) + (*| _ => false*) + (*end*) + (*| TCne => match c2 with*) + (*| TCne => true*) + (*| _ => false*) + (*end*) + (*| TChs => match c2 with*) + (*| TChs => true*) + (*| _ => false*) + (*end*) + (*| TClo => match c2 with*) + (*| TClo => true*) + (*| _ => false*) + (*end*) + (*| TCmi => match c2 with*) + (*| TCmi => true*) + (*| _ => false*) + (*end*) + (*| TCpl => match c2 with*) + (*| TCpl => true*) + (*| _ => false*) + (*end*) + (*| TChi => match c2 with*) + (*| TChi => true*) + (*| _ => false*) + (*end*) + (*| TCls => match c2 with*) + (*| TCls => true*) + (*| _ => false*) + (*end*) + (*| TCge => match c2 with*) + (*| TCge => true*) + (*| _ => false*) + (*end*) + (*| TClt => match c2 with*) + (*| TClt => true*) + (*| _ => false*) + (*end*) + (*| TCgt => match c2 with*) + (*| TCgt => true*) + (*| _ => false*) + (*end*) + (*| TCle => match c2 with*) + (*| TCle => true*) + (*| _ => false*) + (*end*) + (*end).*) + +(*Lemma testcond_eq_correct c1 c2:*) + (*WHEN testcond_eq c1 c2 ~> b THEN b = true -> c1 = c2.*) +(*Proof.*) + (*wlp_simplify; destruct c1; destruct c2; trivial; try discriminate.*) +(*Qed.*) +(*Hint Resolve testcond_eq_correct: wlp.*) + +Definition arith_op_eq (o1 o2: arith_op): ?? bool := + match o1 with + | OArithP n1 => + match o2 with OArithP n2 => phys_eq n1 n2 | _ => RET false end + | OArithPP n1 => + match o2 with OArithPP n2 => phys_eq n1 n2 | _ => RET false end + | OArithPPP n1 => + match o2 with OArithPPP n2 => phys_eq n1 n2 | _ => RET false end + | OArithRR0R n1 => + match o2 with OArithRR0R n2 => phys_eq n1 n2 | _ => RET false end + | OArithRR0R_XZR n1 vz1 => + match o2 with OArithRR0R_XZR n2 vz2 => iandb (phys_eq n1 n2) (vz_eq vz1 vz2) | _ => RET false end + | OArithRR0 n1 => + match o2 with OArithRR0 n2 => phys_eq n1 n2 | _ => RET false end + | OArithRR0_XZR n1 vz1 => + match o2 with OArithRR0_XZR n2 vz2 => iandb (phys_eq n1 n2) (vz_eq vz1 vz2) | _ => RET false end + | OArithARRRR0 n1 => + match o2 with OArithARRRR0 n2 => phys_eq n1 n2 | _ => RET false end + | OArithARRRR0_XZR n1 vz1 => + match o2 with OArithARRRR0_XZR n2 vz2 => iandb (phys_eq n1 n2) (vz_eq vz1 vz2) | _ => RET false end + | OArithComparisonPP_CN n1 => + match o2 with OArithComparisonPP_CN n2 => phys_eq n1 n2 | _ => RET false end + | OArithComparisonPP_CZ n1 => + match o2 with OArithComparisonPP_CZ n2 => phys_eq n1 n2 | _ => RET false end + | OArithComparisonPP_CC n1 => + match o2 with OArithComparisonPP_CC n2 => phys_eq n1 n2 | _ => RET false end + | OArithComparisonPP_CV n1 => + match o2 with OArithComparisonPP_CV n2 => phys_eq n1 n2 | _ => RET false end + | OArithComparisonR0R_CN n1 is1 => + match o2 with OArithComparisonR0R_CN n2 is2 => iandb (phys_eq n1 n2) (is_eq is1 is2) | _ => RET false end + | OArithComparisonR0R_CZ n1 is1 => + match o2 with OArithComparisonR0R_CZ n2 is2 => iandb (phys_eq n1 n2) (is_eq is1 is2) | _ => RET false end + | OArithComparisonR0R_CC n1 is1 => + match o2 with OArithComparisonR0R_CC n2 is2 => iandb (phys_eq n1 n2) (is_eq is1 is2) | _ => RET false end + | OArithComparisonR0R_CV n1 is1 => + match o2 with OArithComparisonR0R_CV n2 is2 => iandb (phys_eq n1 n2) (is_eq is1 is2) | _ => RET false end + | OArithComparisonR0R_CN_XZR n1 is1 vz1 => + match o2 with OArithComparisonR0R_CN_XZR n2 is2 vz2 => iandb (vz_eq vz1 vz2) (iandb (phys_eq n1 n2) (is_eq is1 is2)) | _ => RET false end + | OArithComparisonR0R_CZ_XZR n1 is1 vz1 => + match o2 with OArithComparisonR0R_CZ_XZR n2 is2 vz2 => iandb (vz_eq vz1 vz2) (iandb (phys_eq n1 n2) (is_eq is1 is2)) | _ => RET false end + | OArithComparisonR0R_CC_XZR n1 is1 vz1 => + match o2 with OArithComparisonR0R_CC_XZR n2 is2 vz2 => iandb (vz_eq vz1 vz2) (iandb (phys_eq n1 n2) (is_eq is1 is2)) | _ => RET false end + | OArithComparisonR0R_CV_XZR n1 is1 vz1 => + match o2 with OArithComparisonR0R_CV_XZR n2 is2 vz2 => iandb (vz_eq vz1 vz2) (iandb (phys_eq n1 n2) (is_eq is1 is2)) | _ => RET false end + | OArithComparisonP_CN n1 => + match o2 with OArithComparisonP_CN n2 => phys_eq n1 n2 | _ => RET false end + | OArithComparisonP_CZ n1 => + match o2 with OArithComparisonP_CZ n2 => phys_eq n1 n2 | _ => RET false end + | OArithComparisonP_CC n1 => + match o2 with OArithComparisonP_CC n2 => phys_eq n1 n2 | _ => RET false end + | OArithComparisonP_CV n1 => + match o2 with OArithComparisonP_CV n2 => phys_eq n1 n2 | _ => RET false end + | Ocset c1 => + match o2 with Ocset c2 => struct_eq c1 c2 | _ => RET false end + | Ofmovi fsz1 => + match o2 with Ofmovi fsz2 => phys_eq fsz1 fsz2 | _ => RET false end + | Ofmovi_XZR fsz1 => + match o2 with Ofmovi_XZR fsz2 => phys_eq fsz1 fsz2 | _ => RET false end + | Ocsel c1 => + match o2 with Ocsel c2 => struct_eq c1 c2 | _ => RET false end + | Ofnmul fsz1 => + match o2 with Ofnmul fsz2 => phys_eq fsz1 fsz2 | _ => RET false end + end. + +Ltac my_wlp_simplify := wlp_xsimplify ltac:(intros; subst; simpl in * |- *; congruence || intuition eauto with wlp). + +Lemma arith_op_eq_correct o1 o2: + WHEN arith_op_eq o1 o2 ~> b THEN b = true -> o1 = o2. +Proof. + destruct o1, o2; my_wlp_simplify; try congruence; + try (destruct vz; destruct vz0); try (destruct is; destruct is0); + repeat apply f_equal; try congruence; + try apply Int.same_if_eq; try apply Int64.same_if_eq; try auto. +Qed. +Hint Resolve arith_op_eq_correct: wlp. +Opaque arith_op_eq_correct. + +Definition control_op_eq (c1 c2: control_op): ?? bool := + match c1 with + | Ob lbl1 => + match c2 with Ob lbl2 => phys_eq lbl1 lbl2 | _ => RET false end + | Obc c1 lbl1 => + match c2 with Obc c2 lbl2 => iandb (struct_eq c1 c2) (phys_eq lbl1 lbl2) | _ => RET false end + | Obl id1 => + match c2 with Obl id2 => phys_eq id1 id2 | _ => RET false end + | Obs id1 => + match c2 with Obs id2 => phys_eq id1 id2 | _ => RET false end + | Ocbnz sz1 lbl1 => + match c2 with Ocbnz sz2 lbl2 => iandb (phys_eq sz1 sz2) (phys_eq lbl1 lbl2) | _ => RET false end + | Ocbz sz1 lbl1 => + match c2 with Ocbz sz2 lbl2 => iandb (phys_eq sz1 sz2) (phys_eq lbl1 lbl2) | _ => RET false end + | Otbnz sz1 n1 lbl1 => + match c2 with Otbnz sz2 n2 lbl2 => iandb (RET (Int.eq n1 n2)) (iandb (phys_eq sz1 sz2) (phys_eq lbl1 lbl2)) | _ => RET false end + | Otbz sz1 n1 lbl1 => + match c2 with Otbz sz2 n2 lbl2 => iandb (RET (Int.eq n1 n2)) (iandb (phys_eq sz1 sz2) (phys_eq lbl1 lbl2)) | _ => RET false end + | Obtbl tbl1 => + match c2 with Obtbl tbl2 => (phys_eq tbl1 tbl2) | _ => RET false end + (*| Ocbu bt1 l1 =>*) + (*match c2 with Ocbu bt2 l2 => iandb (phys_eq bt1 bt2) (phys_eq l1 l2) | _ => RET false end*) + (*| Ojumptable tbl1 =>*) + (*match c2 with Ojumptable tbl2 => phys_eq tbl1 tbl2 | _ => RET false end*) + (*| Odiv =>*) + (*match c2 with Odiv => RET true | _ => RET false end*) + (*| Odivu =>*) + (*match c2 with Odivu => RET true | _ => RET false end*) + | OIncremPC sz1 => + match c2 with OIncremPC sz2 => RET (Z.eqb sz1 sz2) | _ => RET false end + | OError => + match c2 with OError => RET true | _ => RET false end + end. + +Lemma control_op_eq_correct c1 c2: + WHEN control_op_eq c1 c2 ~> b THEN b = true -> c1 = c2. +Proof. + destruct c1, c2; wlp_simplify; try rewrite Z.eqb_eq in * |-; try congruence; + try apply Int.same_if_eq in H; try congruence. +Qed. +Hint Resolve control_op_eq_correct: wlp. +Opaque control_op_eq_correct. + +Definition store_op_eq (s1 s2: store_op): ?? bool := + match s1 with + | Ostore1 st1 a1 => + match s2 with Ostore1 st2 a2 => iandb (phys_eq st1 st2) (struct_eq a1 a2) | _ => RET false end + | Ostore2 st1 a1 => + match s2 with Ostore2 st2 a2 => iandb (phys_eq st1 st2) (struct_eq a1 a2) | _ => RET false end + | OstoreU st1 a1 => + match s2 with OstoreU st2 a2 => iandb (phys_eq st1 st2) (struct_eq a1 a2) | _ => RET false end + end. + +Lemma store_op_eq_correct s1 s2: + WHEN store_op_eq s1 s2 ~> b THEN b = true -> s1 = s2. +Proof. + destruct s1, s2; wlp_simplify; try congruence. + all: rewrite H0 in H; rewrite H; reflexivity. +Qed. +Hint Resolve store_op_eq_correct: wlp. +Opaque store_op_eq_correct. + +Definition load_op_eq (l1 l2: load_op): ?? bool := + match l1 with + | Oload1 ld1 a1 => + match l2 with Oload1 ld2 a2 => iandb (phys_eq ld1 ld2) (struct_eq a1 a2) | _ => RET false end + | Oload2 ld1 a1 => + match l2 with Oload2 ld2 a2 => iandb (phys_eq ld1 ld2) (struct_eq a1 a2) | _ => RET false end + | OloadU ld1 a1 => + match l2 with OloadU ld2 a2 => iandb (phys_eq ld1 ld2) (struct_eq a1 a2) | _ => RET false end + end. + +Lemma load_op_eq_correct l1 l2: + WHEN load_op_eq l1 l2 ~> b THEN b = true -> l1 = l2. +Proof. + destruct l1, l2; wlp_simplify; try congruence. + all: rewrite H0 in H; rewrite H; reflexivity. +Qed. +Hint Resolve load_op_eq_correct: wlp. +Opaque load_op_eq_correct. + +Definition allocf_op_eq (al1 al2: allocf_op): ?? bool := + match al1 with + | OAllocf_SP sz1 linkofs1 => + match al2 with OAllocf_SP sz2 linkofs2 => iandb (RET (Z.eqb sz1 sz2)) (phys_eq linkofs1 linkofs2) | _ => RET false end + | OAllocf_Mem sz1 linkofs1 => + match al2 with OAllocf_Mem sz2 linkofs2 => iandb (RET (Z.eqb sz1 sz2)) (phys_eq linkofs1 linkofs2) | _ => RET false end + end. + +Lemma allocf_op_eq_correct al1 al2: + WHEN allocf_op_eq al1 al2 ~> b THEN b = true -> al1 = al2. +Proof. + destruct al1, al2; wlp_simplify; try congruence. + all: rewrite H2; rewrite Z.eqb_eq in H; rewrite H; reflexivity. +Qed. +Hint Resolve allocf_op_eq_correct: wlp. +Opaque allocf_op_eq_correct. + +Definition freef_op_eq (fr1 fr2: freef_op): ?? bool := + match fr1 with + | OFreef_SP sz1 linkofs1 => + match fr2 with OFreef_SP sz2 linkofs2 => iandb (RET (Z.eqb sz1 sz2)) (phys_eq linkofs1 linkofs2) | _ => RET false end + | OFreef_Mem sz1 linkofs1 => + match fr2 with OFreef_Mem sz2 linkofs2 => iandb (RET (Z.eqb sz1 sz2)) (phys_eq linkofs1 linkofs2) | _ => RET false end + end. + +Lemma freef_op_eq_correct fr1 fr2: + WHEN freef_op_eq fr1 fr2 ~> b THEN b = true -> fr1 = fr2. +Proof. + destruct fr1, fr2; wlp_simplify; try congruence. + all: rewrite H2; rewrite Z.eqb_eq in H; rewrite H; reflexivity. +Qed. +Hint Resolve freef_op_eq_correct: wlp. +Opaque freef_op_eq_correct. + +Definition op_eq (o1 o2: op): ?? bool := + match o1 with + | Arith i1 => + match o2 with Arith i2 => arith_op_eq i1 i2 | _ => RET false end + | Control i1 => + match o2 with Control i2 => control_op_eq i1 i2 | _ => RET false end + | Load i1 => + match o2 with Load i2 => load_op_eq i1 i2 | _ => RET false end + | Store i1 => + match o2 with Store i2 => store_op_eq i1 i2 | _ => RET false end + | Allocframe i1 => + match o2 with Allocframe i2 => allocf_op_eq i1 i2 | _ => RET false end + | Freeframe i1 => + match o2 with Freeframe i2 => freef_op_eq i1 i2 | _ => RET false end + | Loadsymbol id1 => + match o2 with Loadsymbol id2 => phys_eq id1 id2 | _ => RET false end + | Cvtsw2x => + match o2 with Cvtsw2x => RET true | _ => RET false end + | Cvtuw2x => + match o2 with Cvtuw2x => RET true | _ => RET false end + | Cvtx2w => + match o2 with Cvtx2w => RET true | _ => RET false end + | Constant c1 => + match o2 with Constant c2 => phys_eq c1 c2 | _ => RET false end + (*| _ => RET false*) + end. + +Lemma op_eq_correct o1 o2: + WHEN op_eq o1 o2 ~> b THEN b=true -> o1 = o2. +Proof. + destruct o1, o2; wlp_simplify; congruence. +Qed. + +End IMPPARAM. + +End P. + +Module L <: ISeqLanguage with Module LP:=P. + +Module LP:=P. + +Include MkSeqLanguage P. + +End L. + +Module IST := ImpSimu L ImpPosDict. + +Import L. +Import P. + +(** Compilation from [Asmvliw] to [L] *) + +Local Open Scope positive_scope. + +Definition pmem : R.t := 1. + +Definition ireg_to_pos (ir: ireg) : R.t := + match ir with + | X0 => 8 | X1 => 9 | X2 => 10 | X3 => 11 | X4 => 12 | X5 => 13 | X6 => 14 | X7 => 15 + | X8 => 16 | X9 => 17 | X10 => 18 | X11 => 19 | X12 => 20 | X13 => 21 | X14 => 22 | X15 => 23 + | X16 => 24 | X17 => 25 | X18 => 26 | X19 => 27 | X20 => 28 | X21 => 29 | X22 => 30 | X23 => 31 + | X24 => 32 | X25 => 33 | X26 => 34 | X27 => 35 | X28 => 36 | X29 => 37 | X30 => 38 + end +. + +Definition freg_to_pos (fr: freg) : R.t := + match fr with + | D0 => 39 | D1 => 40 | D2 => 41 | D3 => 42 | D4 => 43 | D5 => 44 | D6 => 45 | D7 => 46 + | D8 => 47 | D9 => 48 | D10 => 49 | D11 => 50 | D12 => 51 | D13 => 52 | D14 => 53 | D15 => 54 + | D16 => 55 | D17 => 56 | D18 => 57 | D19 => 58 | D20 => 59 | D21 => 60 | D22 => 61 | D23 => 62 + | D24 => 63 | D25 => 64 | D26 => 65 | D27 => 66 | D28 => 67 | D29 => 68 | D30 => 69 | D31 => 70 + end +. + +Lemma ireg_to_pos_discr: forall r r', r <> r' -> ireg_to_pos r <> ireg_to_pos r'. +Proof. + destruct r; destruct r'; try contradiction; discriminate. +Qed. + +Lemma freg_to_pos_discr: forall r r', r <> r' -> freg_to_pos r <> freg_to_pos r'. +Proof. + destruct r; destruct r'; try contradiction; discriminate. +Qed. + +(*Lemma creg_to_pos_discr: forall r r', r <> r' -> freg_to_pos r <> freg_to_pos r'.*) +(*Proof.*) + (*destruct r; destruct r'; try contradiction; discriminate.*) +(*Qed.*) + +Definition ppos (r: preg) : R.t := + match r with + | CR c => match c with + | CN => 2 + | CZ => 3 + | CC => 4 + | CV => 5 + end + | PC => 6 + | DR d => match d with + | IR i => match i with + | XSP => 7 + | RR1 ir => ireg_to_pos ir + end + | FR fr => freg_to_pos fr + end + end +. + +(*Definition ppos_ireg0 (r: ireg0) : R.t :=*) + (*match r with*) + (*| RR0 p => ppos p*) + (*| XZR => 71*) + (*end*) +(*.*) + +Notation "# r" := (ppos r) (at level 100, right associativity). + +Lemma not_eq_add: + forall k n n', n <> n' -> k + n <> k + n'. +Proof. + intros k n n' H1 H2. apply H1; clear H1. eapply Pos.add_reg_l; eauto. +Qed. + +Lemma ppos_equal: forall r r', r = r' <-> ppos r = ppos r'. +Proof. + destruct r as [dr|cr|]; destruct r' as [dr'|cr'|]; + try destruct dr as [ir|fr]; try destruct dr' as [ir'|fr']; + try destruct ir as [irr|]; try destruct ir' as [irr'|]. + all: split; intros; try rewrite H; try discriminate; try contradiction; simpl; eauto; + try destruct irr; try destruct irr'; + try destruct fr; try destruct fr'; + try destruct cr; try destruct cr'; + simpl; try discriminate; try reflexivity. +Qed. + +Lemma ppos_discr: forall r r', r <> r' -> ppos r <> ppos r'. +Proof. + destruct r as [dr|cr|]; destruct r' as [dr'|cr'|]; + try destruct dr as [ir|fr]; try destruct dr' as [ir'|fr']; + try destruct ir as [irr|]; try destruct ir' as [irr'|]. + all: try discriminate; try contradiction. + 1: intros; unfold ppos; apply ireg_to_pos_discr; congruence. + 1,2,11,18: intros; unfold ppos; try destruct irr; try destruct irr'; discriminate. + 1,3: intros; unfold ppos; try destruct irr; try destruct fr; try destruct irr'; try destruct fr'; discriminate. + 1,2,7,13: intros; unfold ppos; try destruct fr; try destruct fr'; discriminate. + 1: intros; unfold ppos; apply freg_to_pos_discr; congruence. + 1,4: intros; unfold ppos; try destruct irr; try destruct irr'; try destruct cr; try destruct cr'; discriminate. + 2,4: intros; unfold ppos; try destruct fr; try destruct fr'; try destruct cr; try destruct cr'; discriminate. + 1,2,4,5: intros; unfold ppos; try destruct cr; try destruct cr'; discriminate. + 1: intros; unfold ppos; try destruct cr; try destruct cr'; congruence. +Qed. + +Lemma ppos_pmem_discr: forall r, pmem <> ppos r. +Proof. + intros. destruct r as [dr|cr|]. + - destruct dr as [ir|fr]; try destruct ir as [irr|]; try destruct irr; try destruct fr; + unfold ppos; unfold pmem; discriminate. + - unfold ppos; unfold pmem; destruct cr; discriminate. + - unfold ppos; unfold pmem; discriminate. +Qed. + +(** Inversion functions, used for debug traces *) + +Definition pos_to_ireg (p: R.t) : option ireg := + match p with + | 8 => Some (X0) | 9 => Some (X1) | 10 => Some (X2) | 11 => Some (X3) | 12 => Some (X4) | 13 => Some (X5) | 14 => Some (X6) | 15 => Some (X7) + | 16 => Some (X8) | 17 => Some (X9) | 18 => Some (X10) | 19 => Some (X11) | 20 => Some (X12) | 21 => Some (X13) | 22 => Some (X14) | 23 => Some (X15) + | 24 => Some (X16) | 25 => Some (X17) | 26 => Some (X18) | 27 => Some (X19) | 28 => Some (X20) | 29 => Some (X21) | 30 => Some (X22) | 31 => Some (X23) + | 32 => Some (X24) | 33 => Some (X25) | 34 => Some (X26) | 35 => Some (X27) | 36 => Some (X28) | 37 => Some (X29) | 38 => Some (X30) | _ => None + end. + +Definition pos_to_freg (p: R.t) : option freg := + match p with + | 39 => Some(D0) | 40 => Some(D1) | 41 => Some(D2) | 42 => Some(D3) | 43 => Some(D4) | 44 => Some(D5) | 45 => Some(D6) | 46 => Some(D7) + | 47 => Some(D8) | 48 => Some(D9) | 49 => Some(D10) | 50 => Some(D11) | 51 => Some(D12) | 52 => Some(D13) | 53 => Some(D14) | 54 => Some(D15) + | 55 => Some(D16) | 56 => Some(D17) | 57 => Some(D18) | 58 => Some(D19) | 59 => Some(D20) | 60 => Some(D21) | 61 => Some(D22) | 62 => Some(D23) + | 63 => Some(D24) | 64 => Some(D25) | 65 => Some(D26) | 66 => Some(D27) | 67 => Some(D28) | 68 => Some(D29) | 69 => Some(D30) | 70 => Some(D31) | _ => None + end. + +Definition inv_ppos (p: R.t) : option preg := + match p with + | 1 => None + | 2 => Some (CR CN) + | 3 => Some (CR CZ) + | 4 => Some (CR CC) + | 5 => Some (CR CV) + | 6 => Some (PC) + | 7 => Some (DR (IR XSP)) + | n => match pos_to_ireg n with + | None => match pos_to_freg n with + | None => None + | Some fr => Some (DR (FR fr)) + end + | Some ir => Some (DR (IR ir)) + end + end. + +Notation "a @ b" := (Econs a b) (at level 102, right associativity). + +(** Translations of instructions *) + +Definition get_testcond_rlocs (c: testcond) := + match c with + | TCeq => (PReg(#CZ) @ Enil) + | TCne => (PReg(#CZ) @ Enil) + | TChs => (PReg(#CC) @ Enil) + | TClo => (PReg(#CC) @ Enil) + | TCmi => (PReg(#CN) @ Enil) + | TCpl => (PReg(#CN) @ Enil) + | TChi => (PReg(#CZ) @ PReg(#CC) @ Enil) + | TCls => (PReg(#CZ) @ PReg(#CC) @ Enil) + | TCge => (PReg(#CN) @ PReg(#CV) @ Enil) + | TClt => (PReg(#CN) @ PReg(#CV) @ Enil) + | TCgt => (PReg(#CN) @ PReg(#CZ) @ PReg(#CV) @ Enil) + | TCle => (PReg(#CN) @ PReg(#CZ) @ PReg(#CV) @ Enil) + end. + +Definition trans_control (ctl: control) : inst := + match ctl with + | Pb lbl => [(#PC, Op (Control (Ob lbl)) (PReg(#PC) @ Enil))] + | Pbc c lbl => + let lr := get_testcond_rlocs c in + [(#PC, Op (Control (Obc c lbl)) (PReg(#PC) @ lr))] + | Pbl id sg => [(#RA, PReg(#PC)); + (#PC, Op (Control (Obl id)) Enil)] + | Pbs id sg => [(#PC, Op (Control (Obs id)) Enil)] + | Pblr r sg => [(#RA, PReg(#PC)); + (#PC, Old (PReg(#r)))] + | Pbr r sg => [(#PC, PReg(#r))] + | Pret r => [(#PC, PReg(#r))] + | Pcbnz sz r lbl => [(#PC, Op (Control (Ocbnz sz lbl)) (PReg(#r) @ PReg(#PC) @ Enil))] + | Pcbz sz r lbl => [(#PC, Op (Control (Ocbz sz lbl)) (PReg(#r) @ PReg(#PC) @ Enil))] + | Ptbnz sz r n lbl => [(#PC, Op (Control (Otbnz sz n lbl)) (PReg(#r) @ PReg(#PC) @ Enil))] + | Ptbz sz r n lbl => [(#PC, Op (Control (Otbz sz n lbl)) (PReg(#r) @ PReg(#PC) @ Enil))] + | Pbtbl r tbl => [(#X16, Op (Constant Vundef) Enil); + (#PC, Op (Control (Obtbl tbl)) (PReg(#r) @ PReg(#PC) @ Enil)); + (#X16, Op (Constant Vundef) Enil); + (#X17, Op (Constant Vundef) Enil)] + | Pbuiltin ef args res => [] + end. + +Definition trans_exit (ex: option control) : L.inst := + match ex with + | None => [] + | Some ctl => trans_control ctl + end +. + +Definition trans_arith (ai: ar_instruction) : inst := + match ai with + | PArithP n rd => [(#rd, Op(Arith (OArithP n)) Enil)] + | PArithPP n rd r1 => [(#rd, Op(Arith (OArithPP n)) (PReg(#r1) @ Enil))] + | PArithPPP n rd r1 r2 => [(#rd, Op(Arith (OArithPPP n)) (PReg(#r1) @ PReg(#r2) @ Enil))] + | PArithRR0R n rd r1 r2 => + let lr := match r1 with + | RR0 r1' => Op(Arith (OArithRR0R n)) (PReg(#r1') @ PReg(#r2) @ Enil) + | XZR => let vz := if arith_rr0r_isize n then Vint Int.zero else Vlong Int64.zero in + Op(Arith (OArithRR0R_XZR n vz)) (PReg(#r2) @ Enil) + end in + [(#rd, lr)] + | PArithRR0 n rd r1 => + let lr := match r1 with + | RR0 r1' => Op(Arith (OArithRR0 n)) (PReg(#r1') @ Enil) + | XZR => let vz := if arith_rr0_isize n then Vint Int.zero else Vlong Int64.zero in + Op(Arith (OArithRR0_XZR n vz)) (Enil) + end in + [(#rd, lr)] + | PArithARRRR0 n rd r1 r2 r3 => + let lr := match r3 with + | RR0 r3' => Op(Arith (OArithARRRR0 n)) (PReg(#r1) @ PReg (#r2) @ PReg(#r3') @ Enil) + | XZR => let vz := if arith_arrrr0_isize n then Vint Int.zero else Vlong Int64.zero in + Op(Arith (OArithARRRR0_XZR n vz)) (PReg(#r1) @ PReg(#r2) @ Enil) + end in + [(#rd, lr)] + | PArithComparisonPP n r1 r2 => + [(#CN, Op(Arith (OArithComparisonPP_CN n)) (PReg(#r1) @ PReg(#r2) @ Enil)); + (#CZ, Op(Arith (OArithComparisonPP_CZ n)) (PReg(#r1) @ PReg(#r2) @ Enil)); + (#CC, Op(Arith (OArithComparisonPP_CC n)) (PReg(#r1) @ PReg(#r2) @ Enil)); + (#CV, Op(Arith (OArithComparisonPP_CV n)) (PReg(#r1) @ PReg(#r2) @ Enil))] + | PArithComparisonR0R n r1 r2 => + let is := arith_comparison_r0r_isize n in + match r1 with + | RR0 r1' => [(#CN, Op(Arith (OArithComparisonR0R_CN n is)) (PReg(#r1') @ PReg(#r2) @ Enil)); + (#CZ, Op(Arith (OArithComparisonR0R_CZ n is)) (PReg(#r1') @ PReg(#r2) @ Enil)); + (#CC, Op(Arith (OArithComparisonR0R_CC n is)) (PReg(#r1') @ PReg(#r2) @ Enil)); + (#CV, Op(Arith (OArithComparisonR0R_CV n is)) (PReg(#r1') @ PReg(#r2) @ Enil))] + | XZR => let vz := if is then Vint Int.zero else Vlong Int64.zero in + [(#CN, Op(Arith (OArithComparisonR0R_CN_XZR n is vz)) (PReg(#r2) @ Enil)); + (#CZ, Op(Arith (OArithComparisonR0R_CZ_XZR n is vz)) (PReg(#r2) @ Enil)); + (#CC, Op(Arith (OArithComparisonR0R_CC_XZR n is vz)) (PReg(#r2) @ Enil)); + (#CV, Op(Arith (OArithComparisonR0R_CV_XZR n is vz)) (PReg(#r2) @ Enil))] + end + | PArithComparisonP n r1 => + [(#CN, Op(Arith (OArithComparisonP_CN n)) (PReg(#r1) @ Enil)); + (#CZ, Op(Arith (OArithComparisonP_CZ n)) (PReg(#r1) @ Enil)); + (#CC, Op(Arith (OArithComparisonP_CC n)) (PReg(#r1) @ Enil)); + (#CV, Op(Arith (OArithComparisonP_CV n)) (PReg(#r1) @ Enil))] + | Pcset rd c => + let lr := get_testcond_rlocs c in + [(#rd, Op(Arith (Ocset c)) lr)] + | Pfmovi fsz rd r1 => + let lr := match r1 with + | RR0 r1' => Op(Arith (Ofmovi fsz)) (PReg(#r1') @ Enil) + | XZR => Op(Arith (Ofmovi_XZR fsz)) Enil + end in + [(#rd, lr)] + | Pcsel rd r1 r2 c => + let lr := get_testcond_rlocs c in + [(#rd, Op(Arith (Ocsel c)) (PReg(#r1) @ PReg (#r2) @ lr))] + | Pfnmul fsz rd r1 r2 => [(#rd, Op(Arith (Ofnmul fsz)) (PReg(#r1) @ PReg(#r2) @ Enil))] + end. + +Definition eval_addressing_rlocs_st (st: store_rs_a) (rs: dreg) (a: addressing) := + match a with + | ADimm base n => Op (Store (Ostore1 st a)) (PReg (#rs) @ PReg (#base) @ PReg (pmem) @ Enil) + | ADreg base r => Op (Store (Ostore2 st a)) (PReg (#rs) @ PReg (#base) @ PReg(#r) @ PReg (pmem) @ Enil) + | ADlsl base r n => Op (Store (Ostore2 st a)) (PReg (#rs) @ PReg (#base) @ PReg(#r) @ PReg (pmem) @ Enil) + | ADsxt base r n => Op (Store (Ostore2 st a)) (PReg (#rs) @ PReg (#base) @ PReg(#r) @ PReg (pmem) @ Enil) + | ADuxt base r n => Op (Store (Ostore2 st a)) (PReg (#rs) @ PReg (#base) @ PReg(#r) @ PReg (pmem) @ Enil) + | ADadr base id ofs => Op (Store (Ostore1 st a)) (PReg (#rs) @ PReg (#base) @ PReg (pmem) @ Enil) + | ADpostincr base n => Op (Store (OstoreU st a)) (PReg (#rs) @ PReg (pmem) @ Enil) (* not modeled yet *) + end. + +Definition eval_addressing_rlocs_ld (ld: load_rd_a) (a: addressing) := + match a with + | ADimm base n => Op (Load (Oload1 ld a)) (PReg (#base) @ PReg (pmem) @ Enil) + | ADreg base r => Op (Load (Oload2 ld a)) (PReg (#base) @ PReg(#r) @ PReg (pmem) @ Enil) + | ADlsl base r n => Op (Load (Oload2 ld a)) (PReg (#base) @ PReg(#r) @ PReg (pmem) @ Enil) + | ADsxt base r n => Op (Load (Oload2 ld a)) (PReg (#base) @ PReg(#r) @ PReg (pmem) @ Enil) + | ADuxt base r n => Op (Load (Oload2 ld a)) (PReg (#base) @ PReg(#r) @ PReg (pmem) @ Enil) + | ADadr base id ofs => Op (Load (Oload1 ld a)) (PReg (#base) @ PReg (pmem) @ Enil) + | ADpostincr base n => Op (Load (OloadU ld a)) (PReg (pmem) @ Enil) (* not modeled yet *) + end. + +Definition trans_basic (b: basic) : inst := + match b with + | PArith ai => trans_arith ai + | PLoad ld r a => + let lr := eval_addressing_rlocs_ld ld a in [(#r, lr)] + | PStore st r a => + let lr := eval_addressing_rlocs_st st r a in [(pmem, lr)] + | Pallocframe sz linkofs => + [(#X29, PReg(#SP)); + (#SP, Op (Allocframe (OAllocf_SP sz linkofs)) (PReg (#SP) @ PReg pmem @ Enil)); + (#X16, Op (Constant Vundef) Enil); + (pmem, Op (Allocframe (OAllocf_Mem sz linkofs)) (Old(PReg(#SP)) @ PReg pmem @ Enil))] + | Pfreeframe sz linkofs => + [(pmem, Op (Freeframe (OFreef_Mem sz linkofs)) (PReg (#SP) @ PReg pmem @ Enil)); + (#SP, Op (Freeframe (OFreef_SP sz linkofs)) (PReg (#SP) @ Old (PReg pmem) @ Enil)); + (#X16, Op (Constant Vundef) Enil)] + | Ploadsymbol rd id => [(#rd, Op (Loadsymbol id) Enil)] + | Pcvtsw2x rd r1 => [(#rd, Op (Cvtsw2x) (PReg (#r1) @ Enil))] + | Pcvtuw2x rd r1 => [(#rd, Op (Cvtuw2x) (PReg (#r1) @ Enil))] + | Pcvtx2w rd => [(#rd, Op (Cvtx2w) (PReg (#rd) @ Enil))] + end. + +Fixpoint trans_body (b: list basic) : list L.inst := + match b with + | nil => nil + | b :: lb => (trans_basic b) :: (trans_body lb) + end. + +Definition trans_pcincr (sz: Z) (k: L.inst) := (#PC, Op (Control (OIncremPC sz)) (PReg(#PC) @ Enil)) :: k. + +Definition trans_block (b: Asmblock.bblock) : L.bblock := + trans_body (body b) ++ (trans_pcincr (size b) (trans_exit (exit b)) :: nil). + +(*Theorem trans_block_noheader_inv: forall bb, trans_block (no_header bb) = trans_block bb.*) +(*Proof.*) + (*intros. destruct bb as [hd bdy ex COR]; unfold no_header; simpl. unfold trans_block. simpl. reflexivity.*) +(*Qed.*) + +(*Theorem trans_block_header_inv: forall bb hd, trans_block (stick_header hd bb) = trans_block bb.*) +(*Proof.*) + (*intros. destruct bb as [hdr bdy ex COR]; unfold no_header; simpl. unfold trans_block. simpl. reflexivity.*) +(*Qed.*) + +(** Lemmas on the translation *) + +Definition state := L.mem. +Definition exec := L.run. + +Definition match_states (s: Asm.state) (s': state) := + let (rs, m) := s in + s' pmem = Memstate m + /\ forall r, s' (#r) = Val (rs r). + +Definition match_outcome (o:outcome) (s: option state) := + match o with + | Some n => exists s', s=Some s' /\ match_states n s' + | None => s=None + end. + +Notation "a <[ b <- c ]>" := (assign a b c) (at level 102, right associativity). + +Definition trans_state (s: Asm.state) : state := + let (rs, m) := s in + fun x => if (Pos.eq_dec x pmem) then Memstate m + else match (inv_ppos x) with + | Some r => Val (rs r) + | None => Val Vundef + end. + +Lemma not_eq_IR: + forall r r', r <> r' -> IR r <> IR r'. +Proof. + intros. congruence. +Qed. + +(*Lemma inv_ppos_from_ireg: forall (ir: ireg),*) + (*exists x,*) + (*inv_ppos (x) = Some (DR (IR ir)).*) +(*Proof.*) + (*intros. unfold inv_ppos.*) + (*eexists (ireg_to_pos ir). destruct ir; simpl; reflexivity.*) +(*Qed.*) + +Lemma ireg_pos_ppos: forall (sr: state) r, + sr (ireg_to_pos r) = sr (# r). +Proof. + intros. simpl. reflexivity. +Qed. + +Lemma freg_pos_ppos: forall (sr: state) r, + sr (freg_to_pos r) = sr (# r). +Proof. + intros. simpl. reflexivity. +Qed. + +Lemma ireg_not_pc: forall r, + (#PC) <> ireg_to_pos r. +Proof. + intros; destruct r; discriminate. +Qed. + +Lemma ireg_not_pmem: forall r, + ireg_to_pos r <> pmem. +Proof. + intros; destruct r; discriminate. +Qed. + +Lemma ireg_not_CN: forall r, + 2 <> ireg_to_pos r. +Proof. + intros; destruct r; discriminate. +Qed. + +Lemma ireg_not_CZ: forall r, + 3 <> ireg_to_pos r. +Proof. + intros; destruct r; discriminate. +Qed. + +Lemma ireg_not_CC: forall r, + 4 <> ireg_to_pos r. +Proof. + intros; destruct r; discriminate. +Qed. + +Lemma ireg_not_CV: forall r, + 5 <> ireg_to_pos r. +Proof. + intros; destruct r; discriminate. +Qed. + +Lemma freg_not_pmem: forall r, + freg_to_pos r <> pmem. +Proof. + intros; destruct r; discriminate. +Qed. + +Lemma freg_not_CN: forall r, + 2 <> freg_to_pos r. +Proof. + intros; destruct r; discriminate. +Qed. + +Lemma freg_not_CZ: forall r, + 3 <> freg_to_pos r. +Proof. + intros; destruct r; discriminate. +Qed. + +Lemma freg_not_CC: forall r, + 4 <> freg_to_pos r. +Proof. + intros; destruct r; discriminate. +Qed. + +Lemma freg_not_CV: forall r, + 5 <> freg_to_pos r. +Proof. + intros; destruct r; discriminate. +Qed. + +Lemma sr_ireg_update_both: forall sr rsr r1 rr v + (HEQV: forall r : preg, sr (# r) = Val (rsr r)), + (sr <[ ireg_to_pos r1 <- Val (v) ]>) (#rr) = + Val (rsr # r1 <- v rr). +Proof. + intros. unfold assign. + destruct (PregEq.eq r1 rr); subst. + - rewrite Pregmap.gss. simpl. destruct r1; simpl; reflexivity. + - rewrite Pregmap.gso; eauto. + destruct rr; try congruence. + + destruct d as [i|f]; try destruct i as [ir|]; try destruct f; try destruct ir; try rewrite HEQV; destruct r1; simpl; try congruence. + + destruct c; destruct r1; simpl; try rewrite <- HEQV; unfold ppos; try congruence. + + destruct r1; simpl; try rewrite <- HEQV; unfold ppos; try congruence. +Qed. + +Lemma sr_freg_update_both: forall sr rsr r1 rr v + (HEQV: forall r : preg, sr (# r) = Val (rsr r)), + (sr <[ freg_to_pos r1 <- Val (v) ]>) (#rr) = + Val (rsr # r1 <- v rr). +Proof. + intros. unfold assign. + destruct (PregEq.eq r1 rr); subst. + - rewrite Pregmap.gss. simpl. destruct r1; simpl; reflexivity. + - rewrite Pregmap.gso; eauto. + destruct rr; try congruence. + + destruct d as [i|f]; try destruct i as [ir|]; try destruct f; try destruct ir; try rewrite HEQV; destruct r1; simpl; try congruence. + + destruct c; destruct r1; simpl; try rewrite <- HEQV; unfold ppos; try congruence. + + destruct r1; simpl; try rewrite <- HEQV; unfold ppos; try congruence. +Qed. + +Lemma sr_xsp_update_both: forall sr rsr rr v + (HEQV: forall r : preg, sr (# r) = Val (rsr r)), + (sr <[ #XSP <- Val (v) ]>) (#rr) = + Val (rsr # XSP <- v rr). +Proof. + intros. unfold assign. + destruct (PregEq.eq XSP rr); subst. + - rewrite Pregmap.gss. simpl. reflexivity. + - rewrite Pregmap.gso; eauto. + destruct rr; try congruence. + + destruct d as [i|f]; try destruct i as [ir|]; try destruct f; try destruct ir; try rewrite HEQV; simpl; try congruence. + + destruct c; simpl; try rewrite <- HEQV; unfold ppos; try congruence. + + simpl; try rewrite <- HEQV; unfold ppos; try congruence. +Qed. + +Lemma sr_pc_update_both: forall sr rsr rr v + (HEQV: forall r : preg, sr (# r) = Val (rsr r)), + (sr <[ #PC <- Val (v) ]>) (#rr) = + Val (rsr # PC <- v rr). +Proof. + intros. unfold assign. + destruct (PregEq.eq PC rr); subst. + - rewrite Pregmap.gss. simpl. reflexivity. + - rewrite Pregmap.gso; eauto. + destruct rr; try congruence. + + destruct d as [i|f]; try destruct i as [ir|]; try destruct f; try destruct ir; try rewrite HEQV; simpl; try congruence. + + destruct c; simpl; try rewrite <- HEQV; unfold ppos; try congruence. +Qed. + +Lemma sr_gss: forall sr pos v, + (sr <[ pos <- v ]>) pos = v. +Proof. + intros. unfold assign. + destruct (R.eq_dec pos pos) eqn:REQ; try reflexivity; try congruence. +Qed. + +Lemma sr_update_overwrite: forall sr pos v1 v2, + (sr <[ pos <- v1 ]>) <[ pos <- v2 ]> = (sr <[ pos <- v2 ]>). +Proof. + intros. + unfold assign. apply functional_extensionality; intros x. + destruct (R.eq_dec pos x); reflexivity. +Qed. + +(*Ltac Simplif :=*) + (*[>((rewrite nextblock_inv by eauto with asmgen)<]*) + (*[>|| (rewrite nextblock_inv1 by eauto with asmgen)<]*) + (*((rewrite Pregmap.gss)*) + (*[>|| (rewrite nextblock_pc)<]*) + (*|| (rewrite Pregmap.gso by eauto with asmgen)*) + (*|| (rewrite assign_diff by (auto; try discriminate; try (apply ppos_discr; try discriminate; congruence); try (apply ppos_pmem_discr); *) + (*try (apply not_eq_sym; apply ppos_discr; try discriminate; congruence); try (apply not_eq_sym; apply ppos_pmem_discr); auto))*) + (*|| (rewrite assign_eq)*) + (*); auto with asmgen.*) + +(*Ltac Simpl := repeat Simplif.*) + +Ltac sr_val_rwrt := + repeat match goal with + | [H: forall r: preg, ?sr (# r) = Val (?rsr r) |- _ ] + => rewrite H + end. + +Ltac sr_memstate_rwrt := + repeat match goal with + | [H: ?sr pmem = Memstate ?mr |- _ ] + => rewrite <- H + end. + +Ltac replace_ppos := + try erewrite !ireg_pos_ppos; + try erewrite !freg_pos_ppos. + +Ltac DI0N0 ir0 := destruct ir0; subst; simpl. + +Ltac DIRN1 ir := destruct ir as [irrDIRN1|]; subst; try destruct irrDIRN1; simpl. + +Ltac DDRM dr := + destruct dr as [irsDDRF|frDDRF]; + [destruct irsDDRF as [irsDDRF|] + | idtac ]. + +Ltac DDRF dr := + destruct dr as [irsDDRF|frDDRF]; + [destruct irsDDRF as [irsDDRF|]; [destruct irsDDRF|] + | destruct frDDRF]. + +Ltac DPRF pr := + destruct pr as [drDPRF|crDPRF|]; + [destruct drDPRF as [irDPRF|frDPRF]; [destruct irDPRF as [irrDPRF|]; [destruct irrDPRF|] + | destruct frDPRF] + | destruct crDPRF|]. + +Ltac DPRM pr := + destruct pr as [drDPRF|crDPRF|]; + [destruct drDPRF as [irDPRF|frDPRF]; [destruct irDPRF |] + | destruct crDPRF|]. + +Ltac DPRI pr := + destruct pr as [drDPRI|crDPRI|]; + [destruct drDPRI as [irDPRI|frDPRI]; [destruct irDPRI as [irrDPRI|]; [destruct irrDPRI|]|] + | idtac + | idtac ]. + +Ltac discriminate_ppos := + try apply ireg_not_pmem; + try apply ireg_not_pc; + try apply freg_not_pmem; + try apply ireg_not_CN; + try apply ireg_not_CZ; + try apply ireg_not_CC; + try apply ireg_not_CV; + try apply freg_not_CN; + try apply freg_not_CZ; + try apply freg_not_CC; + try apply freg_not_CV; + try(simpl; discriminate). + +Ltac replace_pc := try replace (6) with (#PC) by eauto. + +Ltac replace_regs_pos sr := + try replace (sr 7) with (sr (ppos XSP)) by eauto; + try replace (sr 6) with (sr (ppos PC)) by eauto; + try replace (sr 2) with (sr (ppos CN)) by eauto; + try replace (sr 3) with (sr (ppos CZ)) by eauto; + try replace (sr 4) with (sr (ppos CC)) by eauto; + try replace (sr 5) with (sr (ppos CV)) by eauto. + +Ltac Simpl_exists sr := + replace_ppos; + replace_regs_pos sr; + try sr_val_rwrt; + try (eexists; split; [| split]); eauto; + try (sr_memstate_rwrt; rewrite assign_diff; + try reflexivity; + discriminate_ppos + ). + +Ltac Simpl_rep sr := + replace_ppos; + replace_regs_pos sr; + try sr_val_rwrt; + try (sr_memstate_rwrt; rewrite assign_diff; + try reflexivity; + discriminate_ppos + ). + +Ltac Simpl_update := + try eapply sr_ireg_update_both; eauto; + try eapply sr_freg_update_both; eauto; + try eapply sr_xsp_update_both; eauto; + try eapply sr_pc_update_both; eauto. + +Ltac Simpl sr := Simpl_exists sr; intros rr; try rewrite sr_update_overwrite; replace_regs_pos sr; DPRM rr; Simpl_update. + +Ltac destruct_res_flag rsr := try (rewrite Pregmap.gso; discriminate_ppos); destruct (rsr _); simpl; try reflexivity. + +Ltac discriminate_preg_flags := rewrite !assign_diff; try rewrite !Pregmap.gso; discriminate_ppos; sr_val_rwrt; reflexivity. + +Ltac validate_crbit_flags c := + destruct c; + [ + do 3 (rewrite assign_diff; discriminate_ppos); + do 3 (rewrite Pregmap.gso; try discriminate); + rewrite sr_gss; rewrite Pregmap.gss; reflexivity | + do 2 (rewrite assign_diff; discriminate_ppos); + do 2 (rewrite Pregmap.gso; try discriminate); + rewrite sr_gss; rewrite Pregmap.gss; reflexivity | + do 1 (rewrite assign_diff; discriminate_ppos); + do 1 (rewrite Pregmap.gso; try discriminate); + rewrite sr_gss; rewrite Pregmap.gss; reflexivity | + rewrite sr_gss; rewrite Pregmap.gss; reflexivity + ]. + + +Lemma reg_update_overwrite: forall rsr sr r rd v1 v2 + (HEQV: forall r : preg, sr (# r) = Val (rsr r)), + ((sr <[ # rd <- Val (v1) ]>) <[ # rd <- Val (v2) ]>) (# r) = + Val ((rsr # rd <- v1) # rd <- v2 r). +Proof. + intros. + unfold Pregmap.set; destruct (PregEq.eq r rd). + - rewrite e; apply sr_gss; reflexivity. + - rewrite sr_update_overwrite. rewrite assign_diff; eauto. + unfold not; intros. apply ppos_equal in H. congruence. +Qed. + +Lemma compare_single_res_aux: forall sr mr rsr rr + (HMEM: sr pmem = Memstate mr) + (HEQV: forall r : preg, sr (# r) = Val (rsr r)), + ((((sr <[ 2 <- Val (_CN (v_compare_single Vundef Vundef)) ]>) <[ 3 <- + Val (_CZ (v_compare_single Vundef Vundef)) ]>) <[ 4 <- + Val (_CC (v_compare_single Vundef Vundef)) ]>) <[ 5 <- + Val (_CV (v_compare_single Vundef Vundef)) ]>) (# rr) = +Val + ((compare_single rsr Vundef Vundef) rr). +Proof. + intros. unfold v_compare_single, compare_single. + (destruct rr; + [ DDRF d; discriminate_preg_flags | + validate_crbit_flags c | + discriminate_preg_flags ]). +Qed. + +Lemma compare_single_res: forall sr mr rsr rr v1 v2 + (HMEM: sr pmem = Memstate mr) + (HEQV: forall r : preg, sr (# r) = Val (rsr r)), + ((((sr <[ 2 <- Val (_CN (v_compare_single v1 v2)) ]>) <[ 3 <- + Val (_CZ (v_compare_single v1 v2)) ]>) <[ 4 <- + Val (_CC (v_compare_single v1 v2)) ]>) <[ 5 <- + Val (_CV (v_compare_single v1 v2)) ]>) (# rr) = +Val + ((compare_single rsr v1 v2) rr). +Proof. + intros. + destruct v1; destruct v2; + try eapply compare_single_res_aux; eauto. + unfold v_compare_single, compare_single. + (destruct rr; + [ DDRF d; discriminate_preg_flags | + validate_crbit_flags c | + discriminate_preg_flags ]). +Qed. + +Lemma compare_float_res_aux: forall sr mr rsr rr + (HMEM: sr pmem = Memstate mr) + (HEQV: forall r : preg, sr (# r) = Val (rsr r)), + ((((sr <[ 2 <- Val (_CN (v_compare_float Vundef Vundef)) ]>) <[ 3 <- + Val (_CZ (v_compare_float Vundef Vundef)) ]>) <[ 4 <- + Val (_CC (v_compare_float Vundef Vundef)) ]>) <[ 5 <- + Val (_CV (v_compare_float Vundef Vundef)) ]>) (# rr) = +Val + ((compare_float rsr Vundef Vundef) rr). +Proof. + intros. unfold v_compare_float, compare_float. + (destruct rr; + [ DDRF d; discriminate_preg_flags | + validate_crbit_flags c | + discriminate_preg_flags ]). +Qed. + +Lemma compare_float_res: forall sr mr rsr rr v1 v2 + (HMEM: sr pmem = Memstate mr) + (HEQV: forall r : preg, sr (# r) = Val (rsr r)), + ((((sr <[ 2 <- Val (_CN (v_compare_float v1 v2)) ]>) <[ 3 <- + Val (_CZ (v_compare_float v1 v2)) ]>) <[ 4 <- + Val (_CC (v_compare_float v1 v2)) ]>) <[ 5 <- + Val (_CV (v_compare_float v1 v2)) ]>) (# rr) = +Val + ((compare_float rsr v1 v2) rr). +Proof. + intros. + destruct v1; destruct v2; + try eapply compare_float_res_aux; eauto. + unfold v_compare_float, compare_float. + (destruct rr; + [ DDRF d; discriminate_preg_flags | + validate_crbit_flags c | + discriminate_preg_flags ]). +Qed. + +Lemma compare_long_res_aux: forall sr mr rsr rr + (HMEM: sr pmem = Memstate mr) + (HEQV: forall r : preg, sr (# r) = Val (rsr r)), + ((((sr <[ 2 <- Val (_CN (v_compare_long Vundef Vundef)) ]>) <[ 3 <- + Val (_CZ (v_compare_long Vundef Vundef)) ]>) <[ 4 <- + Val (_CC (v_compare_long Vundef Vundef)) ]>) <[ 5 <- + Val (_CV (v_compare_long Vundef Vundef)) ]>) (# rr) = +Val + ((compare_long rsr Vundef Vundef) rr). +Proof. + intros. unfold v_compare_long, compare_long. + (destruct rr; + [ DDRF d; discriminate_preg_flags | + validate_crbit_flags c | + discriminate_preg_flags ]). +Qed. + +Lemma compare_long_res: forall sr mr rsr rr v1 v2 + (HMEM: sr pmem = Memstate mr) + (HEQV: forall r : preg, sr (# r) = Val (rsr r)), + ((((sr <[ 2 <- Val (_CN (v_compare_long v1 v2)) ]>) <[ 3 <- + Val (_CZ (v_compare_long v1 v2)) ]>) <[ 4 <- + Val (_CC (v_compare_long v1 v2)) ]>) <[ 5 <- + Val (_CV (v_compare_long v1 v2)) ]>) (# rr) = +Val + ((compare_long rsr v1 v2) rr). +Proof. + intros. + destruct v1; destruct v2; + try eapply compare_long_res_aux; eauto; + unfold v_compare_long, compare_long; + (destruct rr; + [ DDRF d; discriminate_preg_flags | + validate_crbit_flags c | + discriminate_preg_flags ]). +Qed. + +Lemma compare_int_res_aux: forall sr mr rsr rr + (HMEM: sr pmem = Memstate mr) + (HEQV: forall r : preg, sr (# r) = Val (rsr r)), + ((((sr <[ 2 <- Val (_CN (v_compare_int Vundef Vundef)) ]>) <[ 3 <- + Val (_CZ (v_compare_int Vundef Vundef)) ]>) <[ 4 <- + Val (_CC (v_compare_int Vundef Vundef)) ]>) <[ 5 <- + Val (_CV (v_compare_int Vundef Vundef)) ]>) (# rr) = +Val + ((compare_int rsr Vundef Vundef) rr). +Proof. + intros. unfold v_compare_int, compare_int. + (destruct rr; + [ DDRF d; discriminate_preg_flags | + validate_crbit_flags c | + discriminate_preg_flags ]). +Qed. + +Lemma compare_int_res: forall sr mr rsr rr v1 v2 + (HMEM: sr pmem = Memstate mr) + (HEQV: forall r : preg, sr (# r) = Val (rsr r)), + ((((sr <[ 2 <- Val (_CN (v_compare_int v1 v2)) ]>) <[ 3 <- + Val (_CZ (v_compare_int v1 v2)) ]>) <[ 4 <- + Val (_CC (v_compare_int v1 v2)) ]>) <[ 5 <- + Val (_CV (v_compare_int v1 v2)) ]>) (# rr) = +Val + ((compare_int rsr v1 v2) rr). +Proof. + intros. + destruct v1; destruct v2; + try eapply compare_int_res_aux; eauto; + unfold v_compare_int, compare_int; + (destruct rr; + [ DDRF d; discriminate_preg_flags | + validate_crbit_flags c | + discriminate_preg_flags ]). +Qed. + +(** Parallelizability test of a bblock (bundle), and bisimulation of the Asmblock and L parallel semantics *) + +(*Module PChk := ParallelChecks L PosPseudoRegSet.*) + +(*Definition bblock_para_check (p: Asmvliw.bblock) : bool :=*) + (*PChk.is_parallelizable (trans_block p).*) + +Section SECT_SEQ. + +(*Import PChk.*) + +(*Arguments Pos.add: simpl never.*) +(*Arguments ppos: simpl never.*) + +Variable Ge: genv. + +Lemma trans_arith_correct rsr mr sr rsw' old i: + (*Ge = Genv ge fn ->*) + (*match_states (State rs m) m' ->*) + (*exists em,*) + (*L.inst_run Ge (trans_arith o) m' old = Some em /\ match_states .*) + match_states (State rsr mr) sr -> + (*match_states (State rsw mw) sw ->*) + exec_arith_instr Ge.(_lk) i rsr = rsw' -> + exists sw, + inst_run Ge (trans_arith i) sr old = Some sw + /\ match_states (State rsw' mr) sw. +Proof. + induction i. + all: intros MS EARITH; subst; inv MS; unfold exec_arith_instr. + - (* PArithP *) + DIRN1 rd; Simpl sr. + - (* PArithPP *) + DIRN1 rs; DIRN1 rd; Simpl sr. + - (* PArithPPP *) + DIRN1 r1; DIRN1 r2; DIRN1 rd; Simpl sr. + - (* PArithRR0R *) + simpl. destruct r1. + + (* OArithRR0R *) simpl; Simpl sr. + + (* OArithRR0R_XZR *) simpl; destruct (arith_rr0r_isize _); Simpl sr. + - (* PArithRR0 *) + simpl. destruct r1. + + (* OArithRR0 *) simpl; Simpl sr. + + (* OArithRR0_XZR *) simpl; destruct (arith_rr0_isize _); Simpl sr. + - (* PArithARRRR0 *) + simpl. destruct r3. + + (* OArithARRRR0 *) simpl; Simpl sr. + + (* OArithARRRR0_XZR *) simpl; destruct (arith_arrrr0_isize _); Simpl sr. + - (* PArithComparisonPP *) + DIRN1 r2; DIRN1 r1; destruct i; + repeat Simpl_rep sr; Simpl_exists sr; + unfold arith_eval_comparison_pp; destruct arith_prepare_comparison_pp; + simpl; intros rr; try destruct sz; + try (eapply compare_single_res; eauto); + try (eapply compare_long_res; eauto); + try (eapply compare_float_res; eauto). + - (* PArithComparisonR0R *) + simpl. destruct r1; ( + simpl; destruct i; + repeat Simpl_rep sr; Simpl_exists sr; + unfold arith_eval_comparison_r0r, arith_comparison_r0r_isize; destruct arith_prepare_comparison_r0r; destruct is; + simpl; intros rr; try destruct sz; + try (eapply compare_long_res; eauto); + try (eapply compare_int_res; eauto)). + - (* PArithComparisonP *) + DIRN1 r1; destruct i; + repeat Simpl_rep sr; Simpl_exists sr; + unfold arith_eval_comparison_p; destruct arith_prepare_comparison_p; + simpl; try intros rr; try destruct sz; + try (eapply compare_single_res; eauto); + try (eapply compare_long_res; eauto); + try (eapply compare_int_res; eauto); + try (eapply compare_float_res; eauto). + - (* Pcset *) + simpl; (*DI0N0 rd.*) unfold eval_testcond, get_testcond_rlocs, cflags_eval; + unfold cond_eval_is; unfold flags_testcond_value, list_exp_eval; destruct c; simpl; + repeat Simpl_rep sr; Simpl_exists sr; + destruct_res_flag rsr; + Simpl sr. + - (* Pfmovi *) + simpl; destruct r1; simpl; destruct fsz; Simpl sr. + - (* Pcsel *) + simpl. + unfold eval_testcond, cflags_eval. DIRN1 r1; DIRN1 r2; destruct c; simpl; + repeat Simpl_rep sr; + (eexists; split; [| split]; [reflexivity | DDRM rd; Simpl_exists sr | idtac]). + all: intros rr; destruct (PregEq.eq rr rd); + [ subst; erewrite Pregmap.gss; erewrite sr_gss; reflexivity | + try erewrite Pregmap.gso; try erewrite assign_diff; try rewrite H0; try fold (ppos rd); try eapply ppos_discr; eauto ]. + - (* Pfnmul *) + simpl; destruct fsz; Simpl sr. +Qed. + +Lemma sp_xsp: + SP = XSP. +Proof. + econstructor. +Qed. + +Theorem bisimu_basic rsr mr sr bi: + match_states (State rsr mr) sr -> + match_outcome (exec_basic Ge.(_lk) Ge.(_genv) bi rsr mr) (inst_run Ge (trans_basic bi) sr sr). +Proof. + +(* a little tactic to automate reasoning on preg_eq *) +Local Hint Resolve not_eq_sym ppos_pmem_discr ppos_discr: core. +Local Ltac preg_eq_discr r rd := + destruct (preg_eq r rd); try (subst r; rewrite assign_eq, Pregmap.gss; auto); + rewrite (assign_diff _ (#rd) (#r) _); auto; + rewrite Pregmap.gso; auto. + + intros MS; inversion MS as (H & H0). + destruct bi; simpl. + (* Loadsymbol / Cvtsw2x / Cvtuw2x / Cvtx2w *) + 6,7,8,9: Simpl sr. + - (* Arith *) + exploit trans_arith_correct; eauto. + - (* Load *) + unfold exec_load, eval_addressing_rlocs_ld, exp_eval; + destruct a; simpl; try destruct base; Simpl_exists sr; erewrite H; + unfold exec_load1, exec_load2, exec_loadU; unfold call_ll_loadv; + try destruct (Mem.loadv _ _ _); simpl; auto. + all: eexists; split; [| split]; [ eauto | DDRF rd; eauto | idtac ]; + intros rr; destruct (PregEq.eq rr rd); subst; [ rewrite Pregmap.gss; rewrite sr_gss; reflexivity | + rewrite assign_diff; try rewrite Pregmap.gso; + try rewrite H0; try (fold (ppos rd); eapply ppos_discr); auto]. + - (* Store *) + unfold exec_store, eval_addressing_rlocs_st, exp_eval; + destruct a; simpl; DIRN1 r; try destruct base; Simpl_exists sr; erewrite H; + unfold exec_store1, exec_store2, exec_storeU; unfold call_ll_storev; + try destruct (Mem.storev _ _ _ _); simpl; auto. + all: eexists; split; [| split]; [ eauto | eauto | + intros rr; rewrite assign_diff; [ rewrite H0; auto | apply ppos_pmem_discr ]]. + - (* Alloc *) + destruct (Mem.alloc _ _ _) eqn:MEMAL. destruct (Mem.store _ _ _ _) eqn:MEMS. + + eexists; repeat split. + * rewrite !assign_diff; try discriminate_ppos; Simpl_exists sr; + rewrite H; destruct (Mem.alloc _ _ _) eqn:MEMAL2; + injection MEMAL; intros Hm Hb; try rewrite Hm, Hb; + rewrite sp_xsp in MEMS; rewrite MEMS. + rewrite !assign_diff; try discriminate_ppos; Simpl_exists sr; rewrite H; + destruct (Mem.alloc _ _ _) eqn:MEMAL3; + injection MEMAL2; intros Hm2 Hb2; try rewrite Hm2, Hb2; + rewrite Hm, Hb; rewrite MEMS; reflexivity. + * eauto. + * intros rr; DPRF rr; repeat Simpl_exists sr. + + simpl; repeat Simpl_exists sr. erewrite H. destruct (Mem.alloc _ _ _) eqn:HMEMAL2. + injection MEMAL; intros Hm Hb. + try rewrite Hm, Hb; clear Hm Hb. + try rewrite sp_xsp in MEMS; rewrite MEMS. reflexivity. + - (* Free *) + destruct (Mem.loadv _ _ _) eqn:MLOAD; simpl; auto; + repeat Simpl_exists sr; rewrite H; simpl. + + destruct (rsr SP) eqn:EQSP; simpl; rewrite <- sp_xsp; rewrite EQSP; rewrite MLOAD; try reflexivity. + destruct (Mem.free _ _ _) eqn:EQFREE; try reflexivity. rewrite assign_diff; discriminate_ppos. + replace_regs_pos sr; sr_val_rwrt. rewrite <- sp_xsp; rewrite EQSP; rewrite MLOAD. rewrite EQFREE. + Simpl_exists sr. intros rr; DPRF rr; repeat Simpl_exists sr. + + rewrite <- sp_xsp; rewrite MLOAD; reflexivity. +Qed. + +Theorem bisimu_body: + forall bdy rsr mr sr, + match_states (State rsr mr) sr -> + match_outcome (exec_body Ge.(_lk) Ge.(_genv) bdy rsr mr) (exec Ge (trans_body bdy) sr). +Proof. + induction bdy as [|i bdy]; simpl; eauto. + intros. + exploit (bisimu_basic rsr mr sr i); eauto. + destruct (exec_basic _ _ _ _ _); simpl. + - intros (s' & X1 & X2). + rewrite X1; simpl; eauto. eapply IHbdy; eauto; simpl. + unfold match_states in *. destruct s. unfold Asm._m. eauto. + - intros X; rewrite X; simpl; auto. +Qed. + +Theorem bisimu_control ex sz rsr mr sr: + match_states (State rsr mr) sr -> + match_outcome (exec_cfi Ge.(_genv) Ge.(_fn) ex (incrPC (Ptrofs.repr sz) rsr) mr) (inst_run Ge (trans_pcincr sz (trans_exit (Some (PCtlFlow ex)))) sr sr). +Proof. + intros MS. + simpl in *. inv MS. + destruct ex. + (* Obr / Oret *) + 6,7: unfold control_eval, incrPC; simpl; destruct Ge; + replace_pc; rewrite (H0 PC); + repeat Simpl_rep sr; Simpl_exists sr; + intros rr; destruct (preg_eq rr PC); [ + rewrite e; rewrite sr_gss; rewrite Pregmap.gss; + try rewrite Pregmap.gso; discriminate_ppos; fold (ppos r); auto | + repeat Simpl_rep sr; try rewrite !Pregmap.gso; auto; apply ppos_discr in n; auto ]. + (* Ocbnz / Ocbz *) + 6,7,8,9: unfold control_eval; destruct Ge; simpl; + replace_pc; rewrite (H0 PC); + unfold eval_branch, eval_neg_branch, eval_testzero, eval_testbit, + incrPC, goto_label_deps, goto_label; + destruct (PregEq.eq r PC); + [ rewrite e; destruct sz0; simpl; Simpl sr | + destruct sz0; simpl; replace_pc; rewrite Pregmap.gso; auto; repeat Simpl_rep sr; try rewrite H0; + try (destruct (Val_cmpu_bool _ _ _) eqn:EQCMP; try reflexivity; destruct b); + try (destruct (Val_cmplu_bool _ _ _) eqn:EQCMP; try reflexivity; destruct b); + try (destruct (Val.cmp_bool _ _ _) eqn:EQCMP; try reflexivity; destruct b); + try (destruct (Val.cmpl_bool _ _ _) eqn:EQCMP; try reflexivity; destruct b); + try (Simpl_exists sr; intros rr; destruct (PregEq.eq rr PC); subst; + [ rewrite sr_gss, Pregmap.gss; reflexivity | rewrite !assign_diff, Pregmap.gso; auto ]); + try (destruct (label_pos _ _ _); try reflexivity; rewrite Pregmap.gss; + destruct Val.offset_ptr; try reflexivity; Simpl_exists sr; + intros rr; destruct (PregEq.eq rr PC); subst; + [ rewrite sr_gss, Pregmap.gss; reflexivity | rewrite !assign_diff, Pregmap.gso; auto ]; + rewrite Pregmap.gso; auto)]. + - (* Ob *) + replace_pc. rewrite (H0 PC). simpl. + unfold goto_label, control_eval. destruct Ge. + unfold goto_label_deps. destruct (label_pos _ _ _); auto. + + unfold incrPC. rewrite Pregmap.gss; eauto. destruct (Val.offset_ptr _ _); auto; + try (rewrite sr_gss; unfold Stuck; reflexivity). + simpl. eexists; split; split. + * rewrite sr_update_overwrite. unfold pmem, assign in *. simpl. rewrite H; reflexivity. + * intros. rewrite sr_update_overwrite. unfold Pregmap.set, assign. + destruct r as [dr|cr|]; try destruct dr as [ir|fr]; try destruct ir as [irr|]; + try destruct irr; try destruct fr; try destruct cr; simpl; try rewrite <- H0; eauto. + + rewrite sr_gss; reflexivity. + - (* Obc *) + replace_pc. rewrite (H0 PC). simpl. + unfold eval_branch, goto_label, control_eval. destruct Ge. + unfold goto_label_deps, cflags_eval, eval_testcond, list_exp_eval. + destruct c; simpl; unfold incrPC; + repeat (replace_ppos; replace_pc; replace_regs_pos sr; sr_val_rwrt; try rewrite !assign_diff; discriminate_ppos). + 1,2,3,4,5,6: destruct_res_flag rsr. + 7,8,9,10: do 2 (destruct_res_flag rsr). + 11,12 : do 3 (destruct_res_flag rsr). + 1,2,3,4,5,6,9,10: destruct (Int.eq _ _); [| Simpl sr ]; + destruct (label_pos _ _ _); [| reflexivity]; replace_pc; + rewrite !Pregmap.gss; destruct Val.offset_ptr; + try (unfold Stuck; reflexivity); Simpl_exists sr; intros rr; + apply reg_update_overwrite; eauto. + 1,3: destruct (andb); [| Simpl sr ]; + destruct (label_pos _ _ _); [| reflexivity]; replace_pc; rewrite !Pregmap.gss; + destruct Val.offset_ptr; try (unfold Stuck; reflexivity); Simpl_exists sr; + intros rr; apply reg_update_overwrite; eauto. + 1,2: destruct (orb); [| Simpl sr ]; + destruct (label_pos _ _ _); [| reflexivity]; replace_pc; rewrite !Pregmap.gss; + destruct Val.offset_ptr; try (unfold Stuck; reflexivity); Simpl_exists sr; + intros rr; apply reg_update_overwrite; eauto. + - (* Obl *) + replace_pc. rewrite (H0 PC). simpl. + unfold control_eval. destruct Ge. + rewrite sr_gss. + repeat Simpl_rep sr. Simpl_exists sr. + Simpl sr. + all: repeat (intros; replace_regs_pos sr; try replace (38) with (#X30) by eauto; unfold incrPC; Simpl_update). + - (* Obs *) + unfold control_eval. destruct Ge. replace_pc. rewrite (H0 PC). simpl; unfold incrPC. + replace_pc; Simpl_exists sr; intros rr; apply reg_update_overwrite; eauto. + - (* Oblr *) + replace_pc. rewrite (H0 PC). + unfold control_eval. destruct Ge. simpl. unfold incrPC. + try (eexists; split; [ | split ]); eauto. + intros rr; DPRF rr; Simpl_update. + 68: rewrite sr_gss, Pregmap.gss; + try rewrite Pregmap.gso; discriminate_ppos; fold (ppos r); rewrite H0; auto. + all: repeat Simpl_rep sr; rewrite !Pregmap.gso; discriminate_ppos; auto. + - (* Obtbl *) + replace_pc. rewrite (H0 PC). + unfold control_eval. destruct Ge. simpl. unfold incrPC. + destruct r1. + 17: rewrite Pregmap.gss, sr_gss; try reflexivity. + all: rewrite !Pregmap.gso, !assign_diff; discriminate_ppos; + rewrite ireg_pos_ppos; try erewrite H0; destruct (rsr _); + try destruct (list_nth_z _ _); try reflexivity; + unfold goto_label, goto_label_deps; destruct (label_pos _ _ _); + try rewrite 2Pregmap.gso, Pregmap.gss; destruct (Val.offset_ptr (rsr PC) (Ptrofs.repr sz)); + try reflexivity; discriminate_ppos; simpl; Simpl_exists sr; + intros rr; + destruct (PregEq.eq X16 rr); [ subst; Simpl_update |]; + destruct (PregEq.eq X17 rr); [ subst; Simpl_update |]; + destruct (PregEq.eq PC rr); [ subst; Simpl_update |]; + rewrite !Pregmap.gso; auto; apply ppos_discr in n; apply ppos_discr in n0; apply ppos_discr in n1; + simpl in *;repeat Simpl_rep sr; auto. +Qed. + +Theorem bisimu_exit ex sz rsr mr sr: + match_states (State rsr mr) sr -> + match_outcome (estep Ge.(_genv) Ge.(_fn) ex (Ptrofs.repr sz) rsr mr) (inst_run Ge (trans_pcincr sz (trans_exit (Some (PCtlFlow ex)))) sr sr). +Proof. + intros; unfold estep. + exploit (bisimu_control ex sz rsr mr sr); eauto. +Qed. + +Definition trans_block_aux bdy sz ex := (trans_body bdy) ++ (trans_pcincr sz (trans_exit ex) :: nil). + +Theorem bisimu rsr mr sr bdy ex sz: + match_states (State rsr mr) sr -> + match_outcome (bbstep Ge.(_lk) Ge.(_genv) Ge.(_fn) ex (Ptrofs.repr sz) bdy rsr mr) (run Ge (trans_block_aux bdy sz (Some (PCtlFlow ex))) sr). +Proof. + intros MS. unfold bbstep, trans_block_aux. + exploit (bisimu_body bdy rsr mr sr); eauto. + destruct (exec_body _ _ _ _ _); simpl. + - unfold match_states in *. intros (s' & X1 & X2). destruct s. + erewrite run_app_Some; eauto. + exploit (bisimu_exit ex sz _rs _m s'); eauto. + destruct Ge; simpl. destruct MS as (Y1 & Y2). destruct X2 as (X2 & X3). + replace_pc. erewrite !X3; simpl. + destruct (inst_run _ _ _ _); simpl; auto. + - intros X; erewrite run_app_None; eauto. +Qed. + +(* TODO We should use this version, but our current definitions +does not match +Theorem bisimu rsr mr b sr ex sz: + match_states (State rsr mr) sr -> + match_outcome (bbstep Ge.(_lk) Ge.(_genv) Ge.(_fn) ex (Ptrofs.repr sz) (body b) rsr mr) (exec Ge (trans_block b) sr). +Proof. + + intros MS. unfold bbstep. + exploit (bisimu_body (body b) rsr mr sr); eauto. + unfold exec, trans_block; simpl. + destruct (exec_body _ _ _ _); simpl. + - unfold match_states in *. intros (s' & X1 & X2). destruct s. + erewrite run_app_Some; eauto. + exploit (bisimu_exit ex sz _rs _m s' s'); eauto. + destruct Ge; simpl. destruct X2 as (X2 & X3). destruct MS as (Y1 & Y2). + replace (6) with (#PC) by auto. erewrite X3; simpl. + unfold trans_exit. + destruct (inst_run _ _ _); simpl; auto. + - intros X; erewrite run_app_None; eauto. + + intros MS. unfold bbstep, trans_block. + exploit (bisimu_body (body b) rsr mr sr); eauto. + destruct (exec_body _ _ _ _ _); simpl. + - unfold match_states in *. intros (s' & X1 & X2). destruct s. + erewrite run_app_Some; eauto. + exploit (bisimu_exit ex sz _rs _m s' s'); eauto. + destruct Ge; simpl. destruct MS as (Y1 & Y2). destruct X2 as (X2 & X3). + replace (6) with (#PC) by auto. erewrite !X3; simpl. + destruct (inst_run _ _ _ _); simpl; auto. + - intros X; erewrite run_app_None; eauto. +Qed.*) + +(*Theorem bisimu_bblock rsr mr sr bdy1 bdy2 ex sz:*) + (*match_states (State rsr mr) sr ->*) + (*match_outcome *) + (*match bbstep Ge.(_lk) Ge.(_genv) Ge.(_fn) ex (Ptrofs.repr sz) bdy1 rsr mr with*) + (*| Some (State rs' m') => exec_body Ge.(_lk) Ge.(_genv) bdy2 rs' m'*) + (*| Stuck => Stuck*) + (*end*) + (*(run Ge ((trans_block_aux bdy1 sz (Some (PCtlFlow (ex))))++(trans_body bdy2)) sr).*) +(*Proof.*) + (*intros.*) + (*exploit (bisimu rsr mr sr bdy1 ex sz); eauto.*) + (*destruct (bbstep _ _ _ _ _ _); simpl.*) + (*- intros (s' & X1 & X2).*) + (*erewrite run_app_Some; eauto. destruct s.*) + (*eapply bisimu_body; eauto.*) + (*- intros; erewrite run_app_None; eauto.*) +(*Qed.*) + +(*Lemma trans_body_perserves_permutation bdy1 bdy2:*) + (*Permutation bdy1 bdy2 ->*) + (*Permutation (trans_body bdy1) (trans_body bdy2).*) +(*Proof.*) + (*induction 1; simpl; econstructor; eauto.*) +(*Qed.*) +(* +Lemma trans_body_app bdy1: forall bdy2, + trans_body (bdy1++bdy2) = (trans_body bdy1) ++ (trans_body bdy2). +Proof. + induction bdy1; simpl; congruence. +Qed. +*) +(*Theorem trans_block_perserves_permutation bdy1 bdy2 b:*) + (*Permutation (bdy1 ++ bdy2) (body b) ->*) + (*Permutation (trans_block b) ((trans_block_aux bdy1 (size b) (exit b))++(trans_body bdy2)).*) +(*Proof.*) + (*intro H; unfold trans_block, trans_block_aux.*) + (*eapply perm_trans.*) + (*- eapply Permutation_app_tail. *) + (*apply trans_body_perserves_permutation.*) + (*apply Permutation_sym; eapply H.*) + (*- rewrite trans_body_app. rewrite <-! app_assoc.*) + (*apply Permutation_app_head.*) + (*apply Permutation_app_comm.*) +(*Qed.*) + +(*Theorem bisimu_par rs1 m1 s1' b ge fn o2:*) + (*Ge = Genv ge fn ->*) + (*match_states (State rs1 m1) s1' -> *) + (*parexec_bblock ge fn b rs1 m1 o2 ->*) + (*exists o2',*) + (*prun Ge (trans_block b) s1' o2'*) + (*/\ match_outcome o2 o2'.*) +(*Proof.*) + (*intros GENV MS PAREXEC.*) + (*inversion PAREXEC as (bdy1 & bdy2 & PERM & WIO).*) + (*exploit trans_block_perserves_permutation; eauto.*) + (*intros Perm.*) + (*exploit (bisimu_par_wio_bblock ge fn rs1 m1 s1' bdy1 bdy2 (exit b) (size b)); eauto.*) + (*rewrite <- WIO. clear WIO.*) + (*intros H; eexists; split. 2: eapply H.*) + (*unfold prun; eexists; split; eauto. *) + (*destruct (prun_iw _ _ _ _); simpl; eauto.*) +(*Qed.*) + +(** sequential execution *) +(*Theorem bisimu_basic ge fn bi rs m s:*) + (*Ge = Genv ge fn ->*) + (*match_states (State rs m) s ->*) + (*match_outcome (exec_basic_instr ge bi rs m) (inst_run Ge (trans_basic bi) s s).*) +(*Proof.*) + (*intros; unfold exec_basic_instr. rewrite inst_run_prun.*) + (*eapply bisimu_par_wio_basic; eauto.*) +(*Qed.*) + +(*Lemma bisimu_body:*) + (*forall bdy ge fn rs m s,*) + (*Ge = Genv ge fn ->*) + (*match_states (State rs m) s ->*) + (*match_outcome (exec_body ge bdy rs m) (exec Ge (trans_body bdy) s).*) +(*Proof.*) + (*induction bdy as [|i bdy]; simpl; eauto. *) + (*intros.*) + (*exploit (bisimu_basic ge fn i rs m s); eauto.*) + (*destruct (exec_basic_instr _ _ _ _); simpl.*) + (*- intros (s' & X1 & X2). rewrite X1; simpl; eauto.*) + (*- intros X; rewrite X; simpl; auto.*) +(*Qed.*) + +(*Theorem bisimu_exit ge fn b rs m s:*) + (*Ge = Genv ge fn ->*) + (*match_states (State rs m) s ->*) + (*match_outcome (exec_control ge fn (exit b) (nextblock b rs) m) (inst_run Ge (trans_pcincr (size b) (trans_exit (exit b))) s s).*) +(*Proof.*) + (*intros; unfold exec_control, nextblock. rewrite inst_run_prun. *) + (*apply (bisimu_par_control (exit b) (size b) (Val.offset_ptr (rs PC) (Ptrofs.repr (size b))) ge fn rs rs m m s s); auto.*) +(*Qed.*) + +(*Lemma bbstep_is_exec_bblock: forall bb (cfi: cf_instruction) size_bb bdy rs m rs' m' t,*) + (*(body bb) = bdy ->*) + (*(exit bb) = Some (PCtlFlow cfi) ->*) + (*Ptrofs.repr (size bb) = size_bb ->*) + (*exec_bblock Ge.(_lk) Ge.(_genv) Ge.(_fn) bb rs m t rs' m'*) + (*<-> (bbstep Ge.(_lk) Ge.(_genv) Ge.(_fn) (cfi) size_bb bdy rs m = Next rs' m' /\ t = E0).*) +(*Proof.*) + (*intros.*) +(*Admitted.*) + +(* TODO This is the lemma we should use if we want to modelize +builtins in our scheduling process. +If we do not modelize builtins, we could use a simpler definition (trace E0) *) +(* +Theorem bisimu' rs m rs' m' bb s: + match_states (State rs m) s -> + (exists t, exec_bblock Ge.(_lk) Ge.(_genv) Ge.(_fn) bb rs m t rs' m') + <-> (exists s', (exec Ge (trans_block bb) s) = Some s' /\ match_states (State rs' m') s'). +Proof. + intros MS. + destruct (exit bb) eqn:EQEXIT. + destruct c eqn:EQC. + - split. + + intros (t & H). + rewrite bbstep_is_exec_bblock in H; eauto. + eexists; split. destruct H as [H0 H1]. + generalize (bisimu ) + unfold exec_bblock. + exploit (bisimu_body (body b) ge fn rs m s); eauto. + unfold exec, trans_block; simpl. + destruct (exec_body _ _ _ _); simpl. + - intros (s' & X1 & X2). + erewrite run_app_Some; eauto. + exploit (bisimu_exit ge fn b rs0 m0 s'); eauto. + subst Ge; simpl. destruct X2 as (Y1 & Y2). erewrite Y2; simpl. + destruct (inst_run _ _ _); simpl; auto. + - intros X; erewrite run_app_None; eauto. +Qed.*) + +Theorem trans_state_match: forall S, match_states S (trans_state S). +Proof. + intros. destruct S as (rs & m). simpl. + split. reflexivity. + intro. destruct r as [dr|cr|]; try destruct dr as [ir|fr]; try destruct cr; + try destruct ir as [irr|]; try destruct irr; try destruct fr; try reflexivity. +Qed. + +Lemma state_eq_decomp: + forall rs1 m1 rs2 m2, rs1 = rs2 -> m1 = m2 -> State rs1 m1 = State rs2 m2. +Proof. + intros. congruence. +Qed. + +Theorem state_equiv S1 S2 S': match_states S1 S' -> match_states S2 S' -> S1 = S2. +Proof. + unfold match_states; intros H0 H1. destruct S1 as (rs1 & m1). destruct S2 as (rs2 & m2). inv H0. inv H1. + apply state_eq_decomp. + - apply functional_extensionality. intros. assert (Val (rs1 x) = Val (rs2 x)) by congruence. congruence. + - congruence. +Qed. + +(*Lemma bblock_para_check_correct ge fn bb rs m rs' m':*) + (*Ge = Genv ge fn ->*) + (*exec_bblock ge fn bb rs m = Next rs' m' ->*) + (*bblock_para_check bb = true ->*) + (*det_parexec ge fn bb rs m rs' m'.*) +(*Proof.*) + (*intros H H0 H1 o H2. unfold bblock_para_check in H1.*) + (*exploit (bisimu rs m bb ge fn); eauto. eapply trans_state_match.*) + (*rewrite H0; simpl.*) + (*intros (s2' & EXEC & MS).*) + (*exploit bisimu_par. 2: apply (trans_state_match (State rs m)). all: eauto.*) + (*intros (o2' & PRUN & MO).*) + (*exploit parallelizable_correct. apply is_para_correct_aux. eassumption.*) + (*intro. eapply H3 in PRUN. clear H3. destruct o2'.*) + (*- inv PRUN. inv H3. unfold exec in EXEC; unfold trans_state in H.*) + (*assert (x = s2') by congruence. subst. clear H.*) + (*assert (m0 = s2') by (apply functional_extensionality; auto). subst. clear H4.*) + (*destruct o; try discriminate. inv MO. inv H. assert (s2' = x) by congruence. subst.*) + (*exploit (state_equiv (State rs' m') (State rs0 m0)).*) + (*2: eapply H4. eapply MS. intro H. inv H. reflexivity.*) + (*- unfold match_outcome in MO. destruct o.*) + (*+ inv MO. inv H3. discriminate.*) + (*+ clear MO. unfold exec in EXEC.*) + (*unfold trans_state in PRUN; rewrite EXEC in PRUN. discriminate.*) +(*Qed.*) + +End SECT_SEQ. + +Section SECT_BBLOCK_EQUIV. + +Variable Ge: genv. + +Local Hint Resolve trans_state_match: core. + +Lemma bblock_simu_reduce: + forall p1 p2, + L.bblock_simu Ge (trans_block p1) (trans_block p2) -> + (has_builtin p1 = true -> exit p1 = exit p2) -> + Asmblockprops.bblock_simu Ge.(_lk) Ge.(_genv) Ge.(_fn) p1 p2. +Proof. + unfold bblock_simu. intros p1 p2 H BLT rs m rs' m' t EBB. + generalize (H (trans_state (State rs m))); clear H. + intro H. (* TODO How to define this correctly ? + exploit (bisimu rs m (body p1) (trans_state (State rs m))); eauto. + exploit (bisimu Ge rs m p2 ge fn (trans_state (State rs m))); eauto. + destruct (exec_bblock ge fn p1 rs m); try congruence. + intros H3 (s2' & exp2 & MS'). unfold exec in exp2, H3. rewrite exp2 in H2. + destruct H2 as (m2' & H2 & H4). discriminate. rewrite H2 in H3. + destruct (exec_bblock ge fn p2 rs m); simpl in H3. + * destruct H3 as (s' & H3 & H5 & H6). inv H3. inv MS'. + cutrewrite (rs0=rs1). + - cutrewrite (m0=m1); auto. congruence. + - apply functional_extensionality. intros r. + generalize (H0 r). intros Hr. congruence. + * discriminate. +Qed.*) +Admitted. + +(** Used for debug traces *) + +Definition ireg_name (ir: ireg) : pstring := + match ir with + | X0 => Str ("X0") | X1 => Str ("X1") | X2 => Str ("X2") | X3 => Str ("X3") | X4 => Str ("X4") | X5 => Str ("X5") | X6 => Str ("X6") | X7 => Str ("X7") + | X8 => Str ("X8") | X9 => Str ("X9") | X10 => Str ("X10") | X11 => Str ("X11") | X12 => Str ("X12") | X13 => Str ("X13") | X14 => Str ("X14") | X15 => Str ("X15") + | X16 => Str ("X16") | X17 => Str ("X17") | X18 => Str ("X18") | X19 => Str ("X19") | X20 => Str ("X20") | X21 => Str ("X21") | X22 => Str ("X22") | X23 => Str ("X23") + | X24 => Str ("X24") | X25 => Str ("X25") | X26 => Str ("X26") | X27 => Str ("X27") | X28 => Str ("X28") | X29 => Str ("X29") | X30 => Str ("X30") + end +. + +Definition freg_name (fr: freg) : pstring := + match fr with + | D0 => Str ("D0") | D1 => Str ("D1") | D2 => Str ("D2") | D3 => Str ("D3") | D4 => Str ("D4") | D5 => Str ("D5") | D6 => Str ("D6") | D7 => Str ("D7") + | D8 => Str ("D8") | D9 => Str ("D9") | D10 => Str ("D10") | D11 => Str ("D11") | D12 => Str ("D12") | D13 => Str ("D13") | D14 => Str ("D14") | D15 => Str ("D15") + | D16 => Str ("D16") | D17 => Str ("D17") | D18 => Str ("D18") | D19 => Str ("D19") | D20 => Str ("D20") | D21 => Str ("D21") | D22 => Str ("D22") | D23 => Str ("D23") + | D24 => Str ("D24") | D25 => Str ("D25") | D26 => Str ("D26") | D27 => Str ("D27") | D28 => Str ("D28") | D29 => Str ("D29") | D30 => Str ("D30") | D31 => Str ("D31") + end +. + +Definition string_of_name (x: P.R.t): ?? pstring := + if (Pos.eqb x pmem) then + RET (Str "MEM") + else + match inv_ppos x with + | Some (CR cr) => match cr with + | CN => RET (Str ("CN")) + | CZ => RET (Str ("CZ")) + | CC => RET (Str ("CC")) + | CV => RET (Str ("CV")) + end + | Some (PC) => RET (Str ("PC")) + | Some (DR dr) => match dr with + | IR ir => match ir with + | XSP => RET (Str ("XSP")) + | RR1 irr => RET (ireg_name irr) + end + | FR fr => RET (freg_name fr) + end + | _ => RET (Str ("UNDEFINED")) + end. + +Definition string_of_name_ArithP (n: arith_p) : pstring := + match n with + | Padrp _ _ => "Padrp" + | Pmovz _ _ _ => "Pmov" + | Pmovn _ _ _ => "Pmov" + | Pfmovimms _ => "Pfmovimm" + | Pfmovimmd _ => "Pfmovimm" + end. + +Definition string_of_name_ArithPP (n: arith_pp) : pstring := + match n with + | Pmov => "Pmov" + | Pmovk _ _ _ => "Pmovk" + | Paddadr _ _ => "Paddadr" + | Psbfiz _ _ _ => "Psbfiz" + | Psbfx _ _ _ => "Psbfx" + | Pubfiz _ _ _ => "Pubfiz" + | Pubfx _ _ _ => "Pubfx" + | Pfmov => "Pfmov" + | Pfcvtds => "Pfcvtds" + | Pfcvtsd => "Pfcvtsd" + | Pfabs _ => "Pfabs" + | Pfneg _ => "Pfneg" + | Pscvtf _ _ => "Pscvtf" + | Pucvtf _ _ => "Pucvtf" + | Pfcvtzs _ _ => "Pfcvtzs" + | Pfcvtzu _ _ => "Pfcvtzu" + | Paddimm _ _ => "Paddimm" + | Psubimm _ _ => "Psubimm" + end. + +Definition string_of_name_ArithPPP (n: arith_ppp) : pstring := + match n with + | Pasrv _ => "Pasrv" + | Plslv _ => "Plslv" + | Plsrv _ => "Plsrv" + | Prorv _ => "Prorv" + | Psmulh => "Psmulh" + | Pumulh => "Pumulh" + | Psdiv _ => "Psdiv" + | Pudiv _ => "Pudiv" + | Paddext _ => "Paddext" + | Psubext _ => "Psubext" + | Pfadd _ => "Pfadd" + | Pfdiv _ => "Pfdiv" + | Pfmul _ => "Pfmul" + | Pfsub _ => "Pfsub" + end. + +Definition string_of_name_ArithRR0R (n: arith_rr0r) : pstring := + match n with + | Padd _ _ => "ArithRR0R=>Padd" + | Psub _ _ => "ArithRR0R=>Psub" + | Pand _ _ => "ArithRR0R=>Pand" + | Pbic _ _ => "ArithRR0R=>Pbic" + | Peon _ _ => "ArithRR0R=>Peon" + | Peor _ _ => "ArithRR0R=>Peor" + | Porr _ _ => "ArithRR0R=>Porr" + | Porn _ _ => "ArithRR0R=>Porn" + end. + +Definition string_of_name_ArithRR0R_XZR (n: arith_rr0r) : pstring := + match n with + | Padd _ _ => "ArithRR0R_XZR=>Padd" + | Psub _ _ => "ArithRR0R_XZR=>Psub" + | Pand _ _ => "ArithRR0R_XZR=>Pand" + | Pbic _ _ => "ArithRR0R_XZR=>Pbic" + | Peon _ _ => "ArithRR0R_XZR=>Peon" + | Peor _ _ => "ArithRR0R_XZR=>Peor" + | Porr _ _ => "ArithRR0R_XZR=>Porr" + | Porn _ _ => "ArithRR0R_XZR=>Porn" + end. + +Definition string_of_name_ArithRR0 (n: arith_rr0) : pstring := + match n with + | Pandimm _ _ => "ArithRR0=>Pandimm" + | Peorimm _ _ => "ArithRR0=>Peorimm" + | Porrimm _ _ => "ArithRR0=>Porrimm" + end. + +Definition string_of_name_ArithRR0_XZR (n: arith_rr0) : pstring := +match n with + | Pandimm _ _ => "ArithRR0_XZR=>Pandimm" + | Peorimm _ _ => "ArithRR0_XZR=>Peorimm" + | Porrimm _ _ => "ArithRR0_XZR=>Porrimm" + end. + +Definition string_of_name_ArithARRRR0 (n: arith_arrrr0) : pstring := + match n with + | Pmadd _ => "ArithARRRR0=>Pmadd" + | Pmsub _ => "ArithARRRR0=>Pmsub" + end. + +Definition string_of_name_ArithARRRR0_XZR (n: arith_arrrr0) : pstring := + match n with + | Pmadd _ => "ArithARRRR0_XZR=>Pmadd" + | Pmsub _ => "ArithARRRR0_XZR=>Pmsub" + end. + +Definition string_of_name_ArithComparisonPP_CN (n: arith_comparison_pp) : pstring := + match n with + | Pcmpext _ => "ArithComparisonPP_CN=>Pcmpext" + | Pcmnext _ => "ArithComparisonPP_CN=>Pcmnext" + | Pfcmp _ => "ArithComparisonPP_CN=>Pfcmp" + end. + +Definition string_of_name_ArithComparisonPP_CZ (n: arith_comparison_pp) : pstring := + match n with + | Pcmpext _ => "ArithComparisonPP_CZ=>Pcmpext" + | Pcmnext _ => "ArithComparisonPP_CZ=>Pcmnext" + | Pfcmp _ => "ArithComparisonPP_CZ=>Pfcmp" + end. + +Definition string_of_name_ArithComparisonPP_CC (n: arith_comparison_pp) : pstring := +match n with + | Pcmpext _ => "ArithComparisonPP_CC=>Pcmpext" + | Pcmnext _ => "ArithComparisonPP_CC=>Pcmnext" + | Pfcmp _ => "ArithComparisonPP_CC=>Pfcmp" + end. + +Definition string_of_name_ArithComparisonPP_CV (n: arith_comparison_pp) : pstring := +match n with + | Pcmpext _ => "ArithComparisonPP_CV=>Pcmpext" + | Pcmnext _ => "ArithComparisonPP_CV=>Pcmnext" + | Pfcmp _ => "ArithComparisonPP_CV=>Pfcmp" + end. + +Definition string_of_name_ArithComparisonR0R_CN (n: arith_comparison_r0r) : pstring := + match n with + | Pcmp _ _ => "ArithComparisonR0R_CN=>Pcmp" + | Pcmn _ _ => "ArithComparisonR0R_CN=>Pcmn" + | Ptst _ _ => "ArithComparisonR0R_CN=>Ptst" + end. + +Definition string_of_name_ArithComparisonR0R_CZ (n: arith_comparison_r0r) : pstring := + match n with + | Pcmp _ _ => "ArithComparisonR0R_CZ=>Pcmp" + | Pcmn _ _ => "ArithComparisonR0R_CZ=>Pcmn" + | Ptst _ _ => "ArithComparisonR0R_CZ=>Ptst" + end. + +Definition string_of_name_ArithComparisonR0R_CC (n: arith_comparison_r0r) : pstring := + match n with + | Pcmp _ _ => "ArithComparisonR0R_CC=>Pcmp" + | Pcmn _ _ => "ArithComparisonR0R_CC=>Pcmn" + | Ptst _ _ => "ArithComparisonR0R_CC=>Ptst" + end. + +Definition string_of_name_ArithComparisonR0R_CV (n: arith_comparison_r0r) : pstring := + match n with + | Pcmp _ _ => "ArithComparisonR0R_CV=>Pcmp" + | Pcmn _ _ => "ArithComparisonR0R_CV=>Pcmn" + | Ptst _ _ => "ArithComparisonR0R_CV=>Ptst" + end. + +Definition string_of_name_ArithComparisonR0R_CN_XZR (n: arith_comparison_r0r) : pstring := + match n with + | Pcmp _ _ => "ArithComparisonR0R_CN_XZR=>Pcmp" + | Pcmn _ _ => "ArithComparisonR0R_CN_XZR=>Pcmn" + | Ptst _ _ => "ArithComparisonR0R_CN_XZR=>Ptst" + end. + +Definition string_of_name_ArithComparisonR0R_CZ_XZR (n: arith_comparison_r0r) : pstring := + match n with + | Pcmp _ _ => "ArithComparisonR0R_CZ_XZR=>Pcmp" + | Pcmn _ _ => "ArithComparisonR0R_CZ_XZR=>Pcmn" + | Ptst _ _ => "ArithComparisonR0R_CZ_XZR=>Ptst" + end. + +Definition string_of_name_ArithComparisonR0R_CC_XZR (n: arith_comparison_r0r) : pstring := +match n with + | Pcmp _ _ => "ArithComparisonR0R_CC_XZR=>Pcmp" + | Pcmn _ _ => "ArithComparisonR0R_CC_XZR=>Pcmn" + | Ptst _ _ => "ArithComparisonR0R_CC_XZR=>Ptst" + end. + +Definition string_of_name_ArithComparisonR0R_CV_XZR (n: arith_comparison_r0r) : pstring := +match n with + | Pcmp _ _ => "ArithComparisonR0R_CV_XZR=>Pcmp" + | Pcmn _ _ => "ArithComparisonR0R_CV_XZR=>Pcmn" + | Ptst _ _ => "ArithComparisonR0R_CV_XZR=>Ptst" + end. + +Definition string_of_name_ArithComparisonP_CN (n: arith_comparison_p) : pstring := + match n with + | Pfcmp0 _ => "ArithComparisonP_CN=>Pfcmp0" + | Pcmpimm _ _ => "ArithComparisonP_CN=>Pcmpimm" + | Pcmnimm _ _ => "ArithComparisonP_CN=>Pcmnimm" + | Ptstimm _ _ => "ArithComparisonP_CN=>Ptstimm" + end. + +Definition string_of_name_ArithComparisonP_CZ (n: arith_comparison_p) : pstring := + match n with + | Pfcmp0 _ => "ArithComparisonP_CZ=>Pfcmp0" + | Pcmpimm _ _ => "ArithComparisonP_CZ=>Pcmpimm" + | Pcmnimm _ _ => "ArithComparisonP_CZ=>Pcmnimm" + | Ptstimm _ _ => "ArithComparisonP_CZ=>Ptstimm" + end. + +Definition string_of_name_ArithComparisonP_CC (n: arith_comparison_p) : pstring := + match n with + | Pfcmp0 _ => "ArithComparisonP_CC=>Pfcmp0" + | Pcmpimm _ _ => "ArithComparisonP_CC=>Pcmpimm" + | Pcmnimm _ _ => "ArithComparisonP_CC=>Pcmnimm" + | Ptstimm _ _ => "ArithComparisonP_CC=>Ptstimm" + end. + +Definition string_of_name_ArithComparisonP_CV (n: arith_comparison_p) : pstring := + match n with + | Pfcmp0 _ => "ArithComparisonP_CV=>Pfcmp0" + | Pcmpimm _ _ => "ArithComparisonP_CV=>Pcmpimm" + | Pcmnimm _ _ => "ArithComparisonP_CV=>Pcmnimm" + | Ptstimm _ _ => "ArithComparisonP_CV=>Ptstimm" + end. + +Definition string_of_name_cset (c: testcond) : pstring := + match c with + | TCeq => "Cset=>TCeq" + | TCne => "Cset=>TCne" + | TChs => "Cset=>TChs" + | TClo => "Cset=>TClo" + | TCmi => "Cset=>TCmi" + | TCpl => "Cset=>TCpl" + | TChi => "Cset=>TChi" + | TCls => "Cset=>TCls" + | TCge => "Cset=>TCge" + | TClt => "Cset=>TClt" + | TCgt => "Cset=>TCgt" + | TCle => "Cset=>TCle" + end. + +Definition string_of_arith (op: arith_op): pstring := + match op with + | OArithP n => string_of_name_ArithP n + | OArithPP n => string_of_name_ArithPP n + | OArithPPP n => string_of_name_ArithPPP n + | OArithRR0R n => string_of_name_ArithRR0R n + | OArithRR0R_XZR n _ => string_of_name_ArithRR0R_XZR n + | OArithRR0 n => string_of_name_ArithRR0 n + | OArithRR0_XZR n _ => string_of_name_ArithRR0_XZR n + | OArithARRRR0 n => string_of_name_ArithARRRR0 n + | OArithARRRR0_XZR n _ => string_of_name_ArithARRRR0_XZR n + | OArithComparisonPP_CN n => string_of_name_ArithComparisonPP_CN n + | OArithComparisonPP_CZ n => string_of_name_ArithComparisonPP_CZ n + | OArithComparisonPP_CC n => string_of_name_ArithComparisonPP_CC n + | OArithComparisonPP_CV n => string_of_name_ArithComparisonPP_CV n + | OArithComparisonR0R_CN n _ => string_of_name_ArithComparisonR0R_CN n + | OArithComparisonR0R_CZ n _ => string_of_name_ArithComparisonR0R_CZ n + | OArithComparisonR0R_CC n _ => string_of_name_ArithComparisonR0R_CC n + | OArithComparisonR0R_CV n _ => string_of_name_ArithComparisonR0R_CV n + | OArithComparisonR0R_CN_XZR n _ _ => string_of_name_ArithComparisonR0R_CN_XZR n + | OArithComparisonR0R_CZ_XZR n _ _ => string_of_name_ArithComparisonR0R_CZ_XZR n + | OArithComparisonR0R_CC_XZR n _ _ => string_of_name_ArithComparisonR0R_CC_XZR n + | OArithComparisonR0R_CV_XZR n _ _ => string_of_name_ArithComparisonR0R_CV_XZR n + | OArithComparisonP_CN n => string_of_name_ArithComparisonP_CN n + | OArithComparisonP_CZ n => string_of_name_ArithComparisonP_CZ n + | OArithComparisonP_CC n => string_of_name_ArithComparisonP_CC n + | OArithComparisonP_CV n => string_of_name_ArithComparisonP_CV n + | Ocset c => string_of_name_cset c + | Ofmovi _ => "Ofmovi" + | Ofmovi_XZR _ => "Ofmovi_XZR" + | Ocsel _ => "Ocsel" + | Ofnmul _ => "Ofnmul" + end. + +Definition string_of_store (op: store_op) : pstring := + match op with + | Ostore1 _ _ => "Ostore1" + | Ostore2 _ _ => "Ostore2" + | OstoreU _ _ => "OstoreU" + end. + +Definition string_of_load (op: load_op) : pstring := + match op with + | Oload1 _ _ => "Oload1" + | Oload2 _ _ => "Oload2" + | OloadU _ _ => "OloadU" + end. + +Definition string_of_control (op: control_op) : pstring := + match op with + | Ob _ => "Ob" + | Obc _ _ => "Obc" + | Obl _ => "Obl" + | Obs _ => "Obs" + | Ocbnz _ _ => "Ocbnz" + | Ocbz _ _ => "Ocbz" + | Otbnz _ _ _ => "Otbnz" + | Otbz _ _ _ => "Otbz" + | Obtbl _ => "Obtbl" + | OIncremPC _ => "OIncremPC" + (*| Oj_l _ => "Oj_l"*) + (*| Ocbu _ _ => "Ocbu"*) + (*| Odiv => "Odiv"*) + (*| Odivu => "Odivu"*) + (*| Ojumptable _ => "Ojumptable"*) + | OError => "OError" + (*| OIncremPC _ => "OIncremPC"*) + end. + +Definition string_of_allocf (op: allocf_op) : pstring := + match op with + | OAllocf_SP _ _ => "OAllocf_SP" + | OAllocf_Mem _ _ => "OAllocf_Mem" + end. + +Definition string_of_freef (op: freef_op) : pstring := + match op with + | OFreef_SP _ _ => "OFreef_SP" + | OFreef_Mem _ _ => "OFreef_Mem" + end. + +Definition string_of_op (op: P.op): ?? pstring := + match op with + | Arith op => RET (string_of_arith op) + | Load op => RET (string_of_load op) + | Store op => RET (string_of_store op) + | Control op => RET (string_of_control op) + | Allocframe op => RET (string_of_allocf op) + | Freeframe op => RET (string_of_freef op) + | Loadsymbol _ => RET (Str "Loadsymbol") + | Constant _ => RET (Str "Constant") + | Cvtsw2x => RET (Str "Cvtsw2x") + | Cvtuw2x => RET (Str "Cvtuw2x") + | Cvtx2w => RET (Str "Cvtx2w") + (*| Fail => RET (Str "Fail")*) + end. +End SECT_BBLOCK_EQUIV. + +(** REWRITE RULES *) + +Definition is_constant (o: op): bool := + match o with (* TODO *) + | OArithP _ | OArithRR0_XZR _ _ | Ofmovi_XZR _ => true + | _ => false + end. + +Lemma is_constant_correct ge o: is_constant o = true -> op_eval ge o [] <> None. +Proof. + destruct o; simpl in * |- *; try congruence. + destruct op0; simpl in * |- *; try congruence; + destruct n; simpl in * |- *; try congruence; + unfold arith_eval; destruct ge; simpl in * |- *; try congruence. +Qed. + +Definition main_reduce (t: Terms.term):= RET (Terms.nofail is_constant t). + +Local Hint Resolve is_constant_correct: wlp. + +Lemma main_reduce_correct t: + WHEN main_reduce t ~> pt THEN Terms.match_pt t pt. +Proof. + wlp_simplify. +Qed. + +Definition reduce := {| Terms.result := main_reduce; Terms.result_correct := main_reduce_correct |}. + +Definition bblock_simu_test (verb: bool) (p1 p2: Asmblock.bblock) : ?? bool := + assert_same_builtin p1 p2;; + if verb then + IST.verb_bblock_simu_test reduce string_of_name string_of_op (trans_block p1) (trans_block p2) + else + IST.bblock_simu_test reduce (trans_block p1) (trans_block p2). + +Local Hint Resolve IST.bblock_simu_test_correct IST.verb_bblock_simu_test_correct: wlp. + +(** Main simulation (Impure) theorem *) +Theorem bblock_simu_test_correct verb p1 p2 : + WHEN bblock_simu_test verb p1 p2 ~> b THEN b=true -> forall ge fn lk, Asmblockprops.bblock_simu lk ge fn p1 p2. +Proof. + wlp_simplify; eapply bblock_simu_reduce with (Ge:={| _genv := ge; _fn := fn; _lk := lk |}); eauto. +Qed. +(*Qed.*) +Hint Resolve bblock_simu_test_correct: wlp. + +(** ** Coerce bblock_simu_test into a pure function (this is a little unsafe like all oracles in CompCert). *) + +Import UnsafeImpure. + +Definition pure_bblock_simu_test (verb: bool) (p1 p2: Asmblock.bblock): bool := + match unsafe_coerce (bblock_simu_test verb p1 p2) with + | Some b => b + | None => false + end. + +Theorem pure_bblock_simu_test_correct verb p1 p2 lk ge fn: pure_bblock_simu_test verb p1 p2 = true -> Asmblockprops.bblock_simu lk ge fn p1 p2. +Proof. + unfold pure_bblock_simu_test. + destruct (unsafe_coerce (bblock_simu_test verb p1 p2)) eqn: UNSAFE; try discriminate. + intros; subst. eapply bblock_simu_test_correct; eauto. + apply unsafe_coerce_not_really_correct; eauto. +Qed. + +Definition bblock_simub: Asmblock.bblock -> Asmblock.bblock -> bool := pure_bblock_simu_test true. + +Lemma bblock_simub_correct p1 p2 lk ge fn: bblock_simub p1 p2 = true -> Asmblockprops.bblock_simu lk ge fn p1 p2. +Proof. + eapply (pure_bblock_simu_test_correct true). +Qed. diff --git a/aarch64/Asmblockgen.v b/aarch64/Asmblockgen.v new file mode 100644 index 00000000..0a21485c --- /dev/null +++ b/aarch64/Asmblockgen.v @@ -0,0 +1,1258 @@ +(* *************************************************************) +(* *) +(* The Compcert verified compiler *) +(* *) +(* Sylvain Boulmé Grenoble-INP, VERIMAG *) +(* Léo Gourdin UGA, VERIMAG *) +(* Xavier Leroy INRIA Paris-Rocquencourt *) +(* David Monniaux CNRS, VERIMAG *) +(* Cyril Six Kalray *) +(* *) +(* Copyright Kalray. Copyright VERIMAG. All rights reserved. *) +(* This file is distributed under the terms of the INRIA *) +(* Non-Commercial License Agreement. *) +(* *) +(* *************************************************************) + +(** * Translation from Machblock to AArch64 assembly block language (Asmblock) + Inspired from the Mach->Asm pass of original Leroy's backend, but adapted to the block structure like the KVX backend. *) + +Require Import Recdef Coqlib Zwf Zbits. +Require Import Errors AST Integers Floats Op. +Require Import Locations Machblock Asm Asmblock. + +Local Open Scope string_scope. +Local Open Scope list_scope. +Local Open Scope error_monad_scope. + +(** Extracting integer or float registers. *) + +Definition ireg_of (r: mreg) : res ireg := + match preg_of r with + | IR irs => match irs with + | RR1 mr => OK mr + | _ => Error(msg "Asmgenblock.ireg_of") + end + | _ => Error(msg "Asmgenblock.iregsp_of") + end. + +Definition freg_of (r: mreg) : res freg := + match preg_of r with FR mr => OK mr | _ => Error(msg "Asmgenblock.freg_of") end. + +(** Recognition of immediate arguments for logical integer operations.*) + +(** Valid immediate arguments are repetitions of a bit pattern [B] + of length [e] = 2, 4, 8, 16, 32 or 64. + The bit pattern [B] must be of the form [0*1*0*] or [1*0*1*] + but must not be all zeros or all ones. *) + +(** The following automaton recognizes [0*1*0*|1*0*1*]. +<< + 0 1 0 + / \ / \ / \ + \ / \ / \ / + -0--> [B] --1--> [D] --0--> [F] + / + [A] + \ + -1--> [C] --0--> [E] --1--> [G] + / \ / \ / \ + \ / \ / \ / + 1 0 1 +>> +*) + +Module Automaton. + +Inductive state : Type := SA | SB | SC | SD | SE | SF | SG | Sbad. + +Definition start := SA. + +Definition next (s: state) (b: bool) := + match s, b with + | SA,false => SB | SA,true => SC + | SB,false => SB | SB,true => SD + | SC,false => SE | SC,true => SC + | SD,false => SF | SD,true => SD + | SE,false => SE | SE,true => SG + | SF,false => SF | SF,true => Sbad + | SG,false => Sbad | SG,true => SG + | Sbad,_ => Sbad + end. + +Definition accepting (s: state) := + match s with + | SA | SB | SC | SD | SE | SF | SG => true + | Sbad => false + end. + +Fixpoint run (len: nat) (s: state) (x: Z) : bool := + match len with + | Datatypes.O => accepting s + | Datatypes.S len => run len (next s (Z.odd x)) (Z.div2 x) + end. + +End Automaton. + +(** The following function determines the candidate length [e], + ensuring that [x] is a repetition [BB...B] + of a bit pattern [B] of length [e]. *) + +Definition logical_imm_length (x: Z) (sixtyfour: bool) : nat := + (** [test n] checks that the low [2n] bits of [x] are of the + form [BB], that is, two occurrences of the same [n] bits *) + let test (n: Z) : bool := + Z.eqb (Zzero_ext n x) (Zzero_ext n (Z.shiftr x n)) in + (** If [test n] fails, we know that the candidate length [e] is + at least [2n]. Hence we test with decreasing values of [n]: + 32, 16, 8, 4, 2. *) + if sixtyfour && negb (test 32) then 64%nat + else if negb (test 16) then 32%nat + else if negb (test 8) then 16%nat + else if negb (test 4) then 8%nat + else if negb (test 2) then 4%nat + else 2%nat. + +(** A valid logical immediate is +- neither [0] nor [-1]; +- composed of a repetition [BBBBB] of a bit-pattern [B] of length [e] +- the low [e] bits of the number, that is, [B], match [0*1*0*] or [1*0*1*]. +*) + +Definition is_logical_imm32 (x: int) : bool := + negb (Int.eq x Int.zero) && negb (Int.eq x Int.mone) && + Automaton.run (logical_imm_length (Int.unsigned x) false) + Automaton.start (Int.unsigned x). + +Definition is_logical_imm64 (x: int64) : bool := + negb (Int64.eq x Int64.zero) && negb (Int64.eq x Int64.mone) && + Automaton.run (logical_imm_length (Int64.unsigned x) true) + Automaton.start (Int64.unsigned x). + +(** Arithmetic immediates are 12-bit unsigned numbers, possibly shifted left 12 bits *) + +Definition is_arith_imm32 (x: int) : bool := + Int.eq x (Int.zero_ext 12 x) + || Int.eq x (Int.shl (Int.zero_ext 12 (Int.shru x (Int.repr 12))) (Int.repr 12)). + +Definition is_arith_imm64 (x: int64) : bool := + Int64.eq x (Int64.zero_ext 12 x) + || Int64.eq x (Int64.shl (Int64.zero_ext 12 (Int64.shru x (Int64.repr 12))) (Int64.repr 12)). + +Program Definition single_basic (bi: basic): bblock := + {| header := nil; body:= bi::nil; exit := None |}. + +(* insert [bi] at the head of [k] *) +Program Definition insert_basic (bi: basic) (k:bblocks): bblocks := + match k with + | bb::k' => + match bb.(header) with + | nil => {| header := nil; body := bi :: (body bb); exit := exit bb |}::k' + | _ => (single_basic bi)::k + end + | _ => (single_basic bi)::k + end. + +Notation "bi ::b k" := (insert_basic bi k) (at level 49, right associativity). + +(* insert [ctl] at the head of [k] *) +Program Definition insert_ctl (ctl: control) (k:bblocks): bblocks := + {| header := nil; body := nil; exit := Some ctl |}::k. + +Notation "ctl ::c k" := (insert_ctl ctl k) (at level 49, right associativity). + +(* TODO: Coercions to move in Asmblock ? *) +Coercion PArithP: arith_p >-> Funclass. +Coercion PArithPP: arith_pp >-> Funclass. +Coercion PArithPPP: arith_ppp >-> Funclass. +Coercion PArithRR0: arith_rr0 >-> Funclass. +Coercion PArithRR0R: arith_rr0r >-> Funclass. +Coercion PArithARRRR0: arith_arrrr0 >-> Funclass. +Coercion PArithComparisonP: arith_comparison_p >-> Funclass. +Coercion PArithComparisonPP: arith_comparison_pp >-> Funclass. +Coercion PArithComparisonR0R: arith_comparison_r0r >-> Funclass. +Coercion PArith: ar_instruction >-> basic. + +Definition bcode := list basic. + +Notation "i ::bi k" := (cons (A:=basic) i k) (at level 49, right associativity). +(* NB: this notation helps the Coq typechecker to infer coercion [PArith] in [bcode] expressions *) +(** Alignment check for symbols *) + +Parameter symbol_is_aligned : ident -> Z -> bool. +(** [symbol_is_aligned id sz] checks whether the symbol [id] is [sz] aligned *) + +(***************************************************************************************) + +(** Decompose integer literals into 16-bit fragments *) + +Fixpoint decompose_int (N: nat) (n p: Z) {struct N} : list (Z * Z) := + match N with + | Datatypes.O => nil + | Datatypes.S N => + let frag := Zzero_ext 16 (Z.shiftr n p) in + if Z.eqb frag 0 then + decompose_int N n (p + 16) + else + (frag, p) :: decompose_int N (Z.ldiff n (Z.shiftl 65535 p)) (p + 16) + end. + +Definition negate_decomposition (l: list (Z * Z)) := + List.map (fun np => (Z.lxor (fst np) 65535, snd np)) l. + +Definition loadimm_k (sz: isize) (rd: ireg) (l: list (Z * Z)) (k: bcode) : bcode := + List.fold_right (fun np k => Pmovk sz (fst np) (snd np) rd rd ::bi k) k l. + +Definition loadimm_z (sz: isize) (rd: ireg) (l: list (Z * Z)) (k: bcode) : bcode := + match l with + | nil => Pmovz sz 0 0 rd ::bi k + | (n1, p1) :: l => (Pmovz sz n1 p1 rd) ::bi loadimm_k sz rd l k + end. + +Definition loadimm_n (sz: isize) (rd: ireg) (l: list (Z * Z)) (k: bcode) : bcode := + match l with + | nil => Pmovn sz 0 0 rd ::bi k + | (n1, p1) :: l => Pmovn sz n1 p1 rd ::bi loadimm_k sz rd (negate_decomposition l) k + end. + +Definition loadimm (sz: isize) (rd: ireg) (n: Z) (k: bcode) : bcode := + let N := match sz with W => 2%nat | X => 4%nat end in + let dz := decompose_int N n 0 in + let dn := decompose_int N (Z.lnot n) 0 in + if Nat.leb (List.length dz) (List.length dn) + then loadimm_z sz rd dz k + else loadimm_n sz rd dn k. + +Definition loadimm32 (rd: ireg) (n: int) (k: bcode) : bcode := + if is_logical_imm32 n + then Porrimm W (Int.unsigned n) rd XZR ::bi k + else loadimm W rd (Int.unsigned n) k. + +Definition loadimm64 (rd: ireg) (n: int64) (k: bcode) : bcode := + if is_logical_imm64 n + then Porrimm X (Int64.unsigned n) rd XZR ::bi k + else loadimm X rd (Int64.unsigned n) k. + +(* STUB inspired from kvx/Asmblockgen.v and the reference aarch64/Asmgen.v (see below) *) + +Definition indexed_memory_access (insn: addressing -> basic) + (sz: Z) (base: iregsp) (ofs: ptrofs) (k: bblocks) : bblocks := + let ofs := Ptrofs.to_int64 ofs in + insn (ADimm base ofs) ::b k. (* STUB: change me ! See Asmgen below *) + +Definition indexed_memory_access_bc (insn: addressing -> basic) + (sz: Z) (base: iregsp) (ofs: ptrofs) (k: bcode) : bcode := + let ofs := Ptrofs.to_int64 ofs in + insn (ADimm base ofs) :: k. + +Definition loadind (base: iregsp) (ofs: ptrofs) (ty: typ) (dst: mreg) (k: bcode) := + match ty, preg_of dst with + | Tint, IR rd => OK (indexed_memory_access_bc (PLoad Pldrw rd) 4 base ofs k) + | Tlong, IR rd => OK (indexed_memory_access_bc (PLoad Pldrx rd) 8 base ofs k) + | Tsingle, FR rd => OK (indexed_memory_access_bc (PLoad Pldrs rd) 4 base ofs k) + | Tfloat, FR rd => OK (indexed_memory_access_bc (PLoad Pldrd rd) 8 base ofs k) + | Tany32, IR rd => OK (indexed_memory_access_bc (PLoad Pldrw_a rd) 4 base ofs k) + | Tany64, IR rd => OK (indexed_memory_access_bc (PLoad Pldrx_a rd) 8 base ofs k) + | Tany64, FR rd => OK (indexed_memory_access_bc (PLoad Pldrd_a rd) 8 base ofs k) + | _, _ => Error (msg "Asmgen.loadind") + end. + +Definition storeind (src: mreg) (base: iregsp) (ofs: ptrofs) (ty: typ) (k: bcode) := + match ty, preg_of src with + | Tint, IR rd => OK (indexed_memory_access_bc (PStore Pstrw rd) 4 base ofs k) + | Tlong, IR rd => OK (indexed_memory_access_bc (PStore Pstrx rd) 8 base ofs k) + | Tsingle, FR rd => OK (indexed_memory_access_bc (PStore Pstrs rd) 4 base ofs k) + | Tfloat, FR rd => OK (indexed_memory_access_bc (PStore Pstrd rd) 8 base ofs k) + | Tany32, IR rd => OK (indexed_memory_access_bc (PStore Pstrw_a rd) 4 base ofs k) + | Tany64, IR rd => OK (indexed_memory_access_bc (PStore Pstrx_a rd) 8 base ofs k) + | Tany64, FR rd => OK (indexed_memory_access_bc (PStore Pstrd_a rd) 8 base ofs k) + | _, _ => Error (msg "Asmgen.storeind") + end. + +Definition loadptr (base: iregsp) (ofs: ptrofs) (dst: ireg) (k: bblocks): bblocks := + indexed_memory_access (PLoad Pldrx dst) 8 base ofs k. + +Definition loadptr_bc (base: iregsp) (ofs: ptrofs) (dst: ireg) (k: bcode): bcode := + indexed_memory_access_bc (PLoad Pldrx dst) 8 base ofs k. + +Definition storeptr (src: ireg) (base: iregsp) (ofs: ptrofs) (k: bblocks): bblocks := + indexed_memory_access (PStore Pstrx src) 8 base ofs k. + +(*Definition storeptr_bc (src: ireg) (base: iregsp) (ofs: ptrofs) (k: bcode): bcode :=*) + (*indexed_memory_access_bc (PStore Pstrx src) 8 base ofs k.*) + +(** Function epilogue *) + +(*Definition make_epilogue (f: Machblock.function) (k: bblocks) : bblocks :=*) + (*(* FIXME*) + (*Cannot be used because memcpy destroys X30;*) + (*issue being discussed with X. Leroy *)*) + (*(* if is_leaf_function f*) + (*then Pfreeframe f.(fn_stacksize) f.(fn_link_ofs) :: k*) + (*else*) loadptr XSP f.(fn_retaddr_ofs) RA*) + (*(Pfreeframe f.(fn_stacksize) f.(fn_link_ofs) ::b k).*) + +Definition make_epilogue (f: Machblock.function) : bcode := + loadptr_bc XSP f.(fn_retaddr_ofs) RA + (Pfreeframe f.(fn_stacksize) f.(fn_link_ofs)::nil). + +(** Add immediate *) + +Definition addimm_aux (insn: Z -> arith_pp) + (rd r1: iregsp) (n: Z) (k: bcode) := + let nlo := Zzero_ext 12 n in + let nhi := n - nlo in + if Z.eqb nhi 0 then + insn nlo rd r1 ::bi k + else if Z.eqb nlo 0 then + insn nhi rd r1 ::bi k + else + insn nhi rd r1 ::bi insn nlo rd rd ::bi k. + +Definition addimm32 (rd r1: ireg) (n: int) (k: bcode) : bcode := + let m := Int.neg n in + if Int.eq n (Int.zero_ext 24 n) then + addimm_aux (Paddimm W) rd r1 (Int.unsigned n) k + else if Int.eq m (Int.zero_ext 24 m) then + addimm_aux (Psubimm W) rd r1 (Int.unsigned m) k + else if Int.lt n Int.zero then + loadimm32 X16 m (Psub W SOnone rd r1 X16 ::bi k) + else + loadimm32 X16 n (Padd W SOnone rd r1 X16 ::bi k). + +Definition addimm64 (rd r1: iregsp) (n: int64) (k: bcode) : bcode := + let m := Int64.neg n in + if Int64.eq n (Int64.zero_ext 24 n) then + addimm_aux (Paddimm X) rd r1 (Int64.unsigned n) k + else if Int64.eq m (Int64.zero_ext 24 m) then + addimm_aux (Psubimm X) rd r1 (Int64.unsigned m) k + else if Int64.lt n Int64.zero then + loadimm64 X16 m (Psubext (EOuxtx Int.zero) rd r1 X16 ::bi k) + else + loadimm64 X16 n (Paddext (EOuxtx Int.zero) rd r1 X16 ::bi k). + +(** Logical immediate *) + +Definition logicalimm32 + (insn1: Z -> arith_rr0) + (insn2: shift_op -> arith_rr0r) + (rd r1: ireg) (n: int) (k: bcode) : bcode := + if is_logical_imm32 n + then insn1 (Int.unsigned n) rd r1 ::bi k + else loadimm32 X16 n (insn2 SOnone rd r1 X16 ::bi k). + +Definition logicalimm64 + (insn1: Z -> arith_rr0) + (insn2: shift_op -> arith_rr0r) + (rd r1: ireg) (n: int64) (k: bcode) : bcode := + if is_logical_imm64 n + then insn1 (Int64.unsigned n) rd r1 ::bi k + else loadimm64 X16 n (insn2 SOnone rd r1 X16 ::bi k). + +(** Sign- or zero-extended arithmetic *) + +Definition transl_extension (ex: extension) (a: int) : extend_op := + match ex with Xsgn32 => EOsxtw a | Xuns32 => EOuxtw a end. + +Definition move_extended_base + (rd: ireg) (r1: ireg) (ex: extension) (k: bcode) : bcode := + match ex with + | Xsgn32 => Pcvtsw2x rd r1 ::bi k + | Xuns32 => Pcvtuw2x rd r1 ::bi k + end. + +Definition move_extended + (rd: ireg) (r1: ireg) (ex: extension) (a: int) (k: bcode) : bcode := + if Int.eq a Int.zero then + move_extended_base rd r1 ex k + else + move_extended_base rd r1 ex (Padd X (SOlsl a) rd XZR rd ::bi k). + +Definition arith_extended + (insnX: extend_op -> arith_ppp) + (insnS: shift_op -> arith_rr0r) + (rd r1 r2: ireg) (ex: extension) (a: int) (k: bcode) : bcode := + if Int.ltu a (Int.repr 5) then + insnX (transl_extension ex a) rd r1 r2 ::bi k + else + move_extended_base X16 r2 ex (insnS (SOlsl a) rd r1 X16 ::bi k). + +(** Extended right shift *) + +Definition shrx32 (rd r1: ireg) (n: int) (k: bcode) : bcode := + if Int.eq n Int.zero then + Pmov rd r1 ::bi k + else + Porr W (SOasr (Int.repr 31)) X16 XZR r1 ::bi + Padd W (SOlsr (Int.sub Int.iwordsize n)) X16 r1 X16 ::bi + Porr W (SOasr n) rd XZR X16 ::bi k. + +Definition shrx64 (rd r1: ireg) (n: int) (k: bcode) : bcode := + if Int.eq n Int.zero then + Pmov rd r1 ::bi k + else + Porr X (SOasr (Int.repr 63)) X16 XZR r1 ::bi + Padd X (SOlsr (Int.sub Int64.iwordsize' n)) X16 r1 X16 ::bi + Porr X (SOasr n) rd XZR X16 ::bi k. + +(** Load the address [id + ofs] in [rd] *) + +Definition loadsymbol (rd: ireg) (id: ident) (ofs: ptrofs) (k: bcode) : bcode := + if Archi.pic_code tt then + if Ptrofs.eq ofs Ptrofs.zero then + Ploadsymbol rd id ::bi k + else + Ploadsymbol rd id :: addimm64 rd rd (Ptrofs.to_int64 ofs) k + else + Padrp id ofs rd ::bi Paddadr id ofs rd rd ::bi k. + +(** Translate a shifted operand *) + +Definition transl_shift (s: Op.shift) (a: int): Asm.shift_op := + match s with + | Slsl => SOlsl a + | Slsr => SOlsr a + | Sasr => SOasr a + | Sror => SOror a + end. + +(** Translation of a condition. Prepends to [k] the instructions + that evaluate the condition and leave its boolean result in one of + the bits of the condition register. The bit in question is + determined by the [crbit_for_cond] function. *) + +Definition transl_cond + (cond: condition) (args: list mreg) (k: bcode) := + match cond, args with + | (Ccomp c | Ccompu c), a1 :: a2 :: nil => + do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Pcmp W SOnone r1 r2 ::bi k) + | (Ccompshift c s a | Ccompushift c s a), a1 :: a2 :: nil => + do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Pcmp W (transl_shift s a) r1 r2 ::bi k) + | (Ccompimm c n | Ccompuimm c n), a1 :: nil => + do r1 <- ireg_of a1; + OK (if is_arith_imm32 n then + Pcmpimm W (Int.unsigned n) r1 ::bi k + else if is_arith_imm32 (Int.neg n) then + Pcmnimm W (Int.unsigned (Int.neg n)) r1 ::bi k + else + loadimm32 X16 n (Pcmp W SOnone r1 X16 ::bi k)) + | (Cmaskzero n | Cmasknotzero n), a1 :: nil => + do r1 <- ireg_of a1; + OK (if is_logical_imm32 n then + Ptstimm W (Int.unsigned n) r1 ::bi k + else + loadimm32 X16 n (Ptst W SOnone r1 X16 ::bi k)) + | (Ccompl c | Ccomplu c), a1 :: a2 :: nil => + do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Pcmp X SOnone r1 r2 ::bi k) + | (Ccomplshift c s a | Ccomplushift c s a), a1 :: a2 :: nil => + do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Pcmp X (transl_shift s a) r1 r2 ::bi k) + | (Ccomplimm c n | Ccompluimm c n), a1 :: nil => + do r1 <- ireg_of a1; + OK (if is_arith_imm64 n then + Pcmpimm X (Int64.unsigned n) r1 ::bi k + else if is_arith_imm64 (Int64.neg n) then + Pcmnimm X (Int64.unsigned (Int64.neg n)) r1 ::bi k + else + loadimm64 X16 n (Pcmp X SOnone r1 X16 ::bi k)) + | (Cmasklzero n | Cmasklnotzero n), a1 :: nil => + do r1 <- ireg_of a1; + OK (if is_logical_imm64 n then + Ptstimm X (Int64.unsigned n) r1 ::bi k + else + loadimm64 X16 n (Ptst X SOnone r1 X16 ::bi k)) + | Ccompf cmp, a1 :: a2 :: nil => + do r1 <- freg_of a1; do r2 <- freg_of a2; + OK (Pfcmp D r1 r2 ::bi k) + | Cnotcompf cmp, a1 :: a2 :: nil => + do r1 <- freg_of a1; do r2 <- freg_of a2; + OK (Pfcmp D r1 r2 ::bi k) + | Ccompfzero cmp, a1 :: nil => + do r1 <- freg_of a1; + OK (Pfcmp0 D r1 ::bi k) + | Cnotcompfzero cmp, a1 :: nil => + do r1 <- freg_of a1; + OK (Pfcmp0 D r1 ::bi k) + | Ccompfs cmp, a1 :: a2 :: nil => + do r1 <- freg_of a1; do r2 <- freg_of a2; + OK (Pfcmp S r1 r2 ::bi k) + | Cnotcompfs cmp, a1 :: a2 :: nil => + do r1 <- freg_of a1; do r2 <- freg_of a2; + OK (Pfcmp S r1 r2 ::bi k) + | Ccompfszero cmp, a1 :: nil => + do r1 <- freg_of a1; + OK (Pfcmp0 S r1 ::bi k) + | Cnotcompfszero cmp, a1 :: nil => + do r1 <- freg_of a1; + OK (Pfcmp0 S r1 ::bi k) + | _, _ => + Error(msg "Asmgenblock.transl_cond") + end. + +Definition cond_for_signed_cmp (cmp: comparison) := + match cmp with + | Ceq => TCeq + | Cne => TCne + | Clt => TClt + | Cle => TCle + | Cgt => TCgt + | Cge => TCge + end. + +Definition cond_for_unsigned_cmp (cmp: comparison) := + match cmp with + | Ceq => TCeq + | Cne => TCne + | Clt => TClo + | Cle => TCls + | Cgt => TChi + | Cge => TChs + end. + +Definition cond_for_float_cmp (cmp: comparison) := + match cmp with + | Ceq => TCeq + | Cne => TCne + | Clt => TCmi + | Cle => TCls + | Cgt => TCgt + | Cge => TCge + end. + +Definition cond_for_float_not_cmp (cmp: comparison) := + match cmp with + | Ceq => TCne + | Cne => TCeq + | Clt => TCpl + | Cle => TChi + | Cgt => TCle + | Cge => TClt + end. + +Definition cond_for_cond (cond: condition) := + match cond with + | Ccomp cmp => cond_for_signed_cmp cmp + | Ccompu cmp => cond_for_unsigned_cmp cmp + | Ccompshift cmp s a => cond_for_signed_cmp cmp + | Ccompushift cmp s a => cond_for_unsigned_cmp cmp + | Ccompimm cmp n => cond_for_signed_cmp cmp + | Ccompuimm cmp n => cond_for_unsigned_cmp cmp + | Cmaskzero n => TCeq + | Cmasknotzero n => TCne + | Ccompl cmp => cond_for_signed_cmp cmp + | Ccomplu cmp => cond_for_unsigned_cmp cmp + | Ccomplshift cmp s a => cond_for_signed_cmp cmp + | Ccomplushift cmp s a => cond_for_unsigned_cmp cmp + | Ccomplimm cmp n => cond_for_signed_cmp cmp + | Ccompluimm cmp n => cond_for_unsigned_cmp cmp + | Cmasklzero n => TCeq + | Cmasklnotzero n => TCne + | Ccompf cmp => cond_for_float_cmp cmp + | Cnotcompf cmp => cond_for_float_not_cmp cmp + | Ccompfzero cmp => cond_for_float_cmp cmp + | Cnotcompfzero cmp => cond_for_float_not_cmp cmp + | Ccompfs cmp => cond_for_float_cmp cmp + | Cnotcompfs cmp => cond_for_float_not_cmp cmp + | Ccompfszero cmp => cond_for_float_cmp cmp + | Cnotcompfszero cmp => cond_for_float_not_cmp cmp + end. + +(** Translation of a conditional branch. Prepends to [k] the instructions + that evaluate the condition and ranch to [lbl] if it holds. + We recognize some conditional branches that can be implemented + without setting then testing condition flags. *) + +Definition transl_cond_branch_default + (c: condition) (args: list mreg) (lbl: label) (k: bcode) : res (bcode*control) := + do ccode <- transl_cond c args k; + OK(ccode, PCtlFlow (Pbc (cond_for_cond c) lbl)). + +Definition transl_cond_branch + (c: condition) (args: list mreg) (lbl: label) (k: bcode) : res (bcode*control) := + match args, c with + | a1 :: nil, (Ccompimm Cne n | Ccompuimm Cne n) => + if Int.eq n Int.zero + then (do r1 <- ireg_of a1; OK (k, PCtlFlow (Pcbnz W r1 lbl))) + else transl_cond_branch_default c args lbl k + | a1 :: nil, (Ccompimm Ceq n | Ccompuimm Ceq n) => + if Int.eq n Int.zero + then (do r1 <- ireg_of a1; OK (k, PCtlFlow (Pcbz W r1 lbl))) + else transl_cond_branch_default c args lbl k + | a1 :: nil, (Ccomplimm Cne n | Ccompluimm Cne n) => + if Int64.eq n Int64.zero + then (do r1 <- ireg_of a1; OK (k, PCtlFlow (Pcbnz X r1 lbl))) + else transl_cond_branch_default c args lbl k + | a1 :: nil, (Ccomplimm Ceq n | Ccompluimm Ceq n) => + if Int64.eq n Int64.zero + then (do r1 <- ireg_of a1; OK (k, PCtlFlow (Pcbz X r1 lbl))) + else transl_cond_branch_default c args lbl k + | a1 :: nil, Cmaskzero n => + match Int.is_power2 n with + | Some bit => do r1 <- ireg_of a1; OK (k, PCtlFlow (Ptbz W r1 bit lbl)) + | None => transl_cond_branch_default c args lbl k + end + | a1 :: nil, Cmasknotzero n => + match Int.is_power2 n with + | Some bit => do r1 <- ireg_of a1; OK (k, PCtlFlow (Ptbnz W r1 bit lbl)) + | None => transl_cond_branch_default c args lbl k + end + | a1 :: nil, Cmasklzero n => + match Int64.is_power2' n with + | Some bit => do r1 <- ireg_of a1; OK (k, PCtlFlow (Ptbz X r1 bit lbl)) + | None => transl_cond_branch_default c args lbl k + end + | a1 :: nil, Cmasklnotzero n => + match Int64.is_power2' n with + | Some bit => do r1 <- ireg_of a1; OK (k, PCtlFlow (Ptbnz X r1 bit lbl)) + | None => transl_cond_branch_default c args lbl k + end + | _, _ => + transl_cond_branch_default c args lbl k + end. + +(** Translation of the arithmetic operation [r <- op(args)]. + The corresponding instructions are prepended to [k]. *) + +Definition transl_op + (op: operation) (args: list mreg) (res: mreg) (k: bcode) := + match op, args with + | Omove, a1 :: nil => + match preg_of res, preg_of a1 with + | IR r, IR a => OK (Pmov r a ::bi k) + | FR r, FR a => OK (Pfmov r a ::bi k) + | _ , _ => Error(msg "Asmgenblock.Omove") + end + | Ointconst n, nil => + do rd <- ireg_of res; + OK (loadimm32 rd n k) + | Olongconst n, nil => + do rd <- ireg_of res; + OK (loadimm64 rd n k) + | Ofloatconst f, nil => + do rd <- freg_of res; + OK (if Float.eq_dec f Float.zero + then Pfmovi D rd XZR ::bi k + else Pfmovimmd f rd ::bi k) + | Osingleconst f, nil => + do rd <- freg_of res; + OK (if Float32.eq_dec f Float32.zero + then Pfmovi S rd XZR ::bi k + else Pfmovimms f rd ::bi k) + | Oaddrsymbol id ofs, nil => + do rd <- ireg_of res; + OK (loadsymbol rd id ofs k) + | Oaddrstack ofs, nil => + do rd <- ireg_of res; + OK (addimm64 rd XSP (Ptrofs.to_int64 ofs) k) + (** 32-bit integer arithmetic *) + | Oshift s a, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (Porr W (transl_shift s a) rd XZR r1 ::bi k) + | Oadd, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Padd W SOnone rd r1 r2 ::bi k) + | Oaddshift s a, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Padd W (transl_shift s a) rd r1 r2 ::bi k) + | Oaddimm n, a1 :: nil => + do rd <- ireg_of res; do rs <- ireg_of a1; + OK (addimm32 rd rs n k) + | Oneg, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (Psub W SOnone rd XZR r1 ::bi k) + | Onegshift s a, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (Psub W (transl_shift s a) rd XZR r1 ::bi k) + | Osub, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Psub W SOnone rd r1 r2 ::bi k) + | Osubshift s a, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Psub W (transl_shift s a) rd r1 r2 ::bi k) + | Omul, a1 :: a2 :: nil => + do rd <- ireg_of res; do rs1 <- ireg_of a1; do rs2 <- ireg_of a2; + OK (Pmadd W rd rs1 rs2 XZR ::bi k) + | Omuladd, a1 :: a2 :: a3 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; do r3 <- ireg_of a3; + OK (Pmadd W rd r2 r3 r1 ::bi k) + | Omulsub, a1 :: a2 :: a3 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; do r3 <- ireg_of a3; + OK (Pmsub W rd r2 r3 r1 ::bi k) + | Odiv, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Psdiv W rd r1 r2 ::bi k) + | Odivu, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Pudiv W rd r1 r2 ::bi k) + | Oand, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Pand W SOnone rd r1 r2 ::bi k) + | Oandshift s a, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Pand W (transl_shift s a) rd r1 r2 ::bi k) + | Oandimm n, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (logicalimm32 (Pandimm W) (Pand W) rd r1 n k) + | Oor, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Porr W SOnone rd r1 r2 ::bi k) + | Oorshift s a, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Porr W (transl_shift s a) rd r1 r2 ::bi k) + | Oorimm n, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (logicalimm32 (Porrimm W) (Porr W) rd r1 n k) + | Oxor, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Peor W SOnone rd r1 r2 ::bi k) + | Oxorshift s a, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Peor W (transl_shift s a) rd r1 r2 ::bi k) + | Oxorimm n, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (logicalimm32 (Peorimm W) (Peor W) rd r1 n k) + | Onot, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (Porn W SOnone rd XZR r1 ::bi k) + | Onotshift s a, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (Porn W (transl_shift s a) rd XZR r1 ::bi k) + | Obic, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Pbic W SOnone rd r1 r2 ::bi k) + | Obicshift s a, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Pbic W (transl_shift s a) rd r1 r2 ::bi k) + | Oorn, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Porn W SOnone rd r1 r2 ::bi k) + | Oornshift s a, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Porn W (transl_shift s a) rd r1 r2 ::bi k) + | Oeqv, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Peon W SOnone rd r1 r2 ::bi k) + | Oeqvshift s a, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Peon W (transl_shift s a) rd r1 r2 ::bi k) + | Oshl, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Plslv W rd r1 r2 ::bi k) + | Oshr, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Pasrv W rd r1 r2 ::bi k) + | Oshru, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Plsrv W rd r1 r2 ::bi k) + | Oshrximm n, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (shrx32 rd r1 n k) + | Ozext s, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (Pubfiz W Int.zero s rd r1 ::bi k) + | Osext s, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (Psbfiz W Int.zero s rd r1 ::bi k) + | Oshlzext s a, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (Pubfiz W a (Z.min s (Int.zwordsize - Int.unsigned a)) rd r1 ::bi k) + | Oshlsext s a, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (Psbfiz W a (Z.min s (Int.zwordsize - Int.unsigned a)) rd r1 ::bi k) + | Ozextshr a s, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (Pubfx W a (Z.min s (Int.zwordsize - Int.unsigned a)) rd r1 ::bi k) + | Osextshr a s, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (Psbfx W a (Z.min s (Int.zwordsize - Int.unsigned a)) rd r1 ::bi k) + (** 64-bit integer arithmetic *) + | Oshiftl s a, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (Porr X (transl_shift s a) rd XZR r1 ::bi k) + | Oextend x a, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (move_extended rd r1 x a k) + (* [Omakelong] and [Ohighlong] should not occur *) + | Olowlong, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + assertion (ireg_eq rd r1); + OK (Pcvtx2w rd ::bi k) + | Oaddl, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Padd X SOnone rd r1 r2 ::bi k) + | Oaddlshift s a, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Padd X (transl_shift s a) rd r1 r2 ::bi k) + | Oaddlext x a, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (arith_extended Paddext (Padd X) rd r1 r2 x a k) + | Oaddlimm n, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (addimm64 rd r1 n k) + | Onegl, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (Psub X SOnone rd XZR r1 ::bi k) + | Oneglshift s a, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (Psub X (transl_shift s a) rd XZR r1 ::bi k) + | Osubl, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Psub X SOnone rd r1 r2 ::bi k) + | Osublshift s a, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Psub X (transl_shift s a) rd r1 r2 ::bi k) + | Osublext x a, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (arith_extended Psubext (Psub X) rd r1 r2 x a k) + | Omull, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Pmadd X rd r1 r2 XZR ::bi k) + | Omulladd, a1 :: a2 :: a3 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; do r3 <- ireg_of a3; + OK (Pmadd X rd r2 r3 r1 ::bi k) + | Omullsub, a1 :: a2 :: a3 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; do r3 <- ireg_of a3; + OK (Pmsub X rd r2 r3 r1 ::bi k) + | Omullhs, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Psmulh rd r1 r2 ::bi k) + | Omullhu, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Pumulh rd r1 r2 ::bi k) + | Odivl, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Psdiv X rd r1 r2 ::bi k) + | Odivlu, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Pudiv X rd r1 r2 ::bi k) + | Oandl, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Pand X SOnone rd r1 r2 ::bi k) + | Oandlshift s a, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Pand X (transl_shift s a) rd r1 r2 ::bi k) + | Oandlimm n, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (logicalimm64 (Pandimm X) (Pand X) rd r1 n k) + | Oorl, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Porr X SOnone rd r1 r2 ::bi k) + | Oorlshift s a, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Porr X (transl_shift s a) rd r1 r2 ::bi k) + | Oorlimm n, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (logicalimm64 (Porrimm X) (Porr X) rd r1 n k) + | Oxorl, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Peor X SOnone rd r1 r2 ::bi k) + | Oxorlshift s a, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Peor X (transl_shift s a) rd r1 r2 ::bi k) + | Oxorlimm n, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (logicalimm64 (Peorimm X) (Peor X) rd r1 n k) + | Onotl, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (Porn X SOnone rd XZR r1 ::bi k) + | Onotlshift s a, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (Porn X (transl_shift s a) rd XZR r1 ::bi k) + | Obicl, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Pbic X SOnone rd r1 r2 ::bi k) + | Obiclshift s a, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Pbic X (transl_shift s a) rd r1 r2 ::bi k) + | Oornl, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Porn X SOnone rd r1 r2 ::bi k) + | Oornlshift s a, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Porn X (transl_shift s a) rd r1 r2 ::bi k) + | Oeqvl, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Peon X SOnone rd r1 r2 ::bi k) + | Oeqvlshift s a, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Peon X (transl_shift s a) rd r1 r2 ::bi k) + | Oshll, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Plslv X rd r1 r2 ::bi k) + | Oshrl, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Pasrv X rd r1 r2 ::bi k) + | Oshrlu, a1 :: a2 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (Plsrv X rd r1 r2 ::bi k) + | Oshrlximm n, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (shrx64 rd r1 n k) + | Ozextl s, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (Pubfiz X Int.zero s rd r1 ::bi k) + | Osextl s, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (Psbfiz X Int.zero s rd r1 ::bi k) + | Oshllzext s a, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (Pubfiz X a (Z.min s (Int64.zwordsize - Int.unsigned a)) rd r1 ::bi k) + | Oshllsext s a, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (Psbfiz X a (Z.min s (Int64.zwordsize - Int.unsigned a)) rd r1 ::bi k) + | Ozextshrl a s, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (Pubfx X a (Z.min s (Int64.zwordsize - Int.unsigned a)) rd r1 ::bi k) + | Osextshrl a s, a1 :: nil => + do rd <- ireg_of res; do r1 <- ireg_of a1; + OK (Psbfx X a (Z.min s (Int64.zwordsize - Int.unsigned a)) rd r1 ::bi k) + (** 64-bit floating-point arithmetic *) + | Onegf, a1 :: nil => + do rd <- freg_of res; do rs <- freg_of a1; + OK (Pfneg D rd rs ::bi k) + | Oabsf, a1 :: nil => + do rd <- freg_of res; do rs <- freg_of a1; + OK (Pfabs D rd rs ::bi k) + | Oaddf, a1 :: a2 :: nil => + do rd <- freg_of res; do rs1 <- freg_of a1; do rs2 <- freg_of a2; + OK (Pfadd D rd rs1 rs2 ::bi k) + | Osubf, a1 :: a2 :: nil => + do rd <- freg_of res; do rs1 <- freg_of a1; do rs2 <- freg_of a2; + OK (Pfsub D rd rs1 rs2 ::bi k) + | Omulf, a1 :: a2 :: nil => + do rd <- freg_of res; do rs1 <- freg_of a1; do rs2 <- freg_of a2; + OK (Pfmul D rd rs1 rs2 ::bi k) + | Odivf, a1 :: a2 :: nil => + do rd <- freg_of res; do rs1 <- freg_of a1; do rs2 <- freg_of a2; + OK (Pfdiv D rd rs1 rs2 ::bi k) + (** 32-bit floating-point arithmetic *) + | Onegfs, a1 :: nil => + do rd <- freg_of res; do rs <- freg_of a1; + OK (Pfneg S rd rs ::bi k) + | Oabsfs, a1 :: nil => + do rd <- freg_of res; do rs <- freg_of a1; + OK (Pfabs S rd rs ::bi k) + | Oaddfs, a1 :: a2 :: nil => + do rd <- freg_of res; do rs1 <- freg_of a1; do rs2 <- freg_of a2; + OK (Pfadd S rd rs1 rs2 ::bi k) + | Osubfs, a1 :: a2 :: nil => + do rd <- freg_of res; do rs1 <- freg_of a1; do rs2 <- freg_of a2; + OK (Pfsub S rd rs1 rs2 ::bi k) + | Omulfs, a1 :: a2 :: nil => + do rd <- freg_of res; do rs1 <- freg_of a1; do rs2 <- freg_of a2; + OK (Pfmul S rd rs1 rs2 ::bi k) + | Odivfs, a1 :: a2 :: nil => + do rd <- freg_of res; do rs1 <- freg_of a1; do rs2 <- freg_of a2; + OK (Pfdiv S rd rs1 rs2 ::bi k) + | Osingleoffloat, a1 :: nil => + do rd <- freg_of res; do rs <- freg_of a1; + OK (Pfcvtsd rd rs ::bi k) + | Ofloatofsingle, a1 :: nil => + do rd <- freg_of res; do rs <- freg_of a1; + OK (Pfcvtds rd rs ::bi k) + (** Conversions between int and float *) + | Ointoffloat, a1 :: nil => + do rd <- ireg_of res; do rs <- freg_of a1; + OK (Pfcvtzs W D rd rs ::bi k) + | Ointuoffloat, a1 :: nil => + do rd <- ireg_of res; do rs <- freg_of a1; + OK (Pfcvtzu W D rd rs ::bi k) + | Ofloatofint, a1 :: nil => + do rd <- freg_of res; do rs <- ireg_of a1; + OK (Pscvtf D W rd rs ::bi k) + | Ofloatofintu, a1 :: nil => + do rd <- freg_of res; do rs <- ireg_of a1; + OK (Pucvtf D W rd rs ::bi k) + | Ointofsingle, a1 :: nil => + do rd <- ireg_of res; do rs <- freg_of a1; + OK (Pfcvtzs W S rd rs ::bi k) + | Ointuofsingle, a1 :: nil => + do rd <- ireg_of res; do rs <- freg_of a1; + OK (Pfcvtzu W S rd rs ::bi k) + | Osingleofint, a1 :: nil => + do rd <- freg_of res; do rs <- ireg_of a1; + OK (Pscvtf S W rd rs ::bi k) + | Osingleofintu, a1 :: nil => + do rd <- freg_of res; do rs <- ireg_of a1; + OK (Pucvtf S W rd rs ::bi k) + | Olongoffloat, a1 :: nil => + do rd <- ireg_of res; do rs <- freg_of a1; + OK (Pfcvtzs X D rd rs ::bi k) + | Olonguoffloat, a1 :: nil => + do rd <- ireg_of res; do rs <- freg_of a1; + OK (Pfcvtzu X D rd rs ::bi k) + | Ofloatoflong, a1 :: nil => + do rd <- freg_of res; do rs <- ireg_of a1; + OK (Pscvtf D X rd rs ::bi k) + | Ofloatoflongu, a1 :: nil => + do rd <- freg_of res; do rs <- ireg_of a1; + OK (Pucvtf D X rd rs ::bi k) + | Olongofsingle, a1 :: nil => + do rd <- ireg_of res; do rs <- freg_of a1; + OK (Pfcvtzs X S rd rs ::bi k) + | Olonguofsingle, a1 :: nil => + do rd <- ireg_of res; do rs <- freg_of a1; + OK (Pfcvtzu X S rd rs ::bi k) + | Osingleoflong, a1 :: nil => + do rd <- freg_of res; do rs <- ireg_of a1; + OK (Pscvtf S X rd rs ::bi k) + | Osingleoflongu, a1 :: nil => + do rd <- freg_of res; do rs <- ireg_of a1; + OK (Pucvtf S X rd rs ::bi k) + (** Boolean tests *) + | Ocmp c, _ => + do rd <- ireg_of res; + transl_cond c args (Pcset rd (cond_for_cond c) ::bi k) + (** Conditional move *) + | Osel cmp ty, a1 :: a2 :: args => + match preg_of res with + | IR r => + do r1 <- ireg_of a1; do r2 <- ireg_of a2; + transl_cond cmp args (Pcsel r r1 r2 (cond_for_cond cmp) ::bi k) + | FR r => + do r1 <- freg_of a1; do r2 <- freg_of a2; + transl_cond cmp args (Pcsel r r1 r2 (cond_for_cond cmp) ::bi k) + | _ => + Error(msg "Asmgenblock.Osel") + end + | _, _ => Error(msg "Asmgenblock.transl_op") + end. + +(** Translation of addressing modes *) + +Definition offset_representable (sz: Z) (ofs: int64) : bool := + let isz := Int64.repr sz in + (** either unscaled 9-bit signed *) + Int64.eq ofs (Int64.sign_ext 9 ofs) || + (** or scaled 12-bit unsigned *) + (Int64.eq (Int64.modu ofs isz) Int64.zero + && Int64.ltu ofs (Int64.shl isz (Int64.repr 12))). + +Definition transl_addressing (sz: Z) (addr: Op.addressing) (args: list mreg) + (insn: Asm.addressing -> basic) (k: bcode) : res bcode := + match addr, args with + | Aindexed ofs, a1 :: nil => + do r1 <- ireg_of a1; + if offset_representable sz ofs then + OK (insn (ADimm r1 ofs) ::bi k) + else + OK (loadimm64 X16 ofs (insn (ADreg r1 X16) ::bi k)) + | Aindexed2, a1 :: a2 :: nil => + do r1 <- ireg_of a1; do r2 <- ireg_of a2; + OK (insn (ADreg r1 r2) ::bi k) + | Aindexed2shift a, a1 :: a2 :: nil => + do r1 <- ireg_of a1; do r2 <- ireg_of a2; + if Int.eq a Int.zero then + OK (insn (ADreg r1 r2) ::bi k) + else if Int.eq (Int.shl Int.one a) (Int.repr sz) then + OK (insn (ADlsl r1 r2 a) ::bi k) + else + OK (Padd X (SOlsl a) X16 r1 r2 ::bi insn (ADimm X16 Int64.zero) ::bi k) + | Aindexed2ext x a, a1 :: a2 :: nil => + do r1 <- ireg_of a1; do r2 <- ireg_of a2; + if Int.eq a Int.zero || Int.eq (Int.shl Int.one a) (Int.repr sz) then + OK (insn (match x with Xsgn32 => ADsxt r1 r2 a + | Xuns32 => ADuxt r1 r2 a end) ::bi k) + else + OK (arith_extended Paddext (Padd X) X16 r1 r2 x a + (insn (ADimm X16 Int64.zero) ::bi k)) + | Aglobal id ofs, nil => + assertion (negb (Archi.pic_code tt)); + if Ptrofs.eq (Ptrofs.modu ofs (Ptrofs.repr sz)) Ptrofs.zero && symbol_is_aligned id sz + then OK (Padrp id ofs X16 ::bi insn (ADadr X16 id ofs) ::bi k) + else OK (loadsymbol X16 id ofs (insn (ADimm X16 Int64.zero) ::bi k)) + | Ainstack ofs, nil => + let ofs := Ptrofs.to_int64 ofs in + if offset_representable sz ofs then + OK (insn (ADimm XSP ofs) ::bi k) + else + OK (loadimm64 X16 ofs (insn (ADreg XSP X16) ::bi k)) + | _, _ => + Error(msg "Asmgen.transl_addressing") + end. + +(** Translation of loads and stores *) + +Definition transl_load (chunk: memory_chunk) (addr: Op.addressing) + (args: list mreg) (dst: mreg) (k: bcode) : res bcode := + match chunk with + | Mint8unsigned => + do rd <- ireg_of dst; transl_addressing 1 addr args (PLoad (Pldrb W) rd) k + | Mint8signed => + do rd <- ireg_of dst; transl_addressing 1 addr args (PLoad (Pldrsb W) rd) k + | Mint16unsigned => + do rd <- ireg_of dst; transl_addressing 2 addr args (PLoad (Pldrh W) rd) k + | Mint16signed => + do rd <- ireg_of dst; transl_addressing 2 addr args (PLoad (Pldrsh W) rd) k + | Mint32 => + do rd <- ireg_of dst; transl_addressing 4 addr args (PLoad Pldrw rd) k + | Mint64 => + do rd <- ireg_of dst; transl_addressing 8 addr args (PLoad Pldrx rd) k + | Mfloat32 => + do rd <- freg_of dst; transl_addressing 4 addr args (PLoad Pldrs rd) k + | Mfloat64 => + do rd <- freg_of dst; transl_addressing 8 addr args (PLoad Pldrd rd) k + | Many32 => + do rd <- ireg_of dst; transl_addressing 4 addr args (PLoad Pldrw_a rd) k + | Many64 => + do rd <- ireg_of dst; transl_addressing 8 addr args (PLoad Pldrx_a rd) k + end. + +Definition transl_store (chunk: memory_chunk) (addr: Op.addressing) + (args: list mreg) (src: mreg) (k: bcode) : res bcode := + match chunk with + | Mint8unsigned | Mint8signed => + do r1 <- ireg_of src; transl_addressing 1 addr args (PStore Pstrb r1) k + | Mint16unsigned | Mint16signed => + do r1 <- ireg_of src; transl_addressing 2 addr args (PStore Pstrh r1) k + | Mint32 => + do r1 <- ireg_of src; transl_addressing 4 addr args (PStore Pstrw r1) k + | Mint64 => + do r1 <- ireg_of src; transl_addressing 8 addr args (PStore Pstrx r1) k + | Mfloat32 => + do r1 <- freg_of src; transl_addressing 4 addr args (PStore Pstrs r1) k + | Mfloat64 => + do r1 <- freg_of src; transl_addressing 8 addr args (PStore Pstrd r1) k + | Many32 => + do r1 <- ireg_of src; transl_addressing 4 addr args (PStore Pstrw_a r1) k + | Many64 => + do r1 <- ireg_of src; transl_addressing 8 addr args (PStore Pstrx_a r1) k + end. + +(** Translation of a Machblock instruction. *) + +Definition transl_instr_basic (f: Machblock.function) (i: Machblock.basic_inst) + (ep: bool) (k: bcode) := + match i with + | MBgetstack ofs ty dst => + loadind XSP ofs ty dst k + | MBsetstack src ofs ty => + storeind src XSP ofs ty k + | MBgetparam ofs ty dst => + do c <- loadind X29 ofs ty dst k; + OK (if ep then c else loadptr_bc XSP f.(fn_link_ofs) X29 c) + | MBop op args res => + transl_op op args res k + | MBload _ chunk addr args dst => + transl_load chunk addr args dst k + | MBstore chunk addr args src => + transl_store chunk addr args src k + end. + +(** Translation of a code sequence *) + +Definition it1_is_parent (before: bool) (i: Machblock.basic_inst) : bool := + match i with + (*| MBgetstack ofs ty dst => before && negb (mreg_eq dst R29)*) + | MBsetstack src ofs ty => before + | MBgetparam ofs ty dst => negb (mreg_eq dst R29) + | MBop op args res => before && negb (mreg_eq res R29) + (*| MBload trapping_mode chunk addr args dst => before && negb (mreg_eq dst R29)*) + | _ => false + end. + +Fixpoint transl_basic_code (f: Machblock.function) (il: list Machblock.basic_inst) (it1p: bool) (k: bcode):= + match il with + | nil => OK (k) + | i1 :: il' => + do k1 <- transl_basic_code f il' (it1_is_parent it1p i1) k; + transl_instr_basic f i1 it1p k1 + end. + +(** Translation of a whole function. Note that we must check + that the generated code contains less than [2^64] instructions, + otherwise the offset part of the [PC] code pointer could wrap + around, leading to incorrect executions. *) + +(* NB Sylvain: this issue with PExpand seems specific to kvx -- and not necessary here *) +(* gen_bblocks can generate two bblocks if the ctl is a PExpand (since the PExpand must be alone in its block) *) +(* +Program Definition gen_bblocks (hd: list label) (c: bcode) (ctl: list instruction) := + match (extract_ctl ctl) with + | None => + (* XXX Que faire du Pnop ? *) + match c with + | nil => {| header := hd; body := Pnop::nil; exit := None |} :: nil + | i :: c => {| header := hd; body := ((i :: c) ++ extract_basic ctl); exit := None |} :: nil + end + (*| Some (i) =>*) + (*match c with*) + (*| nil => {| header := hd; body := nil; exit := Some (PExpand (Pbuiltin ef args res)) |} :: nil*) + (*| _ => {| header := hd; body := c; exit := None |} *) + (*:: {| header := nil; body := nil; exit := Some (PExpand (Pbuiltin ef args res)) |} :: nil*) + (*end*) + | Some ex => {| header := hd; body := (c ++ extract_basic ctl); exit := Some ex |} :: nil + end +. +*) + +(* XXX: the simulation proof may be complex with this pattern. We may fix this later *) +Program Definition cons_bblocks (ll: list label) (bdy: list basic) (ex: option control) (k:bblocks): bblocks := + match non_empty_bblockb bdy ex with + | true => {| header := ll; body:= bdy; exit := ex |}::k + | false => k + end. +Obligation 1. + rewrite <- Heq_anonymous. constructor. +Qed. + +Definition transl_control (f: Machblock.function) (ctl: control_flow_inst) : res (bcode*control) := + match ctl with + | MBcall sig (inl r) => do r1 <- ireg_of r; + OK (nil, PCtlFlow (Pblr r1 sig)) + | MBcall sig (inr symb) => OK (nil, PCtlFlow (Pbl symb sig)) + | MBtailcall sig (inr symb) => OK(make_epilogue f, PCtlFlow (Pbs symb sig)) + | MBtailcall sig (inl r) => do r1 <- ireg_of r; + OK (make_epilogue f, PCtlFlow (Pbr r1 sig)) + | MBbuiltin ef args res => OK (nil, Pbuiltin ef (List.map (map_builtin_arg dreg_of) args) (map_builtin_res dreg_of res)) + | MBgoto lbl => OK (nil, PCtlFlow (Pb lbl)) + | MBcond cond args lbl => transl_cond_branch cond args lbl nil + | MBreturn => OK (make_epilogue f, PCtlFlow (Pret RA)) + | MBjumptable arg tbl => do r <- ireg_of arg; + OK (nil, PCtlFlow (Pbtbl r tbl)) + end. + +Definition transl_exit (f: Machblock.function) (ext: option control_flow_inst) : res (bcode*option control) := + match ext with + Some ctl => do (b,c) <- transl_control f ctl; OK (b, Some c) + | None => OK (nil, None) + end. + +Definition transl_block (f: Machblock.function) (fb: Machblock.bblock) (ep: bool) (k:bblocks): res (list bblock) := + let stub := false in (* TODO: FIXME *) + do (bdy, ex) <- transl_exit f fb.(Machblock.exit); + do bdy' <- transl_basic_code f fb.(Machblock.body) ep bdy; + OK (cons_bblocks fb.(Machblock.header) bdy' ex k) + . + +Fixpoint transl_blocks (f: Machblock.function) (lmb: Machblock.code) (ep: bool): res bblocks := + match lmb with + | nil => OK nil + | mb :: lmb => + do lb <- transl_blocks f lmb false; (* TODO: check [false] here *) + transl_block f mb (if Machblock.header mb then ep else false) lb (* TODO: check this *) + end. + (* OK (make_epilogue f ((Pret X0)::c nil)). (* STUB: TODO CHANGE ME ! *)*) + +(* Currently, we assume to be after the PseudoAsmblockproof.transf_program pass... *) +Program Definition make_prologue (f: Machblock.function) (k:bblocks) := + (*({| header := nil; body := Pallocframe f.(fn_stacksize) f.(fn_link_ofs) ::*) + (*storeptr_bc RA XSP f.(fn_retaddr_ofs) nil;*) + (*exit := None |} :: k).*) + Pallocframe f.(fn_stacksize) f.(fn_link_ofs) ::b + storeptr RA XSP f.(fn_retaddr_ofs) k. + +Definition transl_function (f: Machblock.function) : res Asmblock.function := + do lb <- transl_blocks f f.(Machblock.fn_code) true; + OK (mkfunction f.(Machblock.fn_sig) + (make_prologue f lb)). + +Definition transf_fundef (f: Machblock.fundef) : res Asmblock.fundef := + transf_partial_fundef transl_function f. (* TODO: do we need to check the size here ? (issue only in proofs) *) + +Definition transf_program (p: Machblock.program) : res Asmblock.program := + transform_partial_program transf_fundef p. + diff --git a/aarch64/Asmblockgenproof.v b/aarch64/Asmblockgenproof.v new file mode 100644 index 00000000..41082772 --- /dev/null +++ b/aarch64/Asmblockgenproof.v @@ -0,0 +1,1158 @@ +(** Correctness proof for aarch64/Asmblock generation: main proof. +CURRENTLY A STUB ! +*) + +Require Import Coqlib Errors. +Require Import Integers Floats AST Linking. +Require Import Values Memory Events Globalenvs Smallstep. +Require Import Op Locations Machblock Conventions PseudoAsmblock Asmblock IterList. +Require Import PseudoAsmblockproof Asmblockgen. + +Module MB := Machblock. +Module AB := Asmblock. + +Definition match_prog (p: MB.program) (tp: AB.program) := + match_program (fun _ f tf => transf_fundef f = OK tf) eq p tp. + +Lemma transf_program_match: + forall p tp, transf_program p = OK tp -> match_prog p tp. +Proof. + intros. eapply match_transform_partial_program; eauto. +Qed. + +Parameter next: MB.function -> Z -> Z. + +Section PRESERVATION. + +Lemma next_progress: forall (f:MB.function) (pos:Z), (pos < (next f pos))%Z. +Admitted. + +Variable lk: aarch64_linker. +Variable prog: Machblock.program. +Variable tprog: Asmblock.program. +Hypothesis TRANSF: match_prog prog tprog. +Let ge := Genv.globalenv prog. +Let tge := Genv.globalenv tprog. + + +Hypothesis symbol_high_low: forall (id: ident) (ofs: ptrofs), + Val.addl (symbol_high lk id ofs) (symbol_low lk id ofs) = Genv.symbol_address tge id ofs. + +Lemma functions_bound_max_pos: forall fb f, + Genv.find_funct_ptr ge fb = Some (Internal f) -> + (max_pos next f) <= Ptrofs.max_unsigned. +Admitted. + + + +Lemma transf_program_correct: + forward_simulation (PseudoAsmblock.semantics next prog) (AB.semantics lk tprog). +Admitted. + +End PRESERVATION. + + +(* ORIGINAL aarch64/Asmgenproof file that needs to be adapted + +(* *********************************************************************) +(* *) +(* The Compcert verified compiler *) +(* *) +(* Xavier Leroy, Collège de France and INRIA Paris *) +(* *) +(* Copyright Institut National de Recherche en Informatique et en *) +(* Automatique. All rights reserved. This file is distributed *) +(* under the terms of the INRIA Non-Commercial License Agreement. *) +(* *) +(* *********************************************************************) + +(** Correctness proof for AArch64 code generation. *) + +Require Import Coqlib Errors. +Require Import Integers Floats AST Linking. +Require Import Values Memory Events Globalenvs Smallstep. +Require Import Op Locations Mach Conventions Asm. +Require Import Asmgen Asmgenproof0 Asmgenproof1. + +Definition match_prog (p: Mach.program) (tp: Asm.program) := + match_program (fun _ f tf => transf_fundef f = OK tf) eq p tp. + +Lemma transf_program_match: + forall p tp, transf_program p = OK tp -> match_prog p tp. +Proof. + intros. eapply match_transform_partial_program; eauto. +Qed. + +Section PRESERVATION. + +Variable prog: Mach.program. +Variable tprog: Asm.program. +Hypothesis TRANSF: match_prog prog tprog. +Let ge := Genv.globalenv prog. +Let tge := Genv.globalenv tprog. + +Lemma symbols_preserved: + forall (s: ident), Genv.find_symbol tge s = Genv.find_symbol ge s. +Proof (Genv.find_symbol_match TRANSF). + +Lemma senv_preserved: + Senv.equiv ge tge. +Proof (Genv.senv_match TRANSF). + +Lemma functions_translated: + forall b f, + Genv.find_funct_ptr ge b = Some f -> + exists tf, + Genv.find_funct_ptr tge b = Some tf /\ transf_fundef f = OK tf. +Proof (Genv.find_funct_ptr_transf_partial TRANSF). + +Lemma functions_transl: + forall fb f tf, + Genv.find_funct_ptr ge fb = Some (Internal f) -> + transf_function f = OK tf -> + Genv.find_funct_ptr tge fb = Some (Internal tf). +Proof. + intros. exploit functions_translated; eauto. intros [tf' [A B]]. + monadInv B. rewrite H0 in EQ; inv EQ; auto. +Qed. + +(** * Properties of control flow *) + +Lemma transf_function_no_overflow: + forall f tf, + transf_function f = OK tf -> list_length_z tf.(fn_code) <= Ptrofs.max_unsigned. +Proof. + intros. monadInv H. destruct (zlt Ptrofs.max_unsigned (list_length_z x.(fn_code))); inv EQ0. + omega. +Qed. + +Lemma exec_straight_exec: + forall fb f c ep tf tc c' rs m rs' m', + transl_code_at_pc ge (rs PC) fb f c ep tf tc -> + exec_straight tge tf tc rs m c' rs' m' -> + plus step tge (State rs m) E0 (State rs' m'). +Proof. + intros. inv H. + eapply exec_straight_steps_1; eauto. + eapply transf_function_no_overflow; eauto. + eapply functions_transl; eauto. +Qed. + +Lemma exec_straight_at: + forall fb f c ep tf tc c' ep' tc' rs m rs' m', + transl_code_at_pc ge (rs PC) fb f c ep tf tc -> + transl_code f c' ep' = OK tc' -> + exec_straight tge tf tc rs m tc' rs' m' -> + transl_code_at_pc ge (rs' PC) fb f c' ep' tf tc'. +Proof. + intros. inv H. + exploit exec_straight_steps_2; eauto. + eapply transf_function_no_overflow; eauto. + eapply functions_transl; eauto. + intros [ofs' [PC' CT']]. + rewrite PC'. constructor; auto. +Qed. + +(** The following lemmas show that the translation from Mach to Asm + preserves labels, in the sense that the following diagram commutes: +<< + translation + Mach code ------------------------ Asm instr sequence + | | + | Mach.find_label lbl find_label lbl | + | | + v v + Mach code tail ------------------- Asm instr seq tail + translation +>> + The proof demands many boring lemmas showing that Asm constructor + functions do not introduce new labels. +*) + +Section TRANSL_LABEL. + +Remark loadimm_z_label: forall sz rd l k, tail_nolabel k (loadimm_z sz rd l k). +Proof. + intros; destruct l as [ | [n1 p1] l]; simpl; TailNoLabel. + induction l as [ | [n p] l]; simpl; TailNoLabel. +Qed. + +Remark loadimm_n_label: forall sz rd l k, tail_nolabel k (loadimm_n sz rd l k). +Proof. + intros; destruct l as [ | [n1 p1] l]; simpl; TailNoLabel. + induction l as [ | [n p] l]; simpl; TailNoLabel. +Qed. + +Remark loadimm_label: forall sz rd n k, tail_nolabel k (loadimm sz rd n k). +Proof. + unfold loadimm; intros. destruct Nat.leb; [apply loadimm_z_label|apply loadimm_n_label]. +Qed. +Hint Resolve loadimm_label: labels. + +Remark loadimm32_label: forall r n k, tail_nolabel k (loadimm32 r n k). +Proof. + unfold loadimm32; intros. destruct (is_logical_imm32 n); TailNoLabel. +Qed. +Hint Resolve loadimm32_label: labels. + +Remark loadimm64_label: forall r n k, tail_nolabel k (loadimm64 r n k). +Proof. + unfold loadimm64; intros. destruct (is_logical_imm64 n); TailNoLabel. +Qed. +Hint Resolve loadimm64_label: labels. + +Remark addimm_aux: forall insn rd r1 n k, + (forall rd r1 n, nolabel (insn rd r1 n)) -> + tail_nolabel k (addimm_aux insn rd r1 n k). +Proof. + unfold addimm_aux; intros. + destruct Z.eqb. TailNoLabel. destruct Z.eqb; TailNoLabel. +Qed. + +Remark addimm32_label: forall rd r1 n k, tail_nolabel k (addimm32 rd r1 n k). +Proof. + unfold addimm32; intros. + destruct Int.eq. apply addimm_aux; intros; red; auto. + destruct Int.eq. apply addimm_aux; intros; red; auto. + destruct Int.lt; eapply tail_nolabel_trans; TailNoLabel. +Qed. +Hint Resolve addimm32_label: labels. + +Remark addimm64_label: forall rd r1 n k, tail_nolabel k (addimm64 rd r1 n k). +Proof. + unfold addimm64; intros. + destruct Int64.eq. apply addimm_aux; intros; red; auto. + destruct Int64.eq. apply addimm_aux; intros; red; auto. + destruct Int64.lt; eapply tail_nolabel_trans; TailNoLabel. +Qed. +Hint Resolve addimm64_label: labels. + +Remark logicalimm32_label: forall insn1 insn2 rd r1 n k, + (forall rd r1 n, nolabel (insn1 rd r1 n)) -> + (forall rd r1 r2 s, nolabel (insn2 rd r1 r2 s)) -> + tail_nolabel k (logicalimm32 insn1 insn2 rd r1 n k). +Proof. + unfold logicalimm32; intros. + destruct (is_logical_imm32 n). TailNoLabel. eapply tail_nolabel_trans; TailNoLabel. +Qed. + +Remark logicalimm64_label: forall insn1 insn2 rd r1 n k, + (forall rd r1 n, nolabel (insn1 rd r1 n)) -> + (forall rd r1 r2 s, nolabel (insn2 rd r1 r2 s)) -> + tail_nolabel k (logicalimm64 insn1 insn2 rd r1 n k). +Proof. + unfold logicalimm64; intros. + destruct (is_logical_imm64 n). TailNoLabel. eapply tail_nolabel_trans; TailNoLabel. +Qed. + +Remark move_extended_label: forall rd r1 ex a k, tail_nolabel k (move_extended rd r1 ex a k). +Proof. + unfold move_extended, move_extended_base; intros. destruct Int.eq, ex; TailNoLabel. +Qed. +Hint Resolve move_extended_label: labels. + +Remark arith_extended_label: forall insnX insnS rd r1 r2 ex a k, + (forall rd r1 r2 x, nolabel (insnX rd r1 r2 x)) -> + (forall rd r1 r2 s, nolabel (insnS rd r1 r2 s)) -> + tail_nolabel k (arith_extended insnX insnS rd r1 r2 ex a k). +Proof. + unfold arith_extended; intros. destruct Int.ltu. + TailNoLabel. + destruct ex; simpl; TailNoLabel. +Qed. + +Remark loadsymbol_label: forall r id ofs k, tail_nolabel k (loadsymbol r id ofs k). +Proof. + intros; unfold loadsymbol. + destruct (Archi.pic_code tt); TailNoLabel. destruct Ptrofs.eq; TailNoLabel. +Qed. +Hint Resolve loadsymbol_label: labels. + +Remark transl_cond_label: forall cond args k c, + transl_cond cond args k = OK c -> tail_nolabel k c. +Proof. + unfold transl_cond; intros; destruct cond; TailNoLabel. +- destruct is_arith_imm32; TailNoLabel. destruct is_arith_imm32; TailNoLabel. eapply tail_nolabel_trans; TailNoLabel. +- destruct is_arith_imm32; TailNoLabel. destruct is_arith_imm32; TailNoLabel. eapply tail_nolabel_trans; TailNoLabel. +- destruct is_logical_imm32; TailNoLabel. eapply tail_nolabel_trans; TailNoLabel. +- destruct is_logical_imm32; TailNoLabel. eapply tail_nolabel_trans; TailNoLabel. +- destruct is_arith_imm64; TailNoLabel. destruct is_arith_imm64; TailNoLabel. eapply tail_nolabel_trans; TailNoLabel. +- destruct is_arith_imm64; TailNoLabel. destruct is_arith_imm64; TailNoLabel. eapply tail_nolabel_trans; TailNoLabel. +- destruct is_logical_imm64; TailNoLabel. eapply tail_nolabel_trans; TailNoLabel. +- destruct is_logical_imm64; TailNoLabel. eapply tail_nolabel_trans; TailNoLabel. +Qed. + +Remark transl_cond_branch_default_label: forall cond args lbl k c, + transl_cond_branch_default cond args lbl k = OK c -> tail_nolabel k c. +Proof. + unfold transl_cond_branch_default; intros. + eapply tail_nolabel_trans; [eapply transl_cond_label;eauto|TailNoLabel]. +Qed. +Hint Resolve transl_cond_branch_default_label: labels. + +Remark transl_cond_branch_label: forall cond args lbl k c, + transl_cond_branch cond args lbl k = OK c -> tail_nolabel k c. +Proof. + unfold transl_cond_branch; intros; destruct args; TailNoLabel; destruct cond; TailNoLabel. +- destruct c0; TailNoLabel. +- destruct c0; TailNoLabel. +- destruct (Int.is_power2 n); TailNoLabel. +- destruct (Int.is_power2 n); TailNoLabel. +- destruct c0; TailNoLabel. +- destruct c0; TailNoLabel. +- destruct (Int64.is_power2' n); TailNoLabel. +- destruct (Int64.is_power2' n); TailNoLabel. +Qed. + +Remark transl_op_label: + forall op args r k c, + transl_op op args r k = OK c -> tail_nolabel k c. +Proof. + unfold transl_op; intros; destruct op; TailNoLabel. +- destruct (preg_of r); try discriminate; destruct (preg_of m); inv H; TailNoLabel. +- destruct (Float.eq_dec n Float.zero); TailNoLabel. +- destruct (Float32.eq_dec n Float32.zero); TailNoLabel. +- apply logicalimm32_label; unfold nolabel; auto. +- apply logicalimm32_label; unfold nolabel; auto. +- apply logicalimm32_label; unfold nolabel; auto. +- unfold shrx32. destruct (Int.eq _ _); try destruct (Int.eq _ _); TailNoLabel. +- apply arith_extended_label; unfold nolabel; auto. +- apply arith_extended_label; unfold nolabel; auto. +- apply logicalimm64_label; unfold nolabel; auto. +- apply logicalimm64_label; unfold nolabel; auto. +- apply logicalimm64_label; unfold nolabel; auto. +- unfold shrx64. destruct (Int.eq _ _); try destruct (Int.eq _ _); TailNoLabel. +- eapply tail_nolabel_trans. eapply transl_cond_label; eauto. TailNoLabel. +- destruct (preg_of r); try discriminate; TailNoLabel; + (eapply tail_nolabel_trans; [eapply transl_cond_label; eauto | TailNoLabel]). +Qed. + +Remark transl_addressing_label: + forall sz addr args insn k c, + transl_addressing sz addr args insn k = OK c -> + (forall ad, nolabel (insn ad)) -> + tail_nolabel k c. +Proof. + unfold transl_addressing; intros; destruct addr; TailNoLabel; + eapply tail_nolabel_trans; TailNoLabel. + eapply tail_nolabel_trans. apply arith_extended_label; unfold nolabel; auto. TailNoLabel. +Qed. + +Remark transl_load_label: + forall trap chunk addr args dst k c, + transl_load trap chunk addr args dst k = OK c -> tail_nolabel k c. +Proof. + unfold transl_load; intros; destruct trap; try discriminate; destruct chunk; TailNoLabel; eapply transl_addressing_label; eauto; unfold nolabel; auto. +Qed. + +Remark transl_store_label: + forall chunk addr args src k c, + transl_store chunk addr args src k = OK c -> tail_nolabel k c. +Proof. + unfold transl_store; intros; destruct chunk; TailNoLabel; eapply transl_addressing_label; eauto; unfold nolabel; auto. +Qed. + +Remark indexed_memory_access_label: + forall insn sz base ofs k, + (forall ad, nolabel (insn ad)) -> + tail_nolabel k (indexed_memory_access insn sz base ofs k). +Proof. + unfold indexed_memory_access; intros. destruct offset_representable. + TailNoLabel. + eapply tail_nolabel_trans; TailNoLabel. +Qed. + +Remark loadind_label: + forall base ofs ty dst k c, + loadind base ofs ty dst k = OK c -> tail_nolabel k c. +Proof. + unfold loadind; intros. + destruct ty, (preg_of dst); inv H; apply indexed_memory_access_label; intros; exact I. +Qed. + +Remark storeind_label: + forall src base ofs ty k c, + storeind src base ofs ty k = OK c -> tail_nolabel k c. +Proof. + unfold storeind; intros. + destruct ty, (preg_of src); inv H; apply indexed_memory_access_label; intros; exact I. +Qed. + +Remark loadptr_label: + forall base ofs dst k, tail_nolabel k (loadptr base ofs dst k). +Proof. + intros. apply indexed_memory_access_label. unfold nolabel; auto. +Qed. + +Remark storeptr_label: + forall src base ofs k, tail_nolabel k (storeptr src base ofs k). +Proof. + intros. apply indexed_memory_access_label. unfold nolabel; auto. +Qed. + +Remark make_epilogue_label: + forall f k, tail_nolabel k (make_epilogue f k). +Proof. + unfold make_epilogue; intros. + (* FIXME destruct is_leaf_function. + { TailNoLabel. } *) + eapply tail_nolabel_trans. + apply loadptr_label. + TailNoLabel. +Qed. + +Lemma transl_instr_label: + forall f i ep k c, + transl_instr f i ep k = OK c -> + match i with Mlabel lbl => c = Plabel lbl :: k | _ => tail_nolabel k c end. +Proof. + unfold transl_instr; intros; destruct i; TailNoLabel. +- eapply loadind_label; eauto. +- eapply storeind_label; eauto. +- destruct ep. eapply loadind_label; eauto. + eapply tail_nolabel_trans. apply loadptr_label. eapply loadind_label; eauto. +- eapply transl_op_label; eauto. +- eapply transl_load_label; eauto. +- eapply transl_store_label; eauto. +- destruct s0; monadInv H; TailNoLabel. +- destruct s0; monadInv H; (eapply tail_nolabel_trans; [eapply make_epilogue_label|TailNoLabel]). +- eapply transl_cond_branch_label; eauto. +- eapply tail_nolabel_trans; [eapply make_epilogue_label|TailNoLabel]. +Qed. + +Lemma transl_instr_label': + forall lbl f i ep k c, + transl_instr f i ep k = OK c -> + find_label lbl c = if Mach.is_label lbl i then Some k else find_label lbl k. +Proof. + intros. exploit transl_instr_label; eauto. + destruct i; try (intros [A B]; apply B). + intros. subst c. simpl. auto. +Qed. + +Lemma transl_code_label: + forall lbl f c ep tc, + transl_code f c ep = OK tc -> + match Mach.find_label lbl c with + | None => find_label lbl tc = None + | Some c' => exists tc', find_label lbl tc = Some tc' /\ transl_code f c' false = OK tc' + end. +Proof. + induction c; simpl; intros. + inv H. auto. + monadInv H. rewrite (transl_instr_label' lbl _ _ _ _ _ EQ0). + generalize (Mach.is_label_correct lbl a). + destruct (Mach.is_label lbl a); intros. + subst a. simpl in EQ. exists x; auto. + eapply IHc; eauto. +Qed. + +Lemma transl_find_label: + forall lbl f tf, + transf_function f = OK tf -> + match Mach.find_label lbl f.(Mach.fn_code) with + | None => find_label lbl tf.(fn_code) = None + | Some c => exists tc, find_label lbl tf.(fn_code) = Some tc /\ transl_code f c false = OK tc + end. +Proof. + intros. monadInv H. destruct (zlt Ptrofs.max_unsigned (list_length_z x.(fn_code))); inv EQ0. + monadInv EQ. rewrite transl_code'_transl_code in EQ0. unfold fn_code. + simpl. destruct (storeptr_label X30 XSP (fn_retaddr_ofs f) x) as [A B]; rewrite B. + eapply transl_code_label; eauto. +Qed. + +End TRANSL_LABEL. + +(** A valid branch in a piece of Mach code translates to a valid ``go to'' + transition in the generated Asm code. *) + +Lemma find_label_goto_label: + forall f tf lbl rs m c' b ofs, + Genv.find_funct_ptr ge b = Some (Internal f) -> + transf_function f = OK tf -> + rs PC = Vptr b ofs -> + Mach.find_label lbl f.(Mach.fn_code) = Some c' -> + exists tc', exists rs', + goto_label tf lbl rs m = Next rs' m + /\ transl_code_at_pc ge (rs' PC) b f c' false tf tc' + /\ forall r, r <> PC -> rs'#r = rs#r. +Proof. + intros. exploit (transl_find_label lbl f tf); eauto. rewrite H2. + intros [tc [A B]]. + exploit label_pos_code_tail; eauto. instantiate (1 := 0). + intros [pos' [P [Q R]]]. + exists tc; exists (rs#PC <- (Vptr b (Ptrofs.repr pos'))). + split. unfold goto_label. rewrite P. rewrite H1. auto. + split. rewrite Pregmap.gss. constructor; auto. + rewrite Ptrofs.unsigned_repr. replace (pos' - 0) with pos' in Q. + auto. omega. + generalize (transf_function_no_overflow _ _ H0). omega. + intros. apply Pregmap.gso; auto. +Qed. + +(** Existence of return addresses *) + +Lemma return_address_exists: + forall f sg ros c, is_tail (Mcall sg ros :: c) f.(Mach.fn_code) -> + exists ra, return_address_offset f c ra. +Proof. + intros. eapply Asmgenproof0.return_address_exists; eauto. +- intros. exploit transl_instr_label; eauto. + destruct i; try (intros [A B]; apply A). intros. subst c0. repeat constructor. +- intros. monadInv H0. + destruct (zlt Ptrofs.max_unsigned (list_length_z x.(fn_code))); inv EQ0. monadInv EQ. + rewrite transl_code'_transl_code in EQ0. + exists x; exists true; split; auto. unfold fn_code. + constructor. apply (storeptr_label X30 XSP (fn_retaddr_ofs f0) x). +- exact transf_function_no_overflow. +Qed. + +(** * Proof of semantic preservation *) + +(** Semantic preservation is proved using simulation diagrams + of the following form. +<< + st1 --------------- st2 + | | + t| *|t + | | + v v + st1'--------------- st2' +>> + The invariant is the [match_states] predicate below, which includes: +- The Asm code pointed by the PC register is the translation of + the current Mach code sequence. +- Mach register values and Asm register values agree. +*) + +Inductive match_states: Mach.state -> Asm.state -> Prop := + | match_states_intro: + forall s fb sp c ep ms m m' rs f tf tc + (STACKS: match_stack ge s) + (FIND: Genv.find_funct_ptr ge fb = Some (Internal f)) + (MEXT: Mem.extends m m') + (AT: transl_code_at_pc ge (rs PC) fb f c ep tf tc) + (AG: agree ms sp rs) + (DXP: ep = true -> rs#X29 = parent_sp s) + (LEAF: is_leaf_function f = true -> rs#RA = parent_ra s), + match_states (Mach.State s fb sp c ms m) + (Asm.State rs m') + | match_states_call: + forall s fb ms m m' rs + (STACKS: match_stack ge s) + (MEXT: Mem.extends m m') + (AG: agree ms (parent_sp s) rs) + (ATPC: rs PC = Vptr fb Ptrofs.zero) + (ATLR: rs RA = parent_ra s), + match_states (Mach.Callstate s fb ms m) + (Asm.State rs m') + | match_states_return: + forall s ms m m' rs + (STACKS: match_stack ge s) + (MEXT: Mem.extends m m') + (AG: agree ms (parent_sp s) rs) + (ATPC: rs PC = parent_ra s), + match_states (Mach.Returnstate s ms m) + (Asm.State rs m'). + +Lemma exec_straight_steps: + forall s fb f rs1 i c ep tf tc m1' m2 m2' sp ms2, + match_stack ge s -> + Mem.extends m2 m2' -> + Genv.find_funct_ptr ge fb = Some (Internal f) -> + transl_code_at_pc ge (rs1 PC) fb f (i :: c) ep tf tc -> + (forall k c (TR: transl_instr f i ep k = OK c), + exists rs2, + exec_straight tge tf c rs1 m1' k rs2 m2' + /\ agree ms2 sp rs2 + /\ (it1_is_parent ep i = true -> rs2#X29 = parent_sp s) + /\ (is_leaf_function f = true -> rs2#RA = parent_ra s)) -> + exists st', + plus step tge (State rs1 m1') E0 st' /\ + match_states (Mach.State s fb sp c ms2 m2) st'. +Proof. + intros. inversion H2. subst. monadInv H7. + exploit H3; eauto. intros [rs2 [A [B [C D]]]]. + exists (State rs2 m2'); split. + - eapply exec_straight_exec; eauto. + - econstructor; eauto. eapply exec_straight_at; eauto. +Qed. + +Lemma exec_straight_steps_goto: + forall s fb f rs1 i c ep tf tc m1' m2 m2' sp ms2 lbl c', + match_stack ge s -> + Mem.extends m2 m2' -> + Genv.find_funct_ptr ge fb = Some (Internal f) -> + Mach.find_label lbl f.(Mach.fn_code) = Some c' -> + transl_code_at_pc ge (rs1 PC) fb f (i :: c) ep tf tc -> + it1_is_parent ep i = false -> + (forall k c (TR: transl_instr f i ep k = OK c), + exists jmp, exists k', exists rs2, + exec_straight tge tf c rs1 m1' (jmp :: k') rs2 m2' + /\ agree ms2 sp rs2 + /\ exec_instr tge tf jmp rs2 m2' = goto_label tf lbl rs2 m2' + /\ (is_leaf_function f = true -> rs2#RA = parent_ra s)) -> + exists st', + plus step tge (State rs1 m1') E0 st' /\ + match_states (Mach.State s fb sp c' ms2 m2) st'. +Proof. + intros. inversion H3. subst. monadInv H9. + exploit H5; eauto. intros [jmp [k' [rs2 [A [B [C D]]]]]]. + generalize (functions_transl _ _ _ H7 H8); intro FN. + generalize (transf_function_no_overflow _ _ H8); intro NOOV. + exploit exec_straight_steps_2; eauto. + intros [ofs' [PC2 CT2]]. + exploit find_label_goto_label; eauto. + intros [tc' [rs3 [GOTO [AT' OTH]]]]. + exists (State rs3 m2'); split. + eapply plus_right'. + eapply exec_straight_steps_1; eauto. + econstructor; eauto. + eapply find_instr_tail. eauto. + rewrite C. eexact GOTO. + traceEq. + econstructor; eauto. + apply agree_exten with rs2; auto with asmgen. + congruence. + rewrite OTH by congruence; auto. +Qed. + +Lemma exec_straight_opt_steps_goto: + forall s fb f rs1 i c ep tf tc m1' m2 m2' sp ms2 lbl c', + match_stack ge s -> + Mem.extends m2 m2' -> + Genv.find_funct_ptr ge fb = Some (Internal f) -> + Mach.find_label lbl f.(Mach.fn_code) = Some c' -> + transl_code_at_pc ge (rs1 PC) fb f (i :: c) ep tf tc -> + it1_is_parent ep i = false -> + (forall k c (TR: transl_instr f i ep k = OK c), + exists jmp, exists k', exists rs2, + exec_straight_opt tge tf c rs1 m1' (jmp :: k') rs2 m2' + /\ agree ms2 sp rs2 + /\ exec_instr tge tf jmp rs2 m2' = goto_label tf lbl rs2 m2' + /\ (is_leaf_function f = true -> rs2#RA = parent_ra s)) -> + exists st', + plus step tge (State rs1 m1') E0 st' /\ + match_states (Mach.State s fb sp c' ms2 m2) st'. +Proof. + intros. inversion H3. subst. monadInv H9. + exploit H5; eauto. intros [jmp [k' [rs2 [A [B [C D]]]]]]. + generalize (functions_transl _ _ _ H7 H8); intro FN. + generalize (transf_function_no_overflow _ _ H8); intro NOOV. + inv A. +- exploit find_label_goto_label; eauto. + intros [tc' [rs3 [GOTO [AT' OTH]]]]. + exists (State rs3 m2'); split. + apply plus_one. econstructor; eauto. + eapply find_instr_tail. eauto. + rewrite C. eexact GOTO. + econstructor; eauto. + apply agree_exten with rs2; auto with asmgen. + congruence. + rewrite OTH by congruence; auto. +- exploit exec_straight_steps_2; eauto. + intros [ofs' [PC2 CT2]]. + exploit find_label_goto_label; eauto. + intros [tc' [rs3 [GOTO [AT' OTH]]]]. + exists (State rs3 m2'); split. + eapply plus_right'. + eapply exec_straight_steps_1; eauto. + econstructor; eauto. + eapply find_instr_tail. eauto. + rewrite C. eexact GOTO. + traceEq. + econstructor; eauto. + apply agree_exten with rs2; auto with asmgen. + congruence. + rewrite OTH by congruence; auto. +Qed. + +(** We need to show that, in the simulation diagram, we cannot + take infinitely many Mach transitions that correspond to zero + transitions on the Asm side. Actually, all Mach transitions + correspond to at least one Asm transition, except the + transition from [Machsem.Returnstate] to [Machsem.State]. + So, the following integer measure will suffice to rule out + the unwanted behaviour. *) + +Definition measure (s: Mach.state) : nat := + match s with + | Mach.State _ _ _ _ _ _ => 0%nat + | Mach.Callstate _ _ _ _ => 0%nat + | Mach.Returnstate _ _ _ => 1%nat + end. + +Remark preg_of_not_X29: forall r, negb (mreg_eq r R29) = true -> IR X29 <> preg_of r. +Proof. + intros. change (IR X29) with (preg_of R29). red; intros. + exploit preg_of_injective; eauto. intros; subst r; discriminate. +Qed. + +Lemma sp_val': forall ms sp rs, agree ms sp rs -> sp = rs XSP. +Proof. + intros. eapply sp_val; eauto. +Qed. + +(** This is the simulation diagram. We prove it by case analysis on the Mach transition. *) + +Theorem step_simulation: + forall S1 t S2, Mach.step return_address_offset ge S1 t S2 -> + forall S1' (MS: match_states S1 S1') (WF: wf_state ge S1), + (exists S2', plus step tge S1' t S2' /\ match_states S2 S2') + \/ (measure S2 < measure S1 /\ t = E0 /\ match_states S2 S1')%nat. +Proof. + induction 1; intros; inv MS. + +- (* Mlabel *) + left; eapply exec_straight_steps; eauto; intros. + monadInv TR. econstructor; split. apply exec_straight_one. simpl; eauto. auto. + split. { apply agree_nextinstr; auto. } + split. { simpl; congruence. } + rewrite nextinstr_inv by congruence; assumption. + +- (* Mgetstack *) + unfold load_stack in H. + exploit Mem.loadv_extends; eauto. intros [v' [A B]]. + rewrite (sp_val _ _ _ AG) in A. + left; eapply exec_straight_steps; eauto. intros. simpl in TR. + exploit loadind_correct; eauto with asmgen. intros [rs' [P [Q [R S]]]]. + exists rs'; split. eauto. + split. { eapply agree_set_mreg; eauto with asmgen. congruence. } + split. { simpl; congruence. } + rewrite S. assumption. + +- (* Msetstack *) + unfold store_stack in H. + assert (Val.lessdef (rs src) (rs0 (preg_of src))) by (eapply preg_val; eauto). + exploit Mem.storev_extends; eauto. intros [m2' [A B]]. + left; eapply exec_straight_steps; eauto. + rewrite (sp_val _ _ _ AG) in A. intros. simpl in TR. + exploit storeind_correct; eauto with asmgen. intros [rs' [P [Q R]]]. + exists rs'; split. eauto. + split. eapply agree_undef_regs; eauto with asmgen. + simpl; intros. + split. rewrite Q; auto with asmgen. + rewrite R. assumption. + +- (* Mgetparam *) + assert (f0 = f) by congruence; subst f0. + unfold load_stack in *. + exploit Mem.loadv_extends. eauto. eexact H0. auto. + intros [parent' [A B]]. rewrite (sp_val' _ _ _ AG) in A. + exploit lessdef_parent_sp; eauto. clear B; intros B; subst parent'. + exploit Mem.loadv_extends. eauto. eexact H1. auto. + intros [v' [C D]]. +Opaque loadind. + left; eapply exec_straight_steps; eauto; intros. monadInv TR. + destruct ep. +(* X30 contains parent *) + exploit loadind_correct. eexact EQ. + instantiate (2 := rs0). simpl; rewrite DXP; eauto. simpl; congruence. + intros [rs1 [P [Q [R S]]]]. + exists rs1; split. eauto. + split. eapply agree_set_mreg. eapply agree_set_mreg; eauto. congruence. auto with asmgen. + simpl; split; intros. + { rewrite R; auto with asmgen. + apply preg_of_not_X29; auto. + } + { rewrite S; auto. } + +(* X30 does not contain parent *) + exploit loadptr_correct. eexact A. simpl; congruence. intros [rs1 [P [Q R]]]. + exploit loadind_correct. eexact EQ. instantiate (2 := rs1). simpl; rewrite Q. eauto. simpl; congruence. + intros [rs2 [S [T [U V]]]]. + exists rs2; split. eapply exec_straight_trans; eauto. + split. eapply agree_set_mreg. eapply agree_set_mreg. eauto. eauto. + instantiate (1 := rs1#X29 <- (rs2#X29)). intros. + rewrite Pregmap.gso; auto with asmgen. + congruence. + intros. unfold Pregmap.set. destruct (PregEq.eq r' X29). congruence. auto with asmgen. + split; simpl; intros. rewrite U; auto with asmgen. + apply preg_of_not_X29; auto. + rewrite V. rewrite R by congruence. auto. + +- (* Mop *) + assert (eval_operation tge sp op (map rs args) m = Some v). + { rewrite <- H. apply eval_operation_preserved. exact symbols_preserved. } + exploit eval_operation_lessdef. eapply preg_vals; eauto. eauto. eexact H0. + intros [v' [A B]]. rewrite (sp_val _ _ _ AG) in A. + left; eapply exec_straight_steps; eauto; intros. simpl in TR. + exploit transl_op_correct; eauto. intros [rs2 [P [Q [R S]]]]. + exists rs2; split. eauto. split. + apply agree_set_undef_mreg with rs0; auto. + apply Val.lessdef_trans with v'; auto. + split; simpl; intros. InvBooleans. + rewrite R; auto. apply preg_of_not_X29; auto. +Local Transparent destroyed_by_op. + destruct op; try exact I; simpl; congruence. + rewrite S. + auto. +- (* Mload *) + destruct trap. + { + assert (Op.eval_addressing tge sp addr (map rs args) = Some a). + { rewrite <- H. apply eval_addressing_preserved. exact symbols_preserved. } + exploit eval_addressing_lessdef. eapply preg_vals; eauto. eexact H1. + intros [a' [A B]]. rewrite (sp_val _ _ _ AG) in A. + exploit Mem.loadv_extends; eauto. intros [v' [C D]]. + left; eapply exec_straight_steps; eauto; intros. simpl in TR. + exploit transl_load_correct; eauto. intros [rs2 [P [Q [R S]]]]. + exists rs2; split. eauto. + split. eapply agree_set_undef_mreg; eauto. congruence. + split. simpl; congruence. + rewrite S. assumption. + } + + (* Mload notrap1 *) + inv AT. simpl in *. unfold bind in *. destruct (transl_code _ _ _) in *; discriminate. + +- (* Mload notrap *) + inv AT. simpl in *. unfold bind in *. destruct (transl_code _ _ _) in *; discriminate. + +- (* Mload notrap *) + inv AT. simpl in *. unfold bind in *. destruct (transl_code _ _ _) in *; discriminate. + +- (* Mstore *) + assert (Op.eval_addressing tge sp addr (map rs args) = Some a). + { rewrite <- H. apply eval_addressing_preserved. exact symbols_preserved. } + exploit eval_addressing_lessdef. eapply preg_vals; eauto. eexact H1. + intros [a' [A B]]. rewrite (sp_val _ _ _ AG) in A. + assert (Val.lessdef (rs src) (rs0 (preg_of src))) by (eapply preg_val; eauto). + exploit Mem.storev_extends; eauto. intros [m2' [C D]]. + left; eapply exec_straight_steps; eauto. + intros. simpl in TR. exploit transl_store_correct; eauto. intros [rs2 [P [Q R]]]. + exists rs2; split. eauto. + split. eapply agree_undef_regs; eauto with asmgen. + split. simpl; congruence. + rewrite R. assumption. + +- (* Mcall *) + assert (f0 = f) by congruence. subst f0. + inv AT. + assert (NOOV: list_length_z tf.(fn_code) <= Ptrofs.max_unsigned). + { eapply transf_function_no_overflow; eauto. } + destruct ros as [rf|fid]; simpl in H; monadInv H5. ++ (* Indirect call *) + assert (rs rf = Vptr f' Ptrofs.zero). + { destruct (rs rf); try discriminate. + revert H; predSpec Ptrofs.eq Ptrofs.eq_spec i Ptrofs.zero; intros; congruence. } + assert (rs0 x0 = Vptr f' Ptrofs.zero). + { exploit ireg_val; eauto. rewrite H5; intros LD; inv LD; auto. } + generalize (code_tail_next_int _ _ _ _ NOOV H6). intro CT1. + assert (TCA: transl_code_at_pc ge (Vptr fb (Ptrofs.add ofs Ptrofs.one)) fb f c false tf x). + { econstructor; eauto. } + exploit return_address_offset_correct; eauto. intros; subst ra. + left; econstructor; split. + apply plus_one. eapply exec_step_internal. Simpl. rewrite <- H2; simpl; eauto. + eapply functions_transl; eauto. eapply find_instr_tail; eauto. + simpl. eauto. + econstructor; eauto. + econstructor; eauto. + eapply agree_sp_def; eauto. + simpl. eapply agree_exten; eauto. intros. Simpl. + Simpl. rewrite <- H2. auto. ++ (* Direct call *) + generalize (code_tail_next_int _ _ _ _ NOOV H6). intro CT1. + assert (TCA: transl_code_at_pc ge (Vptr fb (Ptrofs.add ofs Ptrofs.one)) fb f c false tf x). + econstructor; eauto. + exploit return_address_offset_correct; eauto. intros; subst ra. + left; econstructor; split. + apply plus_one. eapply exec_step_internal. eauto. + eapply functions_transl; eauto. eapply find_instr_tail; eauto. + simpl. unfold Genv.symbol_address. rewrite symbols_preserved. rewrite H. eauto. + econstructor; eauto. + econstructor; eauto. + eapply agree_sp_def; eauto. + simpl. eapply agree_exten; eauto. intros. Simpl. + Simpl. rewrite <- H2. auto. + +- (* Mtailcall *) + assert (f0 = f) by congruence. subst f0. + inversion AT; subst. + assert (NOOV: list_length_z tf.(fn_code) <= Ptrofs.max_unsigned). + { eapply transf_function_no_overflow; eauto. } + exploit Mem.loadv_extends. eauto. eexact H1. auto. simpl. intros [parent' [A B]]. + destruct ros as [rf|fid]; simpl in H; monadInv H7. ++ (* Indirect call *) + assert (rs rf = Vptr f' Ptrofs.zero). + { destruct (rs rf); try discriminate. + revert H; predSpec Ptrofs.eq Ptrofs.eq_spec i Ptrofs.zero; intros; congruence. } + assert (rs0 x0 = Vptr f' Ptrofs.zero). + { exploit ireg_val; eauto. rewrite H7; intros LD; inv LD; auto. } + exploit make_epilogue_correct; eauto. intros (rs1 & m1 & U & V & W & X & Y & Z). + exploit exec_straight_steps_2; eauto using functions_transl. + intros (ofs' & P & Q). + left; econstructor; split. + (* execution *) + eapply plus_right'. eapply exec_straight_exec; eauto. + econstructor. eexact P. eapply functions_transl; eauto. eapply find_instr_tail. eexact Q. + simpl. reflexivity. + traceEq. + (* match states *) + econstructor; eauto. + apply agree_set_other; auto with asmgen. + Simpl. rewrite Z by (rewrite <- (ireg_of_eq _ _ EQ1); eauto with asmgen). assumption. ++ (* Direct call *) + exploit make_epilogue_correct; eauto. intros (rs1 & m1 & U & V & W & X & Y & Z). + exploit exec_straight_steps_2; eauto using functions_transl. + intros (ofs' & P & Q). + left; econstructor; split. + (* execution *) + eapply plus_right'. eapply exec_straight_exec; eauto. + econstructor. eexact P. eapply functions_transl; eauto. eapply find_instr_tail. eexact Q. + simpl. reflexivity. + traceEq. + (* match states *) + econstructor; eauto. + apply agree_set_other; auto with asmgen. + Simpl. unfold Genv.symbol_address. rewrite symbols_preserved. rewrite H. auto. + +- (* Mbuiltin *) + inv AT. monadInv H4. + exploit functions_transl; eauto. intro FN. + generalize (transf_function_no_overflow _ _ H3); intro NOOV. + exploit builtin_args_match; eauto. intros [vargs' [P Q]]. + exploit external_call_mem_extends; eauto. + intros [vres' [m2' [A [B [C D]]]]]. + left. econstructor; split. apply plus_one. + eapply exec_step_builtin. eauto. eauto. + eapply find_instr_tail; eauto. + erewrite <- sp_val by eauto. + eapply eval_builtin_args_preserved with (ge1 := ge); eauto. exact symbols_preserved. + eapply external_call_symbols_preserved; eauto. apply senv_preserved. + eauto. + econstructor; eauto. + instantiate (2 := tf); instantiate (1 := x). + unfold nextinstr. rewrite Pregmap.gss. + rewrite set_res_other. rewrite undef_regs_other_2. + rewrite <- H1. simpl. econstructor; eauto. + eapply code_tail_next_int; eauto. + rewrite preg_notin_charact. intros. auto with asmgen. + auto with asmgen. + apply agree_nextinstr. eapply agree_set_res; auto. + eapply agree_undef_regs; eauto. intros. rewrite undef_regs_other_2; auto. + congruence. + + Simpl. + rewrite set_res_other by trivial. + rewrite undef_regs_other. + assumption. + intro. + rewrite in_map_iff. + intros (x0 & PREG & IN). + subst r'. + intro. + apply (preg_of_not_RA x0). + congruence. + +- (* Mgoto *) + assert (f0 = f) by congruence. subst f0. + inv AT. monadInv H4. + exploit find_label_goto_label; eauto. intros [tc' [rs' [GOTO [AT2 INV]]]]. + left; exists (State rs' m'); split. + apply plus_one. econstructor; eauto. + eapply functions_transl; eauto. + eapply find_instr_tail; eauto. + simpl; eauto. + econstructor; eauto. + eapply agree_exten; eauto with asmgen. + congruence. + + rewrite INV by congruence. + assumption. + +- (* Mcond true *) + assert (f0 = f) by congruence. subst f0. + exploit eval_condition_lessdef. eapply preg_vals; eauto. eauto. eauto. intros EC. + left; eapply exec_straight_opt_steps_goto; eauto. + intros. simpl in TR. + exploit transl_cond_branch_correct; eauto. intros (rs' & jmp & A & B & C & D). + exists jmp; exists k; exists rs'. + split. eexact A. + split. apply agree_exten with rs0; auto with asmgen. + split. + exact B. + rewrite D. exact LEAF. + +- (* Mcond false *) + exploit eval_condition_lessdef. eapply preg_vals; eauto. eauto. eauto. intros EC. + left; eapply exec_straight_steps; eauto. intros. simpl in TR. + exploit transl_cond_branch_correct; eauto. intros (rs' & jmp & A & B & C & D). + econstructor; split. + eapply exec_straight_opt_right. eexact A. apply exec_straight_one. eexact B. auto. + split. apply agree_exten with rs0; auto. intros. Simpl. + split. + simpl; congruence. + Simpl. rewrite D. + exact LEAF. + +- (* Mjumptable *) + assert (f0 = f) by congruence. subst f0. + inv AT. monadInv H6. + exploit functions_transl; eauto. intro FN. + generalize (transf_function_no_overflow _ _ H5); intro NOOV. + exploit find_label_goto_label. eauto. eauto. + instantiate (2 := rs0#X16 <- Vundef #X17 <- Vundef). + Simpl. eauto. + eauto. + intros [tc' [rs' [A [B C]]]]. + exploit ireg_val; eauto. rewrite H. intros LD; inv LD. + left; econstructor; split. + apply plus_one. econstructor; eauto. + eapply find_instr_tail; eauto. + simpl. Simpl. rewrite <- H9. unfold Mach.label in H0; unfold label; rewrite H0. eexact A. + econstructor; eauto. + eapply agree_undef_regs; eauto. + simpl. intros. rewrite C; auto with asmgen. Simpl. + congruence. + + rewrite C by congruence. + repeat rewrite Pregmap.gso by congruence. + assumption. + +- (* Mreturn *) + assert (f0 = f) by congruence. subst f0. + inversion AT; subst. simpl in H6; monadInv H6. + assert (NOOV: list_length_z tf.(fn_code) <= Ptrofs.max_unsigned). + eapply transf_function_no_overflow; eauto. + exploit make_epilogue_correct; eauto. intros (rs1 & m1 & U & V & W & X & Y & Z). + exploit exec_straight_steps_2; eauto using functions_transl. + intros (ofs' & P & Q). + left; econstructor; split. + (* execution *) + eapply plus_right'. eapply exec_straight_exec; eauto. + econstructor. eexact P. eapply functions_transl; eauto. eapply find_instr_tail. eexact Q. + simpl. reflexivity. + traceEq. + (* match states *) + econstructor; eauto. + apply agree_set_other; auto with asmgen. + +- (* internal function *) + + exploit functions_translated; eauto. intros [tf [A B]]. monadInv B. + generalize EQ; intros EQ'. monadInv EQ'. + destruct (zlt Ptrofs.max_unsigned (list_length_z x0.(fn_code))); inversion EQ1. clear EQ1. subst x0. + unfold store_stack in *. + exploit Mem.alloc_extends. eauto. eauto. apply Z.le_refl. apply Z.le_refl. + intros [m1' [C D]]. + exploit Mem.storev_extends. eexact D. eexact H1. eauto. eauto. + intros [m2' [F G]]. + simpl chunk_of_type in F. + exploit Mem.storev_extends. eexact G. eexact H2. eauto. eauto. + intros [m3' [P Q]]. + change (chunk_of_type Tptr) with Mint64 in *. + (* Execution of function prologue *) + monadInv EQ0. rewrite transl_code'_transl_code in EQ1. + set (tfbody := Pallocframe (fn_stacksize f) (fn_link_ofs f) :: + storeptr RA XSP (fn_retaddr_ofs f) x0) in *. + set (tf := {| fn_sig := Mach.fn_sig f; fn_code := tfbody |}) in *. + set (rs2 := nextinstr (rs0#X29 <- (parent_sp s) #SP <- sp #X16 <- Vundef)). + exploit (storeptr_correct tge tf XSP (fn_retaddr_ofs f) RA x0 m2' m3' rs2). + simpl preg_of_iregsp. change (rs2 X30) with (rs0 X30). rewrite ATLR. + change (rs2 X2) with sp. eexact P. + simpl; congruence. congruence. + intros (rs3 & U & V & W). + assert (EXEC_PROLOGUE: + exec_straight tge tf + tf.(fn_code) rs0 m' + x0 rs3 m3'). + { change (fn_code tf) with tfbody; unfold tfbody. + apply exec_straight_step with rs2 m2'. + unfold exec_instr. rewrite C. fold sp. + rewrite <- (sp_val _ _ _ AG). rewrite F. reflexivity. + reflexivity. + eexact U. } + exploit exec_straight_steps_2; eauto using functions_transl. omega. constructor. + intros (ofs' & X & Y). + left; exists (State rs3 m3'); split. + eapply exec_straight_steps_1; eauto. omega. constructor. + econstructor; eauto. + rewrite X; econstructor; eauto. + apply agree_exten with rs2; eauto with asmgen. + unfold rs2. + apply agree_nextinstr. apply agree_set_other; auto with asmgen. + apply agree_change_sp with (parent_sp s). + apply agree_undef_regs with rs0. auto. +Local Transparent destroyed_at_function_entry. simpl. + simpl; intros; Simpl. + unfold sp; congruence. + intros. rewrite V by auto with asmgen. reflexivity. + + rewrite W. + unfold rs2. + Simpl. + +- (* external function *) + exploit functions_translated; eauto. + intros [tf [A B]]. simpl in B. inv B. + exploit extcall_arguments_match; eauto. + intros [args' [C D]]. + exploit external_call_mem_extends; eauto. + intros [res' [m2' [P [Q [R S]]]]]. + left; econstructor; split. + apply plus_one. eapply exec_step_external; eauto. + eapply external_call_symbols_preserved; eauto. apply senv_preserved. + econstructor; eauto. + unfold loc_external_result. apply agree_set_other; auto. apply agree_set_pair; auto. + apply agree_undef_caller_save_regs; auto. + +- (* return *) + inv STACKS. simpl in *. + right. split. omega. split. auto. + rewrite <- ATPC in H5. + econstructor; eauto. congruence. + inv WF. + inv STACK. + inv H1. + congruence. +Qed. + +Lemma transf_initial_states: + forall st1, Mach.initial_state prog st1 -> + exists st2, Asm.initial_state tprog st2 /\ match_states st1 st2. +Proof. + intros. inversion H. unfold ge0 in *. + econstructor; split. + econstructor. + eapply (Genv.init_mem_transf_partial TRANSF); eauto. + replace (Genv.symbol_address (Genv.globalenv tprog) (prog_main tprog) Ptrofs.zero) + with (Vptr fb Ptrofs.zero). + econstructor; eauto. + constructor. + apply Mem.extends_refl. + split. auto. simpl. unfold Vnullptr; destruct Archi.ptr64; congruence. + intros. rewrite Regmap.gi. auto. + unfold Genv.symbol_address. + rewrite (match_program_main TRANSF). + rewrite symbols_preserved. + unfold ge; rewrite H1. auto. +Qed. + +Lemma transf_final_states: + forall st1 st2 r, + match_states st1 st2 -> Mach.final_state st1 r -> Asm.final_state st2 r. +Proof. + intros. inv H0. inv H. constructor. assumption. + compute in H1. inv H1. + generalize (preg_val _ _ _ R0 AG). rewrite H2. intros LD; inv LD. auto. +Qed. + +Theorem transf_program_correct: + forward_simulation (Mach.semantics return_address_offset prog) (Asm.semantics tprog). +Proof. + eapply forward_simulation_star with (measure := measure) + (match_states := fun S1 S2 => match_states S1 S2 /\ wf_state ge S1). + - apply senv_preserved. + - simpl; intros. exploit transf_initial_states; eauto. + intros (s2 & A & B). + exists s2; intuition auto. apply wf_initial; auto. + - simpl; intros. destruct H as [MS WF]. eapply transf_final_states; eauto. + - simpl; intros. destruct H0 as [MS WF]. + exploit step_simulation; eauto. intros [ (s2' & A & B) | (A & B & C) ]. + + left; exists s2'; intuition auto. eapply wf_step; eauto. + + right; intuition auto. eapply wf_step; eauto. +Qed. + +End PRESERVATION. +*)
\ No newline at end of file diff --git a/aarch64/Asmblockgenproof0.v b/aarch64/Asmblockgenproof0.v new file mode 100644 index 00000000..92c0aa58 --- /dev/null +++ b/aarch64/Asmblockgenproof0.v @@ -0,0 +1,983 @@ +(* *************************************************************) +(* *) +(* The Compcert verified compiler *) +(* *) +(* Sylvain Boulmé Grenoble-INP, VERIMAG *) +(* Xavier Leroy INRIA Paris-Rocquencourt *) +(* David Monniaux CNRS, VERIMAG *) +(* Cyril Six Kalray *) +(* *) +(* Copyright Kalray. Copyright VERIMAG. All rights reserved. *) +(* This file is distributed under the terms of the INRIA *) +(* Non-Commercial License Agreement. *) +(* *) +(* *************************************************************) + +(** * "block" version of Asmgenproof0 + + This module is largely adapted from Asmgenproof0.v of the other backends + It needs to stand apart because of the block structure, and the distinction control/basic that there isn't in the other backends + It has similar definitions than Asmgenproof0, but adapted to this new structure *) + +Require Import Coqlib. +Require Intv. +Require Import AST. +Require Import Errors. +Require Import Integers. +Require Import Floats. +Require Import Values. +Require Import Memory. +Require Import Globalenvs. +Require Import Events. +Require Import Smallstep. +Require Import Locations. +Require Import Machblock. +Require Import Asmblock. +Require Import Asmblockgen. +Require Import Conventions1. +Require Import Axioms. +Require Import Machblockgenproof. (* FIXME: only use to import [is_tail_app] and [is_tail_app_inv] *) +Require Import Asmblockprops. + +Module MB:=Machblock. +Module AB:=Asmblock. + +(* +Lemma ireg_of_eq: + forall r r', ireg_of r = OK r' -> preg_of r = IR r'. +Proof. + unfold ireg_of; intros. destruct (preg_of r); inv H; auto. +Qed. + +Lemma freg_of_eq: + forall r r', freg_of r = OK r' -> preg_of r = IR r'. +Proof. + unfold freg_of; intros. destruct (preg_of r); inv H; auto. +Qed. + +Lemma preg_of_injective: + forall r1 r2, preg_of r1 = preg_of r2 -> r1 = r2. +Proof. + destruct r1; destruct r2; simpl; intros; reflexivity || discriminate. +Qed. + +Lemma undef_regs_other: + forall r rl rs, + (forall r', In r' rl -> r <> r') -> + undef_regs rl rs r = rs r. +Proof. + induction rl; simpl; intros. auto. + rewrite IHrl by auto. rewrite Pregmap.gso; auto. +Qed. + +Fixpoint preg_notin (r: preg) (rl: list mreg) : Prop := + match rl with + | nil => True + | r1 :: nil => r <> preg_of r1 + | r1 :: rl => r <> preg_of r1 /\ preg_notin r rl + end. + +Remark preg_notin_charact: + forall r rl, + preg_notin r rl <-> (forall mr, In mr rl -> r <> preg_of mr). +Proof. + induction rl; simpl; intros. + tauto. + destruct rl. + simpl. split. intros. intuition congruence. auto. + rewrite IHrl. split. + intros [A B]. intros. destruct H. congruence. auto. + auto. +Qed. + +Lemma undef_regs_other_2: + forall r rl rs, + preg_notin r rl -> + undef_regs (map preg_of rl) rs r = rs r. +Proof. + intros. apply undef_regs_other. intros. + exploit list_in_map_inv; eauto. intros [mr [A B]]. subst. + rewrite preg_notin_charact in H. auto. +Qed. + +(** * Agreement between Mach registers and processor registers *) + +Record agree (ms: Mach.regset) (sp: val) (rs: AB.regset) : Prop := mkagree { + agree_sp: rs#SP = sp; + agree_sp_def: sp <> Vundef; + agree_mregs: forall r: mreg, Val.lessdef (ms r) (rs#(preg_of r)) +}. + +Lemma preg_val: + forall ms sp rs r, agree ms sp rs -> Val.lessdef (ms r) rs#(preg_of r). +Proof. + intros. destruct H. auto. +Qed. + +Lemma preg_vals: + forall ms sp rs, agree ms sp rs -> + forall l, Val.lessdef_list (map ms l) (map rs (map preg_of l)). +Proof. + induction l; simpl. constructor. constructor. eapply preg_val; eauto. auto. +Qed. + +Lemma sp_val: + forall ms sp rs, agree ms sp rs -> sp = rs#SP. +Proof. + intros. destruct H; auto. +Qed. + +Lemma ireg_val: + forall ms sp rs r r', + agree ms sp rs -> + ireg_of r = OK r' -> + Val.lessdef (ms r) rs#r'. +Proof. + intros. rewrite <- (ireg_of_eq _ _ H0). eapply preg_val; eauto. +Qed. + +Lemma freg_val: + forall ms sp rs r r', + agree ms sp rs -> + freg_of r = OK r' -> + Val.lessdef (ms r) (rs#r'). +Proof. + intros. rewrite <- (freg_of_eq _ _ H0). eapply preg_val; eauto. +Qed. + +Lemma agree_exten: + forall ms sp rs rs', + agree ms sp rs -> + (forall r, data_preg r = true -> rs'#r = rs#r) -> + agree ms sp rs'. +Proof. + intros. destruct H. split; auto. + rewrite H0; auto. auto. + intros. rewrite H0; auto. apply preg_of_data. +Qed. + +(** Preservation of register agreement under various assignments. *) + +Lemma agree_set_mreg: + forall ms sp rs r v rs', + agree ms sp rs -> + Val.lessdef v (rs'#(preg_of r)) -> + (forall r', data_preg r' = true -> r' <> preg_of r -> rs'#r' = rs#r') -> + agree (Mach.Regmap.set r v ms) sp rs'. +Proof. + intros. destruct H. split; auto. + rewrite H1; auto. apply not_eq_sym. apply preg_of_not_SP. + intros. unfold Mach.Regmap.set. destruct (Mach.RegEq.eq r0 r). congruence. + rewrite H1. auto. apply preg_of_data. + red; intros; elim n. eapply preg_of_injective; eauto. +Qed. + +Corollary agree_set_mreg_parallel: + forall ms sp rs r v v', + agree ms sp rs -> + Val.lessdef v v' -> + agree (Mach.Regmap.set r v ms) sp (Pregmap.set (preg_of r) v' rs). +Proof. + intros. eapply agree_set_mreg; eauto. rewrite Pregmap.gss; auto. intros; apply Pregmap.gso; auto. +Qed. + +Lemma agree_set_other: + forall ms sp rs r v, + agree ms sp rs -> + data_preg r = false -> + agree ms sp (rs#r <- v). +Proof. + intros. apply agree_exten with rs. auto. + intros. apply Pregmap.gso. congruence. +Qed. + +Lemma agree_nextblock: + forall ms sp rs b, + agree ms sp rs -> agree ms sp (nextblock b rs). +Proof. + intros. unfold nextblock. apply agree_set_other. auto. auto. +Qed. + +Lemma agree_set_pair: + forall sp p v v' ms rs, + agree ms sp rs -> + Val.lessdef v v' -> + agree (Mach.set_pair p v ms) sp (set_pair (map_rpair preg_of p) v' rs). +Proof. + intros. destruct p; simpl. +- apply agree_set_mreg_parallel; auto. +- apply agree_set_mreg_parallel. apply agree_set_mreg_parallel; auto. + apply Val.hiword_lessdef; auto. apply Val.loword_lessdef; auto. +Qed. + +Lemma agree_undef_nondata_regs: + forall ms sp rl rs, + agree ms sp rs -> + (forall r, In r rl -> data_preg r = false) -> + agree ms sp (undef_regs rl rs). +Proof. + induction rl; simpl; intros. auto. + apply IHrl. apply agree_exten with rs; auto. + intros. apply Pregmap.gso. red; intros; subst. + assert (data_preg a = false) by auto. congruence. + intros. apply H0; auto. +Qed. + +Lemma agree_undef_regs: + forall ms sp rl rs rs', + agree ms sp rs -> + (forall r', data_preg r' = true -> preg_notin r' rl -> rs'#r' = rs#r') -> + agree (Mach.undef_regs rl ms) sp rs'. +Proof. + intros. destruct H. split; auto. + rewrite <- agree_sp0. apply H0; auto. + rewrite preg_notin_charact. intros. apply not_eq_sym. apply preg_of_not_SP. + intros. destruct (In_dec mreg_eq r rl). + rewrite Mach.undef_regs_same; auto. + rewrite Mach.undef_regs_other; auto. rewrite H0; auto. + apply preg_of_data. + rewrite preg_notin_charact. intros; red; intros. elim n. + exploit preg_of_injective; eauto. congruence. +Qed. + +Lemma agree_set_undef_mreg: + forall ms sp rs r v rl rs', + agree ms sp rs -> + Val.lessdef v (rs'#(preg_of r)) -> + (forall r', data_preg r' = true -> r' <> preg_of r -> preg_notin r' rl -> rs'#r' = rs#r') -> + agree (Mach.Regmap.set r v (Mach.undef_regs rl ms)) sp rs'. +Proof. + intros. apply agree_set_mreg with (rs'#(preg_of r) <- (rs#(preg_of r))); auto. + apply agree_undef_regs with rs; auto. + intros. unfold Pregmap.set. destruct (PregEq.eq r' (preg_of r)). + congruence. auto. + intros. rewrite Pregmap.gso; auto. +Qed. + +Lemma agree_undef_caller_save_regs: + forall ms sp rs, + agree ms sp rs -> + agree (Mach.undef_caller_save_regs ms) sp (undef_caller_save_regs rs). +Proof. + intros. destruct H. unfold Mach.undef_caller_save_regs, undef_caller_save_regs; split. +- unfold proj_sumbool; rewrite dec_eq_true. auto. +- auto. +- intros. unfold proj_sumbool. rewrite dec_eq_false by (apply preg_of_not_SP). + destruct (List.in_dec preg_eq (preg_of r) (List.map preg_of (List.filter is_callee_save all_mregs))); simpl. ++ apply list_in_map_inv in i. destruct i as (mr & A & B). + assert (r = mr) by (apply preg_of_injective; auto). subst mr; clear A. + apply List.filter_In in B. destruct B as [C D]. rewrite D. auto. ++ destruct (is_callee_save r) eqn:CS; auto. + elim n. apply List.in_map. apply List.filter_In. auto using all_mregs_complete. +Qed. + +Lemma agree_change_sp: + forall ms sp rs sp', + agree ms sp rs -> sp' <> Vundef -> + agree ms sp' (rs#SP <- sp'). +Proof. + intros. inv H. split; auto. + intros. rewrite Pregmap.gso; auto with asmgen. +Qed. + +(** Connection between Mach and Asm calling conventions for external + functions. *) + +Lemma extcall_arg_match: + forall ms sp rs m m' l v, + agree ms sp rs -> + Mem.extends m m' -> + Mach.extcall_arg ms m sp l v -> + exists v', AB.extcall_arg rs m' l v' /\ Val.lessdef v v'. +Proof. + intros. inv H1. + exists (rs#(preg_of r)); split. constructor. eapply preg_val; eauto. + unfold Mach.load_stack in H2. + exploit Mem.loadv_extends; eauto. intros [v' [A B]]. + rewrite (sp_val _ _ _ H) in A. + exists v'; split; auto. + econstructor. eauto. assumption. +Qed. + +Lemma extcall_arg_pair_match: + forall ms sp rs m m' p v, + agree ms sp rs -> + Mem.extends m m' -> + Mach.extcall_arg_pair ms m sp p v -> + exists v', AB.extcall_arg_pair rs m' p v' /\ Val.lessdef v v'. +Proof. + intros. inv H1. +- exploit extcall_arg_match; eauto. intros (v' & A & B). exists v'; split; auto. constructor; auto. +- exploit extcall_arg_match. eauto. eauto. eexact H2. intros (v1 & A1 & B1). + exploit extcall_arg_match. eauto. eauto. eexact H3. intros (v2 & A2 & B2). + exists (Val.longofwords v1 v2); split. constructor; auto. apply Val.longofwords_lessdef; auto. +Qed. + + +Lemma extcall_args_match: + forall ms sp rs m m', agree ms sp rs -> Mem.extends m m' -> + forall ll vl, + list_forall2 (Mach.extcall_arg_pair ms m sp) ll vl -> + exists vl', list_forall2 (AB.extcall_arg_pair rs m') ll vl' /\ Val.lessdef_list vl vl'. +Proof. + induction 3; intros. + exists (@nil val); split. constructor. constructor. + exploit extcall_arg_pair_match; eauto. intros [v1' [A B]]. + destruct IHlist_forall2 as [vl' [C D]]. + exists (v1' :: vl'); split; constructor; auto. +Qed. + +Lemma extcall_arguments_match: + forall ms m m' sp rs sg args, + agree ms sp rs -> Mem.extends m m' -> + Mach.extcall_arguments ms m sp sg args -> + exists args', AB.extcall_arguments rs m' sg args' /\ Val.lessdef_list args args'. +Proof. + unfold Mach.extcall_arguments, AB.extcall_arguments; intros. + eapply extcall_args_match; eauto. +Qed. + +Remark builtin_arg_match: + forall ge (rs: regset) sp m a v, + eval_builtin_arg ge (fun r => rs (preg_of r)) sp m a v -> + eval_builtin_arg ge rs sp m (map_builtin_arg preg_of a) v. +Proof. + induction 1; simpl; eauto with barg. +Qed. + +Lemma builtin_args_match: + forall ge ms sp rs m m', agree ms sp rs -> Mem.extends m m' -> + forall al vl, eval_builtin_args ge ms sp m al vl -> + exists vl', eval_builtin_args ge rs sp m' (map (map_builtin_arg preg_of) al) vl' + /\ Val.lessdef_list vl vl'. +Proof. + induction 3; intros; simpl. + exists (@nil val); split; constructor. + exploit (@eval_builtin_arg_lessdef _ ge ms (fun r => rs (preg_of r))); eauto. + intros; eapply preg_val; eauto. + intros (v1' & A & B). + destruct IHlist_forall2 as [vl' [C D]]. + exists (v1' :: vl'); split; constructor; auto. apply builtin_arg_match; auto. +Qed. + +Lemma agree_set_res: + forall res ms sp rs v v', + agree ms sp rs -> + Val.lessdef v v' -> + agree (Mach.set_res res v ms) sp (AB.set_res (map_builtin_res preg_of res) v' rs). +Proof. + induction res; simpl; intros. +- eapply agree_set_mreg; eauto. rewrite Pregmap.gss. auto. + intros. apply Pregmap.gso; auto. +- auto. +- apply IHres2. apply IHres1. auto. + apply Val.hiword_lessdef; auto. + apply Val.loword_lessdef; auto. +Qed. + +Lemma set_res_other: + forall r res v rs, + data_preg r = false -> + set_res (map_builtin_res preg_of res) v rs r = rs r. +Proof. + induction res; simpl; intros. +- apply Pregmap.gso. red; intros; subst r. rewrite preg_of_data in H; discriminate. +- auto. +- rewrite IHres2, IHres1; auto. +Qed. + +(* inspired from Mach *) + +Lemma find_label_tail: + forall lbl c c', MB.find_label lbl c = Some c' -> is_tail c' c. +Proof. + induction c; simpl; intros. discriminate. + destruct (MB.is_label lbl a). inv H. auto with coqlib. eauto with coqlib. +Qed. + +(* inspired from Asmgenproof0 *) + +(* ... skip ... *) + +(** The ``code tail'' of an instruction list [c] is the list of instructions + starting at PC [pos]. *) + +Inductive code_tail: Z -> bblocks -> bblocks -> Prop := + | code_tail_0: forall c, + code_tail 0 c c + | code_tail_S: forall pos bi c1 c2, + code_tail pos c1 c2 -> + code_tail (pos + (size bi)) (bi :: c1) c2. + +Lemma code_tail_pos: + forall pos c1 c2, code_tail pos c1 c2 -> pos >= 0. +Proof. + induction 1. omega. generalize (size_positive bi); intros; omega. +Qed. + +Lemma find_bblock_tail: + forall c1 bi c2 pos, + code_tail pos c1 (bi :: c2) -> + find_bblock pos c1 = Some bi. +Proof. + induction c1; simpl; intros. + inversion H. + destruct (zlt pos 0). generalize (code_tail_pos _ _ _ H); intro; omega. + destruct (zeq pos 0). subst pos. + inv H. auto. generalize (size_positive a) (code_tail_pos _ _ _ H4). intro; omega. + inv H. congruence. replace (pos0 + size a - size a) with pos0 by omega. + eauto. +Qed. + + +Local Hint Resolve code_tail_0 code_tail_S: core. + +Lemma code_tail_next: + forall fn ofs c0, + code_tail ofs fn c0 -> + forall bi c1, c0 = bi :: c1 -> code_tail (ofs + (size bi)) fn c1. +Proof. + induction 1; intros. + - subst; eauto. + - replace (pos + size bi + size bi0) with ((pos + size bi0) + size bi); eauto. + omega. +Qed. + +Lemma size_blocks_pos c: 0 <= size_blocks c. +Proof. + induction c as [| a l ]; simpl; try omega. + generalize (size_positive a); omega. +Qed. + +Remark code_tail_positive: + forall fn ofs c, + code_tail ofs fn c -> 0 <= ofs. +Proof. + induction 1; intros; simpl. + - omega. + - generalize (size_positive bi). omega. +Qed. + +Remark code_tail_size: + forall fn ofs c, + code_tail ofs fn c -> size_blocks fn = ofs + size_blocks c. +Proof. + induction 1; intros; simpl; try omega. +Qed. + +Remark code_tail_bounds fn ofs c: + code_tail ofs fn c -> 0 <= ofs <= size_blocks fn. +Proof. + intro H; + exploit code_tail_size; eauto. + generalize (code_tail_positive _ _ _ H), (size_blocks_pos c). + omega. +Qed. + +Local Hint Resolve code_tail_next: core. + +Lemma code_tail_next_int: + forall fn ofs bi c, + size_blocks fn <= Ptrofs.max_unsigned -> + code_tail (Ptrofs.unsigned ofs) fn (bi :: c) -> + code_tail (Ptrofs.unsigned (Ptrofs.add ofs (Ptrofs.repr (size bi)))) fn c. +Proof. + intros. + exploit code_tail_size; eauto. + simpl; generalize (code_tail_positive _ _ _ H0), (size_positive bi), (size_blocks_pos c). + intros. + rewrite Ptrofs.add_unsigned, Ptrofs.unsigned_repr. + - rewrite Ptrofs.unsigned_repr; eauto. + omega. + - rewrite Ptrofs.unsigned_repr; omega. +Qed. + +(** Predictor for return addresses in generated Asm code. + + The [return_address_offset] predicate defined here is used in the + semantics for Mach to determine the return addresses that are + stored in activation records. *) + +(** Consider a Mach function [f] and a sequence [c] of Mach instructions + representing the Mach code that remains to be executed after a + function call returns. The predicate [return_address_offset f c ofs] + holds if [ofs] is the integer offset of the PPC instruction + following the call in the Asm code obtained by translating the + code of [f]. Graphically: +<< + Mach function f |--------- Mcall ---------| + Mach code c | |--------| + | \ \ + | \ \ + | \ \ + Asm code | |--------| + Asm function |------------- Pcall ---------| + + <-------- ofs -------> +>> +*) + +Definition return_address_offset (f: MB.function) (c: MB.code) (ofs: ptrofs) : Prop := + forall tf tc, + transf_function f = OK tf -> + transl_blocks f c false = OK tc -> + code_tail (Ptrofs.unsigned ofs) (fn_blocks tf) tc. + +Lemma transl_blocks_tail: + forall f c1 c2, is_tail c1 c2 -> + forall tc2 ep2, transl_blocks f c2 ep2 = OK tc2 -> + exists tc1, exists ep1, transl_blocks f c1 ep1 = OK tc1 /\ is_tail tc1 tc2. +Proof. + induction 1; simpl; intros. + exists tc2; exists ep2; split; auto with coqlib. + monadInv H0. exploit IHis_tail; eauto. intros (tc1 & ep1 & A & B). + exists tc1; exists ep1; split. auto. + eapply is_tail_trans with x0; eauto with coqlib. +Qed. + +Lemma is_tail_code_tail: + forall c1 c2, is_tail c1 c2 -> exists ofs, code_tail ofs c2 c1. +Proof. + induction 1; eauto. + destruct IHis_tail; eauto. +Qed. + +Section RETADDR_EXISTS. + +Hypothesis transf_function_inv: + forall f tf, transf_function f = OK tf -> + exists tc ep, transl_blocks f (Machblock.fn_code f) ep = OK tc /\ is_tail tc (fn_blocks tf). + +Hypothesis transf_function_len: + forall f tf, transf_function f = OK tf -> size_blocks (fn_blocks tf) <= Ptrofs.max_unsigned. + + +Lemma return_address_exists: + forall b f c, is_tail (b :: c) f.(MB.fn_code) -> + exists ra, return_address_offset f c ra. +Proof. + intros. destruct (transf_function f) as [tf|] eqn:TF. + + exploit transf_function_inv; eauto. intros (tc1 & ep1 & TR1 & TL1). + exploit transl_blocks_tail; eauto. intros (tc2 & ep2 & TR2 & TL2). + monadInv TR2. + assert (TL3: is_tail x0 (fn_blocks tf)). + { apply is_tail_trans with tc1; auto. + apply is_tail_trans with (x++x0); auto. eapply is_tail_app. + } + exploit is_tail_code_tail. eexact TL3. intros [ofs CT]. + exists (Ptrofs.repr ofs). red; intros. + rewrite Ptrofs.unsigned_repr. congruence. + exploit code_tail_bounds; eauto. + intros; apply transf_function_len in TF. omega. + + exists Ptrofs.zero; red; intros. congruence. +Qed. + +End RETADDR_EXISTS. + +(** [transl_code_at_pc pc fb f c ep tf tc] holds if the code pointer [pc] points + within the Asmblock code generated by translating Machblock function [f], + and [tc] is the tail of the generated code at the position corresponding + to the code pointer [pc]. *) + +Inductive transl_code_at_pc (ge: MB.genv): + val -> block -> MB.function -> MB.code -> bool -> AB.function -> AB.bblocks -> Prop := + transl_code_at_pc_intro: + forall b ofs f c ep tf tc, + Genv.find_funct_ptr ge b = Some(Internal f) -> + transf_function f = Errors.OK tf -> + transl_blocks f c ep = OK tc -> + code_tail (Ptrofs.unsigned ofs) (fn_blocks tf) tc -> + transl_code_at_pc ge (Vptr b ofs) b f c ep tf tc. + +Remark code_tail_no_bigger: + forall pos c1 c2, code_tail pos c1 c2 -> (length c2 <= length c1)%nat. +Proof. + induction 1; simpl; omega. +Qed. + +Remark code_tail_unique: + forall fn c pos pos', + code_tail pos fn c -> code_tail pos' fn c -> pos = pos'. +Proof. + induction fn; intros until pos'; intros ITA CT; inv ITA; inv CT; auto. + generalize (code_tail_no_bigger _ _ _ H3); simpl; intro; omega. + generalize (code_tail_no_bigger _ _ _ H3); simpl; intro; omega. + f_equal. eauto. +Qed. + +Lemma return_address_offset_correct: + forall ge b ofs fb f c tf tc ofs', + transl_code_at_pc ge (Vptr b ofs) fb f c false tf tc -> + return_address_offset f c ofs' -> + ofs' = ofs. +Proof. + intros. inv H. red in H0. + exploit code_tail_unique. eexact H12. eapply H0; eauto. intro. + rewrite <- (Ptrofs.repr_unsigned ofs). + rewrite <- (Ptrofs.repr_unsigned ofs'). + congruence. +Qed. + +(** The [find_label] function returns the code tail starting at the + given label. A connection with [code_tail] is then established. *) + +Fixpoint find_label (lbl: label) (c: bblocks) {struct c} : option bblocks := + match c with + | nil => None + | bb1 :: bbl => if is_label lbl bb1 then Some c else find_label lbl bbl + end. + +Lemma label_pos_code_tail: + forall lbl c pos c', + find_label lbl c = Some c' -> + exists pos', + label_pos lbl pos c = Some pos' + /\ code_tail (pos' - pos) c c' + /\ pos <= pos' <= pos + size_blocks c. +Proof. + induction c. + simpl; intros. discriminate. + simpl; intros until c'. + case (is_label lbl a). + - intros. inv H. exists pos. split; auto. split. + replace (pos - pos) with 0 by omega. constructor. constructor; try omega. + generalize (size_blocks_pos c). generalize (size_positive a). omega. + - intros. generalize (IHc (pos+size a) c' H). intros [pos' [A [B C]]]. + exists pos'. split. auto. split. + replace (pos' - pos) with ((pos' - (pos + (size a))) + (size a)) by omega. + constructor. auto. generalize (size_positive a). omega. +Qed. + +(** Helper lemmas to reason about +- the "code is tail of" property +- correct translation of labels. *) + +Definition tail_nolabel (k c: bblocks) : Prop := + is_tail k c /\ forall lbl, find_label lbl c = find_label lbl k. + +Lemma tail_nolabel_refl: + forall c, tail_nolabel c c. +Proof. + intros; split. apply is_tail_refl. auto. +Qed. + +Lemma tail_nolabel_trans: + forall c1 c2 c3, tail_nolabel c2 c3 -> tail_nolabel c1 c2 -> tail_nolabel c1 c3. +Proof. + intros. destruct H; destruct H0; split. + eapply is_tail_trans; eauto. + intros. rewrite H1; auto. +Qed. + +Definition nolabel (b: bblock) := + match (header b) with nil => True | _ => False end. + +Hint Extern 1 (nolabel _) => exact I : labels. + +Lemma tail_nolabel_cons: + forall b c k, + nolabel b -> tail_nolabel k c -> tail_nolabel k (b :: c). +Proof. + intros. destruct H0. split. + constructor; auto. + intros. simpl. rewrite <- H1. destruct b as [hd bdy ex]; simpl in *. + destruct hd as [|l hd]; simpl in *. + - assert (is_label lbl {| AB.header := nil; AB.body := bdy; AB.exit := ex; AB.correct := correct |} = false). + { apply is_label_correct_false. simpl header. apply in_nil. } + rewrite H2. auto. + - contradiction. +Qed. + +Hint Resolve tail_nolabel_refl: labels. + +Ltac TailNoLabel := + eauto with labels; + match goal with + | [ |- tail_nolabel _ (_ :: _) ] => apply tail_nolabel_cons; [auto; exact I | TailNoLabel] + | [ H: Error _ = OK _ |- _ ] => discriminate + | [ H: assertion_failed = OK _ |- _ ] => discriminate + | [ H: OK _ = OK _ |- _ ] => inv H; TailNoLabel + | [ H: bind _ _ = OK _ |- _ ] => monadInv H; TailNoLabel + | [ H: (if ?x then _ else _) = OK _ |- _ ] => destruct x; TailNoLabel + | [ H: match ?x with nil => _ | _ :: _ => _ end = OK _ |- _ ] => destruct x; TailNoLabel + | _ => idtac + end. + +Remark tail_nolabel_find_label: + forall lbl k c, tail_nolabel k c -> find_label lbl c = find_label lbl k. +Proof. + intros. destruct H. auto. +Qed. + +Remark tail_nolabel_is_tail: + forall k c, tail_nolabel k c -> is_tail k c. +Proof. + intros. destruct H. auto. +Qed. + +Lemma exec_body_pc: + forall ge l rs1 m1 rs2 m2, + exec_body ge l rs1 m1 = Next rs2 m2 -> + rs2 PC = rs1 PC. +Proof. + induction l. + - intros. inv H. auto. + - intros until m2. intro EXEB. + inv EXEB. destruct (exec_basic_instr _ _ _ _) eqn:EBI; try discriminate. + eapply IHl in H0. rewrite H0. + erewrite exec_basic_instr_pc; eauto. +Qed. + +Section STRAIGHTLINE. + +Variable ge: genv. +Variable fn: function. + +(** Straight-line code is composed of processor instructions that execute + in sequence (no branches, no function calls and returns). + The following inductive predicate relates the machine states + before and after executing a straight-line sequence of instructions. + Instructions are taken from the first list instead of being fetched + from memory. *) + +Inductive exec_straight: list instruction -> regset -> mem -> + list instruction -> regset -> mem -> Prop := + | exec_straight_one: + forall i1 c rs1 m1 rs2 m2, + exec_basic_instr ge i1 rs1 m1 = Next rs2 m2 -> + exec_straight ((PBasic i1) ::g c) rs1 m1 c rs2 m2 + | exec_straight_step: + forall i c rs1 m1 rs2 m2 c' rs3 m3, + exec_basic_instr ge i rs1 m1 = Next rs2 m2 -> + exec_straight c rs2 m2 c' rs3 m3 -> + exec_straight ((PBasic i) :: c) rs1 m1 c' rs3 m3. + +Inductive exec_control_rel: option control -> bblock -> regset -> mem -> + regset -> mem -> Prop := + | exec_control_rel_intro: + forall rs1 m1 b rs1' ctl rs2 m2, + rs1' = nextblock b rs1 -> + exec_control ge fn ctl rs1' m1 = Next rs2 m2 -> + exec_control_rel ctl b rs1 m1 rs2 m2. + +Inductive exec_bblock_rel: bblock -> regset -> mem -> regset -> mem -> Prop := + | exec_bblock_rel_intro: + forall rs1 m1 b rs2 m2, + exec_bblock ge fn b rs1 m1 = Next rs2 m2 -> + exec_bblock_rel b rs1 m1 rs2 m2. + +Lemma exec_straight_body: + forall c l rs1 m1 rs2 m2, + exec_straight c rs1 m1 nil rs2 m2 -> + code_to_basics c = Some l -> + exec_body ge l rs1 m1 = Next rs2 m2. +Proof. + induction c as [|i c]. + - intros until m2. intros EXES CTB. inv EXES. + - intros until m2. intros EXES CTB. inv EXES. + + inv CTB. simpl. rewrite H6. auto. + + inv CTB. destruct (code_to_basics c); try discriminate. inv H0. eapply IHc in H7; eauto. + rewrite <- H7. simpl. rewrite H1. auto. +Qed. + +Lemma exec_straight_body2: + forall c rs1 m1 c' rs2 m2, + exec_straight c rs1 m1 c' rs2 m2 -> + exists body, + exec_body ge body rs1 m1 = Next rs2 m2 + /\ (basics_to_code body) ++g c' = c. +Proof. + intros until m2. induction 1. + - exists (i1::nil). split; auto. simpl. rewrite H. auto. + - destruct IHexec_straight as (bdy & EXEB & BTC). + exists (i:: bdy). split; simpl. + + rewrite H. auto. + + congruence. +Qed. + +Lemma exec_straight_trans: + forall c1 rs1 m1 c2 rs2 m2 c3 rs3 m3, + exec_straight c1 rs1 m1 c2 rs2 m2 -> + exec_straight c2 rs2 m2 c3 rs3 m3 -> + exec_straight c1 rs1 m1 c3 rs3 m3. +Proof. + induction 1; intros. + apply exec_straight_step with rs2 m2; auto. + apply exec_straight_step with rs2 m2; auto. +Qed. + +Lemma exec_straight_two: + forall i1 i2 c rs1 m1 rs2 m2 rs3 m3, + exec_basic_instr ge i1 rs1 m1 = Next rs2 m2 -> + exec_basic_instr ge i2 rs2 m2 = Next rs3 m3 -> + exec_straight (i1 ::g i2 ::g c) rs1 m1 c rs3 m3. +Proof. + intros. apply exec_straight_step with rs2 m2; auto. + apply exec_straight_one; auto. +Qed. + +Lemma exec_straight_three: + forall i1 i2 i3 c rs1 m1 rs2 m2 rs3 m3 rs4 m4, + exec_basic_instr ge i1 rs1 m1 = Next rs2 m2 -> + exec_basic_instr ge i2 rs2 m2 = Next rs3 m3 -> + exec_basic_instr ge i3 rs3 m3 = Next rs4 m4 -> + exec_straight (i1 ::g i2 ::g i3 ::g c) rs1 m1 c rs4 m4. +Proof. + intros. apply exec_straight_step with rs2 m2; auto. + eapply exec_straight_two; eauto. +Qed. + +(** Like exec_straight predicate, but on blocks *) + +Inductive exec_straight_blocks: bblocks -> regset -> mem -> + bblocks -> regset -> mem -> Prop := + | exec_straight_blocks_one: + forall b1 c rs1 m1 rs2 m2, + exec_bblock ge fn b1 rs1 m1 = Next rs2 m2 -> + rs2#PC = Val.offset_ptr rs1#PC (Ptrofs.repr (size b1)) -> + exec_straight_blocks (b1 :: c) rs1 m1 c rs2 m2 + | exec_straight_blocks_step: + forall b c rs1 m1 rs2 m2 c' rs3 m3, + exec_bblock ge fn b rs1 m1 = Next rs2 m2 -> + rs2#PC = Val.offset_ptr rs1#PC (Ptrofs.repr (size b)) -> + exec_straight_blocks c rs2 m2 c' rs3 m3 -> + exec_straight_blocks (b :: c) rs1 m1 c' rs3 m3. + +Lemma exec_straight_blocks_trans: + forall c1 rs1 m1 c2 rs2 m2 c3 rs3 m3, + exec_straight_blocks c1 rs1 m1 c2 rs2 m2 -> + exec_straight_blocks c2 rs2 m2 c3 rs3 m3 -> + exec_straight_blocks c1 rs1 m1 c3 rs3 m3. +Proof. + induction 1; intros. + apply exec_straight_blocks_step with rs2 m2; auto. + apply exec_straight_blocks_step with rs2 m2; auto. +Qed. + +(** Linking exec_straight with exec_straight_blocks *) + +Lemma exec_straight_pc: + forall c c' rs1 m1 rs2 m2, + exec_straight c rs1 m1 c' rs2 m2 -> + rs2 PC = rs1 PC. +Proof. + induction c; intros; try (inv H; fail). + inv H. + - eapply exec_basic_instr_pc; eauto. + - rewrite (IHc c' rs3 m3 rs2 m2); auto. + erewrite exec_basic_instr_pc; eauto. +Qed. + +Lemma regset_same_assign (rs: regset) r: + rs # r <- (rs r) = rs. +Proof. + apply functional_extensionality. intros x. destruct (preg_eq x r); subst; Simpl. +Qed. + +Lemma exec_straight_through_singleinst: + forall a b rs1 m1 rs2 m2 rs2' m2' lb, + bblock_single_inst (PBasic a) = b -> + exec_straight (a ::g nil) rs1 m1 nil rs2 m2 -> + nextblock b rs2 = rs2' -> m2 = m2' -> + exec_straight_blocks (b::lb) rs1 m1 lb rs2' m2'. +Proof. + intros. subst. constructor 1. unfold exec_bblock. simpl body. erewrite exec_straight_body; eauto. + simpl. rewrite regset_same_assign. auto. + simpl; auto. unfold nextblock, incrPC; simpl. Simpl. erewrite exec_straight_pc; eauto. +Qed. + +(** The following lemmas show that straight-line executions + (predicate [exec_straight_blocks]) correspond to correct Asm executions. *) + +Lemma exec_straight_steps_1: + forall c rs m c' rs' m', + exec_straight_blocks c rs m c' rs' m' -> + size_blocks (fn_blocks fn) <= Ptrofs.max_unsigned -> + forall b ofs, + rs#PC = Vptr b ofs -> + Genv.find_funct_ptr ge b = Some (Internal fn) -> + code_tail (Ptrofs.unsigned ofs) (fn_blocks fn) c -> + plus step ge (State rs m) E0 (State rs' m'). +Proof. + induction 1; intros. + apply plus_one. + econstructor; eauto. + eapply find_bblock_tail. eauto. + eapply plus_left'. + econstructor; eauto. + eapply find_bblock_tail. eauto. + apply IHexec_straight_blocks with b0 (Ptrofs.add ofs (Ptrofs.repr (size b))). + auto. rewrite H0. rewrite H3. reflexivity. + auto. + apply code_tail_next_int; auto. + traceEq. +Qed. + +Lemma exec_straight_steps_2: + forall c rs m c' rs' m', + exec_straight_blocks c rs m c' rs' m' -> + size_blocks (fn_blocks fn) <= Ptrofs.max_unsigned -> + forall b ofs, + rs#PC = Vptr b ofs -> + Genv.find_funct_ptr ge b = Some (Internal fn) -> + code_tail (Ptrofs.unsigned ofs) (fn_blocks fn) c -> + exists ofs', + rs'#PC = Vptr b ofs' + /\ code_tail (Ptrofs.unsigned ofs') (fn_blocks fn) c'. +Proof. + induction 1; intros. + exists (Ptrofs.add ofs (Ptrofs.repr (size b1))). split. + rewrite H0. rewrite H2. auto. + apply code_tail_next_int; auto. + apply IHexec_straight_blocks with (Ptrofs.add ofs (Ptrofs.repr (size b))). + auto. rewrite H0. rewrite H3. reflexivity. auto. + apply code_tail_next_int; auto. +Qed. + +End STRAIGHTLINE. + +(** * Properties of the Machblock call stack *) + +Section MATCH_STACK. + +Variable ge: MB.genv. + +Inductive match_stack: list MB.stackframe -> Prop := + | match_stack_nil: + match_stack nil + | match_stack_cons: forall fb sp ra c s f tf tc, + Genv.find_funct_ptr ge fb = Some (Internal f) -> + transl_code_at_pc ge ra fb f c false tf tc -> + sp <> Vundef -> + match_stack s -> + match_stack (Stackframe fb sp ra c :: s). + +Lemma parent_sp_def: forall s, match_stack s -> parent_sp s <> Vundef. +Proof. + induction 1; simpl. + unfold Vnullptr; destruct Archi.ptr64; congruence. + auto. +Qed. + +Lemma parent_ra_def: forall s, match_stack s -> parent_ra s <> Vundef. +Proof. + induction 1; simpl. + unfold Vnullptr; destruct Archi.ptr64; congruence. + inv H0. congruence. +Qed. + +Lemma lessdef_parent_sp: + forall s v, + match_stack s -> Val.lessdef (parent_sp s) v -> v = parent_sp s. +Proof. + intros. inv H0. auto. exploit parent_sp_def; eauto. tauto. +Qed. + +Lemma lessdef_parent_ra: + forall s v, + match_stack s -> Val.lessdef (parent_ra s) v -> v = parent_ra s. +Proof. + intros. inv H0. auto. exploit parent_ra_def; eauto. tauto. +Qed. + +End MATCH_STACK.*) diff --git a/aarch64/Asmgenproof1.v b/aarch64/Asmblockgenproof1.v index 0e36bd05..b42309bc 100644 --- a/aarch64/Asmgenproof1.v +++ b/aarch64/Asmblockgenproof1.v @@ -1,3 +1,5 @@ +(* ORIGINAL aarch64/Asmgenproof1 file that needs to be adapted + (* *********************************************************************) (* *) (* The Compcert verified compiler *) @@ -2136,3 +2138,4 @@ Proof. Qed. End CONSTRUCTORS. +*)
\ No newline at end of file diff --git a/aarch64/Asmblockprops.v b/aarch64/Asmblockprops.v new file mode 100644 index 00000000..782d8aee --- /dev/null +++ b/aarch64/Asmblockprops.v @@ -0,0 +1,358 @@ +(* *************************************************************) +(* *) +(* The Compcert verified compiler *) +(* *) +(* Sylvain Boulmé Grenoble-INP, VERIMAG *) +(* David Monniaux CNRS, VERIMAG *) +(* Cyril Six Kalray *) +(* Léo Gourdin UGA, VERIMAG *) +(* *) +(* Copyright Kalray. Copyright VERIMAG. All rights reserved. *) +(* This file is distributed under the terms of the INRIA *) +(* Non-Commercial License Agreement. *) +(* *) +(* *************************************************************) + +(** Common definition and proofs on Asmblock required by various modules *) + +Require Import Coqlib. +Require Import Integers. +Require Import Memory. +Require Import Globalenvs. +Require Import Values. +Require Import Asmblock. +Require Import Axioms. + +Definition bblock_simu (lk: aarch64_linker) (ge: Genv.t fundef unit) (f: function) (bb bb': bblock) := + forall rs m rs' m' t, + exec_bblock lk ge f bb rs m t rs' m' -> exec_bblock lk ge f bb rs m t rs' m'. + +Hint Extern 2 (_ <> _) => congruence: asmgen. + +Lemma preg_of_data: + forall r, data_preg (preg_of r) = true. +Proof. + intros. destruct r; reflexivity. +Qed. +Hint Resolve preg_of_data: asmgen. + +Lemma data_diff: + forall r r', + data_preg r = true -> data_preg r' = false -> r <> r'. +Proof. + congruence. +Qed. +Hint Resolve data_diff: asmgen. + +Lemma preg_of_not_PC: + forall r, preg_of r <> PC. +Proof. + intros. apply data_diff; auto with asmgen. +Qed. + +(* +Lemma preg_of_not_SP: + forall r, preg_of r <> SP. +Proof. + intros. unfold preg_of; destruct r; cbn; congruence. +Qed. + +Hint Resolve preg_of_not_SP preg_of_not_PC: asmgen. + + +Lemma nextblock_pc: + forall b rs, (nextblock b rs)#PC = Val.offset_ptr rs#PC (Ptrofs.repr (size b)). +Proof. + intros. apply Pregmap.gss. +Qed. + +Lemma nextblock_inv: + forall b r rs, r <> PC -> (nextblock b rs)#r = rs#r. +Proof. + intros. unfold nextblock. apply Pregmap.gso. red; intro; subst. auto. +Qed. + +Lemma nextblock_inv1: + forall b r rs, data_preg r = true -> (nextblock b rs)#r = rs#r. +Proof. + intros. apply nextblock_inv. red; intro; subst; discriminate. +Qed. + +Ltac Simplif := + ((rewrite nextblock_inv by eauto with asmgen) + || (rewrite nextblock_inv1 by eauto with asmgen) + || (rewrite Pregmap.gss) + || (rewrite nextblock_pc) + || (rewrite Pregmap.gso by eauto with asmgen) + ); auto with asmgen. + +Ltac Simpl := repeat Simplif. + +(* For Asmblockgenproof0 *) + +Theorem exec_basic_instr_pc: + forall ge b rs1 m1 rs2 m2, + exec_basic_instr ge b rs1 m1 = Next rs2 m2 -> + rs2 PC = rs1 PC. +Proof. + intros. destruct b; try destruct i; try destruct i. + all: try (inv H; Simpl). + 1-10: unfold parexec_load_offset in H1; destruct (eval_offset ofs); try discriminate; destruct (Mem.loadv _ _ _); unfold parexec_incorrect_load in *; destruct trap; try discriminate; unfold concrete_default_notrap_load_value in *; inv H1; Simpl; fail. + + 1-20: unfold parexec_load_reg, parexec_load_regxs in H1; destruct (Mem.loadv _ _ _); unfold parexec_incorrect_load in *; destruct trap; try discriminate; unfold concrete_default_notrap_load_value in *; inv H1; Simpl; fail. + + { (* PLoadQRRO *) + unfold parexec_load_q_offset in H1. + destruct (gpreg_q_expand _) as [r0 r1] in H1. + destruct (Mem.loadv _ _ _) in H1; try discriminate. + destruct (Mem.loadv _ _ _) in H1; try discriminate. + inv H1. Simpl. } + { (* PLoadORRO *) + unfold parexec_load_o_offset in H1. + destruct (gpreg_o_expand _) as [[[r0 r1] r2] r3] in H1. + destruct (Mem.loadv _ _ _) in H1; try discriminate. + destruct (Mem.loadv _ _ _) in H1; try discriminate. + destruct (Mem.loadv _ _ _) in H1; try discriminate. + destruct (Mem.loadv _ _ _) in H1; try discriminate. + inv H1. Simpl. } + 1-8: unfold parexec_store_offset in H1; destruct (eval_offset ofs); try discriminate; destruct (Mem.storev _ _ _); [inv H1; auto | discriminate]; fail. + 1-8: unfold parexec_store_reg in H1; destruct (Mem.storev _ _ _); [inv H1; Simpl | discriminate]; auto; fail. + 1-8: unfold parexec_store_regxs in H1; destruct (Mem.storev _ _ _); [inv H1; Simpl | discriminate]; auto; fail. + + { (* PStoreQRRO *) + unfold parexec_store_q_offset in H1. + destruct (gpreg_q_expand _) as [r0 r1] in H1. + unfold eval_offset in H1; try discriminate. + destruct (Mem.storev _ _ _) in H1; try discriminate. + destruct (Mem.storev _ _ _) in H1; try discriminate. + inv H1. Simpl. reflexivity. } + { (* PStoreORRO *) + unfold parexec_store_o_offset in H1. + destruct (gpreg_o_expand _) as [[[r0 r1] r2] r3] in H1. + unfold eval_offset in H1; try discriminate. + destruct (Mem.storev _ _ _) in H1; try discriminate. + destruct (Mem.storev _ _ _) in H1; try discriminate. + destruct (Mem.storev _ _ _) in H1; try discriminate. + destruct (Mem.storev _ _ _) in H1; try discriminate. + inv H1. Simpl. reflexivity. } + - destruct (Mem.alloc _ _ _). destruct (Mem.store _ _ _ _ _). inv H1. Simpl. discriminate. + - destruct (Mem.loadv _ _ _); try discriminate. destruct (rs1 _); try discriminate. + destruct (Mem.free _ _ _ _). inv H1. Simpl. discriminate. + - destruct rs; try discriminate. inv H1. Simpl. + - destruct rd; try discriminate. inv H1; Simpl. + - reflexivity. +Qed. + +(* For PostpassSchedulingproof *) + +Lemma regset_double_set: + forall r1 r2 (rs: regset) v1 v2, + r1 <> r2 -> + (rs # r1 <- v1 # r2 <- v2) = (rs # r2 <- v2 # r1 <- v1). +Proof. + intros. apply functional_extensionality. intros r. destruct (preg_eq r r1). + - subst. rewrite Pregmap.gso; auto. repeat (rewrite Pregmap.gss). auto. + - destruct (preg_eq r r2). + + subst. rewrite Pregmap.gss. rewrite Pregmap.gso; auto. rewrite Pregmap.gss. auto. + + repeat (rewrite Pregmap.gso; auto). +Qed. + +Lemma next_eq: + forall (rs rs': regset) m m', + rs = rs' -> m = m' -> Next rs m = Next rs' m'. +Proof. + intros; apply f_equal2; auto. +Qed. + +Lemma exec_load_offset_pc_var: + forall trap t rs m rd ra ofs rs' m' v, + exec_load_offset trap t rs m rd ra ofs = Next rs' m' -> + exec_load_offset trap t rs # PC <- v m rd ra ofs = Next rs' # PC <- v m'. +Proof. + intros. unfold exec_load_offset in *. unfold parexec_load_offset in *. rewrite Pregmap.gso; try discriminate. destruct (eval_offset ofs); try discriminate. + destruct (Mem.loadv _ _ _). + - inv H. apply next_eq; auto. apply functional_extensionality. intros. rewrite regset_double_set; auto. discriminate. + - unfold parexec_incorrect_load in *. + destruct trap; try discriminate. + inv H. apply next_eq; auto. apply functional_extensionality. intros. rewrite regset_double_set; auto. discriminate. +Qed. + +Lemma exec_load_reg_pc_var: + forall trap t rs m rd ra ro rs' m' v, + exec_load_reg trap t rs m rd ra ro = Next rs' m' -> + exec_load_reg trap t rs # PC <- v m rd ra ro = Next rs' # PC <- v m'. +Proof. + intros. unfold exec_load_reg in *. unfold parexec_load_reg in *. rewrite Pregmap.gso; try discriminate. + destruct (Mem.loadv _ _ _). + - inv H. apply next_eq; auto. apply functional_extensionality. intros. rewrite regset_double_set; auto. discriminate. + - unfold parexec_incorrect_load in *. + destruct trap; try discriminate. + inv H. apply next_eq; auto. apply functional_extensionality. intros. rewrite regset_double_set; auto. discriminate. +Qed. + +Lemma exec_load_regxs_pc_var: + forall trap t rs m rd ra ro rs' m' v, + exec_load_regxs trap t rs m rd ra ro = Next rs' m' -> + exec_load_regxs trap t rs # PC <- v m rd ra ro = Next rs' # PC <- v m'. +Proof. + intros. unfold exec_load_regxs in *. unfold parexec_load_regxs in *. rewrite Pregmap.gso; try discriminate. + destruct (Mem.loadv _ _ _). + - inv H. apply next_eq; auto. apply functional_extensionality. intros. rewrite regset_double_set; auto. discriminate. + - unfold parexec_incorrect_load in *. + destruct trap; try discriminate. + inv H. apply next_eq; auto. apply functional_extensionality. intros. rewrite regset_double_set; auto. discriminate. +Qed. + +Lemma exec_load_offset_q_pc_var: + forall rs m rd ra ofs rs' m' v, + exec_load_q_offset rs m rd ra ofs = Next rs' m' -> + exec_load_q_offset rs # PC <- v m rd ra ofs = Next rs' # PC <- v m'. +Proof. + intros. unfold exec_load_q_offset in *. unfold parexec_load_q_offset in *. + destruct (gpreg_q_expand rd) as [rd0 rd1]. + (* destruct (ireg_eq rd0 ra); try discriminate. *) + rewrite Pregmap.gso; try discriminate. + destruct (Mem.loadv _ _ _); try discriminate. + inv H. + destruct (Mem.loadv _ _ _); try discriminate. + inv H1. f_equal. + rewrite (regset_double_set PC rd0) by discriminate. + rewrite (regset_double_set PC rd1) by discriminate. + reflexivity. +Qed. + +Lemma exec_load_offset_o_pc_var: + forall rs m rd ra ofs rs' m' v, + exec_load_o_offset rs m rd ra ofs = Next rs' m' -> + exec_load_o_offset rs # PC <- v m rd ra ofs = Next rs' # PC <- v m'. +Proof. + intros. unfold exec_load_o_offset in *. unfold parexec_load_o_offset in *. + destruct (gpreg_o_expand rd) as [[[rd0 rd1] rd2] rd3]. +(* + destruct (ireg_eq rd0 ra); try discriminate. + destruct (ireg_eq rd1 ra); try discriminate. + destruct (ireg_eq rd2 ra); try discriminate. +*) + rewrite Pregmap.gso; try discriminate. + cbn in *. + destruct (Mem.loadv _ _ _); try discriminate. + destruct (Mem.loadv _ _ _); try discriminate. + destruct (Mem.loadv _ _ _); try discriminate. + destruct (Mem.loadv _ _ _); try discriminate. + rewrite (regset_double_set PC rd0) by discriminate. + rewrite (regset_double_set PC rd1) by discriminate. + rewrite (regset_double_set PC rd2) by discriminate. + rewrite (regset_double_set PC rd3) by discriminate. + inv H. + trivial. +Qed. + +Lemma exec_store_offset_pc_var: + forall t rs m rd ra ofs rs' m' v, + exec_store_offset t rs m rd ra ofs = Next rs' m' -> + exec_store_offset t rs # PC <- v m rd ra ofs = Next rs' # PC <- v m'. +Proof. + intros. unfold exec_store_offset in *. unfold parexec_store_offset in *. rewrite Pregmap.gso; try discriminate. + destruct (eval_offset ofs); try discriminate. + destruct (Mem.storev _ _ _). + - inv H. apply next_eq; auto. + - discriminate. +Qed. + +Lemma exec_store_q_offset_pc_var: + forall rs m rd ra ofs rs' m' v, + exec_store_q_offset rs m rd ra ofs = Next rs' m' -> + exec_store_q_offset rs # PC <- v m rd ra ofs = Next rs' # PC <- v m'. +Proof. + intros. unfold exec_store_q_offset in *. unfold parexec_store_q_offset in *. rewrite Pregmap.gso; try discriminate. + cbn in *. + destruct (gpreg_q_expand _) as [s0 s1]. + destruct (Mem.storev _ _ _); try discriminate. + destruct (Mem.storev _ _ _); try discriminate. + inv H. apply next_eq; auto. +Qed. + +Lemma exec_store_o_offset_pc_var: + forall rs m rd ra ofs rs' m' v, + exec_store_o_offset rs m rd ra ofs = Next rs' m' -> + exec_store_o_offset rs # PC <- v m rd ra ofs = Next rs' # PC <- v m'. +Proof. + intros. + unfold exec_store_o_offset in *. unfold parexec_store_o_offset in *. + destruct (gpreg_o_expand _) as [[[s0 s1] s2] s3]. + destruct (Mem.storev _ _ _); try discriminate. + destruct (Mem.storev _ _ _); try discriminate. + destruct (Mem.storev _ _ _); try discriminate. + destruct (Mem.storev _ _ _); try discriminate. + inv H. + trivial. +Qed. + +Lemma exec_store_reg_pc_var: + forall t rs m rd ra ro rs' m' v, + exec_store_reg t rs m rd ra ro = Next rs' m' -> + exec_store_reg t rs # PC <- v m rd ra ro = Next rs' # PC <- v m'. +Proof. + intros. unfold exec_store_reg in *. unfold parexec_store_reg in *. rewrite Pregmap.gso; try discriminate. + destruct (Mem.storev _ _ _). + - inv H. apply next_eq; auto. + - discriminate. +Qed. + +Lemma exec_store_regxs_pc_var: + forall t rs m rd ra ro rs' m' v, + exec_store_regxs t rs m rd ra ro = Next rs' m' -> + exec_store_regxs t rs # PC <- v m rd ra ro = Next rs' # PC <- v m'. +Proof. + intros. unfold exec_store_regxs in *. unfold parexec_store_regxs in *. rewrite Pregmap.gso; try discriminate. + destruct (Mem.storev _ _ _). + - inv H. apply next_eq; auto. + - discriminate. +Qed. + +Theorem exec_basic_instr_pc_var: + forall ge i rs m rs' m' v, + exec_basic_instr ge i rs m = Next rs' m' -> + exec_basic_instr ge i (rs # PC <- v) m = Next (rs' # PC <- v) m'. +Proof. + intros. unfold exec_basic_instr in *. unfold bstep in *. destruct i. + - unfold exec_arith_instr in *. destruct i; destruct i. + all: try (exploreInst; inv H; apply next_eq; auto; + apply functional_extensionality; intros; rewrite regset_double_set; auto; discriminate). +(* + (* Some cases treated seperately because exploreInst destructs too much *) + all: try (inv H; apply next_eq; auto; apply functional_extensionality; intros; rewrite regset_double_set; auto; discriminate). *) + - destruct i. + + exploreInst; apply exec_load_offset_pc_var; auto. + + exploreInst; apply exec_load_reg_pc_var; auto. + + exploreInst; apply exec_load_regxs_pc_var; auto. + + apply exec_load_offset_q_pc_var; auto. + + apply exec_load_offset_o_pc_var; auto. + - destruct i. + + exploreInst; apply exec_store_offset_pc_var; auto. + + exploreInst; apply exec_store_reg_pc_var; auto. + + exploreInst; apply exec_store_regxs_pc_var; auto. + + apply exec_store_q_offset_pc_var; auto. + + apply exec_store_o_offset_pc_var; auto. + - destruct (Mem.alloc _ _ _) as (m1 & stk). repeat (rewrite Pregmap.gso; try discriminate). + destruct (Mem.storev _ _ _ _); try discriminate. + inv H. apply next_eq; auto. apply functional_extensionality. intros. + rewrite (regset_double_set GPR32 PC); try discriminate. + rewrite (regset_double_set GPR12 PC); try discriminate. + rewrite (regset_double_set FP PC); try discriminate. reflexivity. + - repeat (rewrite Pregmap.gso; try discriminate). + destruct (Mem.loadv _ _ _); try discriminate. + destruct (rs GPR12); try discriminate. + destruct (Mem.free _ _ _ _); try discriminate. + inv H. apply next_eq; auto. + rewrite (regset_double_set GPR32 PC). + rewrite (regset_double_set GPR12 PC). reflexivity. + all: discriminate. + - destruct rs0; try discriminate. inv H. apply next_eq; auto. + repeat (rewrite Pregmap.gso; try discriminate). apply regset_double_set; discriminate. + - destruct rd; try discriminate. inv H. apply next_eq; auto. + repeat (rewrite Pregmap.gso; try discriminate). apply regset_double_set; discriminate. + - inv H. apply next_eq; auto. +Qed. + +*) diff --git a/aarch64/Asmexpand.ml b/aarch64/Asmexpand.ml index b0787d0a..0cee763e 100644 --- a/aarch64/Asmexpand.ml +++ b/aarch64/Asmexpand.ml @@ -34,13 +34,13 @@ let _m1 = Z.of_sint (-1) (* Emit instruction sequences that set or offset a register by a constant. *) let expand_loadimm32 (dst: ireg) n = - List.iter emit (Asmgen.loadimm32 dst n []) + List.iter emit (OrigAsmgen.loadimm32 dst n []) let expand_addimm64 (dst: iregsp) (src: iregsp) n = - List.iter emit (Asmgen.addimm64 dst src n []) + List.iter emit (OrigAsmgen.addimm64 dst src n []) let expand_storeptr (src: ireg) (base: iregsp) ofs = - List.iter emit (Asmgen.storeptr src base ofs []) + List.iter emit (OrigAsmgen.storeptr src base ofs []) (* Handling of varargs *) @@ -132,9 +132,9 @@ let expand_builtin_va_start r = let expand_annot_val kind txt targ args res = emit (Pbuiltin (EF_annot(kind,txt,[targ]), args, BR_none)); match args, res with - | [BA(IR src)], BR(IR dst) -> - if dst <> src then emit (Pmov (RR1 dst, RR1 src)) - | [BA(FR src)], BR(FR dst) -> + | [BA(DR(IR src))], BR(DR(IR dst)) -> + if dst <> src then emit (Pmov (dst, src)) + | [BA(DR(FR src))], BR(DR(FR dst)) -> if dst <> src then emit (Pfmov (dst, src)) | _, _ -> raise (Error "ill-formed __builtin_annot_val") @@ -152,8 +152,8 @@ let offset_in_range ofs = let memcpy_small_arg sz arg tmp = match arg with - | BA (IR r) -> - (RR1 r, _0) + | BA (DR(IR r)) -> + (r, _0) | BA_addrstack ofs -> if offset_in_range ofs && offset_in_range (Ptrofs.add ofs (Ptrofs.repr (Z.of_uint sz))) @@ -164,7 +164,7 @@ let memcpy_small_arg sz arg tmp = let expand_builtin_memcpy_small sz al src dst = let (tsrc, tdst) = - if dst <> BA (IR X17) then (X17, X29) else (X29, X17) in + if dst <> BA (DR(IR(RR1 X17))) then (X17, X29) else (X29, X17) in let (rsrc, osrc) = memcpy_small_arg sz src tsrc in let (rdst, odst) = memcpy_small_arg sz dst tdst in let rec copy osrc odst sz = @@ -197,7 +197,7 @@ let expand_builtin_memcpy_small sz al src dst = let memcpy_big_arg arg tmp = match arg with - | BA (IR r) -> emit (Pmov(RR1 tmp, RR1 r)) + | BA (DR(IR r)) -> emit (Pmov(RR1 tmp, r)) | BA_addrstack ofs -> expand_addimm64 (RR1 tmp) XSP ofs | _ -> assert false @@ -241,29 +241,29 @@ let expand_builtin_memcpy sz al args = let expand_builtin_vload_common chunk base ofs res = let addr = ADimm(base, ofs) in match chunk, res with - | Mint8unsigned, BR(IR res) -> + | Mint8unsigned, BR(DR(IR(RR1 res))) -> emit (Pldrb(W, res, addr)) - | Mint8signed, BR(IR res) -> + | Mint8signed, BR(DR(IR(RR1 res))) -> emit (Pldrsb(W, res, addr)) - | Mint16unsigned, BR(IR res) -> + | Mint16unsigned, BR(DR(IR(RR1 res))) -> emit (Pldrh(W, res, addr)) - | Mint16signed, BR(IR res) -> + | Mint16signed, BR(DR(IR(RR1 res))) -> emit (Pldrsh(W, res, addr)) - | Mint32, BR(IR res) -> + | Mint32, BR(DR(IR(RR1 res))) -> emit (Pldrw(res, addr)) - | Mint64, BR(IR res) -> + | Mint64, BR(DR(IR(RR1 res))) -> emit (Pldrx(res, addr)) - | Mfloat32, BR(FR res) -> + | Mfloat32, BR(DR(FR res)) -> emit (Pldrs(res, addr)) - | Mfloat64, BR(FR res) -> + | Mfloat64, BR(DR(FR res)) -> emit (Pldrd(res, addr)) | _ -> assert false let expand_builtin_vload chunk args res = match args with - | [BA(IR addr)] -> - expand_builtin_vload_common chunk (RR1 addr) _0 res + | [BA(DR(IR addr))] -> + expand_builtin_vload_common chunk addr _0 res | [BA_addrstack ofs] -> if offset_in_range (Z.add ofs (Memdata.size_chunk chunk)) then expand_builtin_vload_common chunk XSP ofs res @@ -271,11 +271,11 @@ let expand_builtin_vload chunk args res = expand_addimm64 (RR1 X16) XSP ofs; (* X16 <- SP + ofs *) expand_builtin_vload_common chunk (RR1 X16) _0 res end - | [BA_addptr(BA(IR addr), BA_long ofs)] -> + | [BA_addptr(BA(DR(IR addr)), BA_long ofs)] -> if offset_in_range (Z.add ofs (Memdata.size_chunk chunk)) then - expand_builtin_vload_common chunk (RR1 addr) ofs res + expand_builtin_vload_common chunk addr ofs res else begin - expand_addimm64 (RR1 X16) (RR1 addr) ofs; (* X16 <- addr + ofs *) + expand_addimm64 (RR1 X16) addr ofs; (* X16 <- addr + ofs *) expand_builtin_vload_common chunk (RR1 X16) _0 res end | _ -> @@ -284,25 +284,25 @@ let expand_builtin_vload chunk args res = let expand_builtin_vstore_common chunk base ofs src = let addr = ADimm(base, ofs) in match chunk, src with - | (Mint8signed | Mint8unsigned), BA(IR src) -> + | (Mint8signed | Mint8unsigned), BA(DR(IR(RR1 src))) -> emit (Pstrb(src, addr)) - | (Mint16signed | Mint16unsigned), BA(IR src) -> + | (Mint16signed | Mint16unsigned), BA(DR(IR(RR1 src))) -> emit (Pstrh(src, addr)) - | Mint32, BA(IR src) -> + | Mint32, BA(DR(IR(RR1 src))) -> emit (Pstrw(src, addr)) - | Mint64, BA(IR src) -> + | Mint64, BA(DR(IR(RR1 src))) -> emit (Pstrx(src, addr)) - | Mfloat32, BA(FR src) -> + | Mfloat32, BA(DR(FR src)) -> emit (Pstrs(src, addr)) - | Mfloat64, BA(FR src) -> + | Mfloat64, BA(DR(FR src)) -> emit (Pstrd(src, addr)) | _ -> assert false let expand_builtin_vstore chunk args = match args with - | [BA(IR addr); src] -> - expand_builtin_vstore_common chunk (RR1 addr) _0 src + | [BA(DR(IR addr)); src] -> + expand_builtin_vstore_common chunk addr _0 src | [BA_addrstack ofs; src] -> if offset_in_range (Z.add ofs (Memdata.size_chunk chunk)) then expand_builtin_vstore_common chunk XSP ofs src @@ -310,11 +310,11 @@ let expand_builtin_vstore chunk args = expand_addimm64 (RR1 X16) XSP ofs; (* X16 <- SP + ofs *) expand_builtin_vstore_common chunk (RR1 X16) _0 src end - | [BA_addptr(BA(IR addr), BA_long ofs); src] -> + | [BA_addptr(BA(DR(IR addr)), BA_long ofs); src] -> if offset_in_range (Z.add ofs (Memdata.size_chunk chunk)) then - expand_builtin_vstore_common chunk (RR1 addr) ofs src + expand_builtin_vstore_common chunk addr ofs src else begin - expand_addimm64 (RR1 X16) (RR1 addr) ofs; (* X16 <- addr + ofs *) + expand_addimm64 (RR1 X16) addr ofs; (* X16 <- addr + ofs *) expand_builtin_vstore_common chunk (RR1 X16) _0 src end | _ -> @@ -330,37 +330,37 @@ let expand_builtin_inline name args res = | "__builtin_nop", [], _ -> emit Pnop (* Byte swap *) - | ("__builtin_bswap" | "__builtin_bswap32"), [BA(IR a1)], BR(IR res) -> + | ("__builtin_bswap" | "__builtin_bswap32"), [BA(DR(IR(RR1 a1)))], BR(DR(IR(RR1 res))) -> emit (Prev(W, res, a1)) - | "__builtin_bswap64", [BA(IR a1)], BR(IR res) -> + | "__builtin_bswap64", [BA(DR(IR(RR1 a1)))], BR(DR(IR(RR1 res))) -> emit (Prev(X, res, a1)) - | "__builtin_bswap16", [BA(IR a1)], BR(IR res) -> + | "__builtin_bswap16", [BA(DR(IR(RR1 a1)))], BR(DR(IR(RR1 res))) -> emit (Prev16(W, res, a1)); emit (Pandimm(W, res, RR0 res, Z.of_uint 0xFFFF)) (* Count leading zeros and leading sign bits *) - | "__builtin_clz", [BA(IR a1)], BR(IR res) -> + | "__builtin_clz", [BA(DR(IR(RR1 a1)))], BR(DR(IR(RR1 res))) -> emit (Pclz(W, res, a1)) - | ("__builtin_clzl" | "__builtin_clzll"), [BA(IR a1)], BR(IR res) -> + | ("__builtin_clzl" | "__builtin_clzll"), [BA(DR(IR(RR1 a1)))], BR(DR(IR(RR1 res))) -> emit (Pclz(X, res, a1)) - | "__builtin_cls", [BA(IR a1)], BR(IR res) -> + | "__builtin_cls", [BA(DR(IR(RR1 a1)))], BR(DR(IR(RR1 res))) -> emit (Pcls(W, res, a1)) - | ("__builtin_clsl" | "__builtin_clsll"), [BA(IR a1)], BR(IR res) -> + | ("__builtin_clsl" | "__builtin_clsll"), [BA(DR(IR(RR1 a1)))], BR(DR(IR(RR1 res))) -> emit (Pcls(X, res, a1)) (* Float arithmetic *) - | "__builtin_fabs", [BA(FR a1)], BR(FR res) -> + | "__builtin_fabs", [BA(DR(FR a1))], BR(DR(FR res)) -> emit (Pfabs(D, res, a1)) - | "__builtin_fsqrt", [BA(FR a1)], BR(FR res) -> + | "__builtin_fsqrt", [BA(DR(FR a1))], BR(DR(FR res)) -> emit (Pfsqrt(D, res, a1)) - | "__builtin_fmadd", [BA(FR a1); BA(FR a2); BA(FR a3)], BR(FR res) -> + | "__builtin_fmadd", [BA(DR(FR a1)); BA(DR(FR a2)); BA(DR(FR a3))], BR(DR(FR res)) -> emit (Pfmadd(D, res, a1, a2, a3)) - | "__builtin_fmsub", [BA(FR a1); BA(FR a2); BA(FR a3)], BR(FR res) -> + | "__builtin_fmsub", [BA(DR(FR a1)); BA(DR(FR a2)); BA(DR(FR a3))], BR(DR(FR res)) -> emit (Pfmsub(D, res, a1, a2, a3)) - | "__builtin_fnmadd", [BA(FR a1); BA(FR a2); BA(FR a3)], BR(FR res) -> + | "__builtin_fnmadd", [BA(DR(FR a1)); BA(DR(FR a2)); BA(DR(FR a3))], BR(DR(FR res)) -> emit (Pfnmadd(D, res, a1, a2, a3)) - | "__builtin_fnmsub", [BA(FR a1); BA(FR a2); BA(FR a3)], BR(FR res) -> + | "__builtin_fnmsub", [BA(DR(FR a1)); BA(DR(FR a2)); BA(DR(FR a3))], BR(DR(FR res)) -> emit (Pfnmsub(D, res, a1, a2, a3)) (* Vararg *) - | "__builtin_va_start", [BA(IR a)], _ -> + | "__builtin_va_start", [BA(DR(IR(RR1 a)))], _ -> expand_builtin_va_start a (* Catch-all *) | _ -> @@ -427,9 +427,9 @@ let float_reg_to_dwarf = function | D30 -> 94 | D31 -> 95 let preg_to_dwarf = function - | IR r -> int_reg_to_dwarf r - | FR r -> float_reg_to_dwarf r - | SP -> 31 + | DR(IR(RR1 r)) -> int_reg_to_dwarf r + | DR(FR r) -> float_reg_to_dwarf r + | DR(IR(XSP)) -> 31 | _ -> assert false let expand_function id fn = diff --git a/aarch64/Asmgen.v b/aarch64/Asmgen.v index 024c9a17..bd6b55cc 100644 --- a/aarch64/Asmgen.v +++ b/aarch64/Asmgen.v @@ -1,1172 +1,364 @@ -(* *********************************************************************) -(* *) -(* The Compcert verified compiler *) -(* *) -(* Xavier Leroy, Collège de France and INRIA Paris *) -(* *) -(* Copyright Institut National de Recherche en Informatique et en *) -(* Automatique. All rights reserved. This file is distributed *) -(* under the terms of the INRIA Non-Commercial License Agreement. *) -(* *) -(* *********************************************************************) - -(** Translation from Mach to AArch64. *) +(* *************************************************************) +(* *) +(* The Compcert verified compiler *) +(* *) +(* Sylvain Boulmé Grenoble-INP, VERIMAG *) +(* Justus Fasse UGA, VERIMAG *) +(* Xavier Leroy INRIA Paris-Rocquencourt *) +(* David Monniaux CNRS, VERIMAG *) +(* Cyril Six Kalray *) +(* Léo Gourdin UGA, VERIMAG *) +(* *) +(* Copyright Kalray. Copyright VERIMAG. All rights reserved. *) +(* This file is distributed under the terms of the INRIA *) +(* Non-Commercial License Agreement. *) +(* *) +(* *************************************************************) Require Import Recdef Coqlib Zwf Zbits. Require Import Errors AST Integers Floats Op. -Require Import Locations Mach Asm. - -Local Open Scope string_scope. -Local Open Scope list_scope. -Local Open Scope error_monad_scope. - -(** Alignment check for symbols *) - -Parameter symbol_is_aligned : ident -> Z -> bool. -(** [symbol_is_aligned id sz] checks whether the symbol [id] is [sz] aligned *) - -(** Extracting integer or float registers. *) - -Definition ireg_of (r: mreg) : res ireg := - match preg_of r with IR mr => OK mr | _ => Error(msg "Asmgen.ireg_of") end. - -Definition freg_of (r: mreg) : res freg := - match preg_of r with FR mr => OK mr | _ => Error(msg "Asmgen.freg_of") end. - -(** Recognition of immediate arguments for logical integer operations.*) - -(** Valid immediate arguments are repetitions of a bit pattern [B] - of length [e] = 2, 4, 8, 16, 32 or 64. - The bit pattern [B] must be of the form [0*1*0*] or [1*0*1*] - but must not be all zeros or all ones. *) - -(** The following automaton recognizes [0*1*0*|1*0*1*]. -<< - 0 1 0 - / \ / \ / \ - \ / \ / \ / - -0--> [B] --1--> [D] --0--> [F] - / - [A] - \ - -1--> [C] --0--> [E] --1--> [G] - / \ / \ / \ - \ / \ / \ / - 1 0 1 ->> -*) - -Module Automaton. - -Inductive state : Type := SA | SB | SC | SD | SE | SF | SG | Sbad. - -Definition start := SA. - -Definition next (s: state) (b: bool) := - match s, b with - | SA,false => SB | SA,true => SC - | SB,false => SB | SB,true => SD - | SC,false => SE | SC,true => SC - | SD,false => SF | SD,true => SD - | SE,false => SE | SE,true => SG - | SF,false => SF | SF,true => Sbad - | SG,false => Sbad | SG,true => SG - | Sbad,_ => Sbad - end. - -Definition accepting (s: state) := - match s with - | SA | SB | SC | SD | SE | SF | SG => true - | Sbad => false - end. - -Fixpoint run (len: nat) (s: state) (x: Z) : bool := - match len with - | Datatypes.O => accepting s - | Datatypes.S len => run len (next s (Z.odd x)) (Z.div2 x) - end. - -End Automaton. - -(** The following function determines the candidate length [e], - ensuring that [x] is a repetition [BB...B] - of a bit pattern [B] of length [e]. *) - -Definition logical_imm_length (x: Z) (sixtyfour: bool) : nat := - (** [test n] checks that the low [2n] bits of [x] are of the - form [BB], that is, two occurrences of the same [n] bits *) - let test (n: Z) : bool := - Z.eqb (Zzero_ext n x) (Zzero_ext n (Z.shiftr x n)) in - (** If [test n] fails, we know that the candidate length [e] is - at least [2n]. Hence we test with decreasing values of [n]: - 32, 16, 8, 4, 2. *) - if sixtyfour && negb (test 32) then 64%nat - else if negb (test 16) then 32%nat - else if negb (test 8) then 16%nat - else if negb (test 4) then 8%nat - else if negb (test 2) then 4%nat - else 2%nat. - -(** A valid logical immediate is -- neither [0] nor [-1]; -- composed of a repetition [BBBBB] of a bit-pattern [B] of length [e] -- the low [e] bits of the number, that is, [B], match [0*1*0*] or [1*0*1*]. -*) - -Definition is_logical_imm32 (x: int) : bool := - negb (Int.eq x Int.zero) && negb (Int.eq x Int.mone) && - Automaton.run (logical_imm_length (Int.unsigned x) false) - Automaton.start (Int.unsigned x). - -Definition is_logical_imm64 (x: int64) : bool := - negb (Int64.eq x Int64.zero) && negb (Int64.eq x Int64.mone) && - Automaton.run (logical_imm_length (Int64.unsigned x) true) - Automaton.start (Int64.unsigned x). - -(** Arithmetic immediates are 12-bit unsigned numbers, possibly shifted left 12 bits *) - -Definition is_arith_imm32 (x: int) : bool := - Int.eq x (Int.zero_ext 12 x) - || Int.eq x (Int.shl (Int.zero_ext 12 (Int.shru x (Int.repr 12))) (Int.repr 12)). - -Definition is_arith_imm64 (x: int64) : bool := - Int64.eq x (Int64.zero_ext 12 x) - || Int64.eq x (Int64.shl (Int64.zero_ext 12 (Int64.shru x (Int64.repr 12))) (Int64.repr 12)). - -(** Decompose integer literals into 16-bit fragments *) - -Fixpoint decompose_int (N: nat) (n p: Z) {struct N} : list (Z * Z) := - match N with - | Datatypes.O => nil - | Datatypes.S N => - let frag := Zzero_ext 16 (Z.shiftr n p) in - if Z.eqb frag 0 then - decompose_int N n (p + 16) - else - (frag, p) :: decompose_int N (Z.ldiff n (Z.shiftl 65535 p)) (p + 16) - end. - -Definition negate_decomposition (l: list (Z * Z)) := - List.map (fun np => (Z.lxor (fst np) 65535, snd np)) l. - -Definition loadimm_k (sz: isize) (rd: ireg) (l: list (Z * Z)) (k: code) : code := - List.fold_right (fun np k => Pmovk sz rd (fst np) (snd np) :: k) k l. - -Definition loadimm_z (sz: isize) (rd: ireg) (l: list (Z * Z)) (k: code) : code := - match l with - | nil => Pmovz sz rd 0 0 :: k - | (n1, p1) :: l => Pmovz sz rd n1 p1 :: loadimm_k sz rd l k - end. - -Definition loadimm_n (sz: isize) (rd: ireg) (l: list (Z * Z)) (k: code) : code := - match l with - | nil => Pmovn sz rd 0 0 :: k - | (n1, p1) :: l => Pmovn sz rd n1 p1 :: loadimm_k sz rd (negate_decomposition l) k - end. - -Definition loadimm (sz: isize) (rd: ireg) (n: Z) (k: code) : code := - let N := match sz with W => 2%nat | X => 4%nat end in - let dz := decompose_int N n 0 in - let dn := decompose_int N (Z.lnot n) 0 in - if Nat.leb (List.length dz) (List.length dn) - then loadimm_z sz rd dz k - else loadimm_n sz rd dn k. - -Definition loadimm32 (rd: ireg) (n: int) (k: code) : code := - if is_logical_imm32 n - then Porrimm W rd XZR (Int.unsigned n) :: k - else loadimm W rd (Int.unsigned n) k. - -Definition loadimm64 (rd: ireg) (n: int64) (k: code) : code := - if is_logical_imm64 n - then Porrimm X rd XZR (Int64.unsigned n) :: k - else loadimm X rd (Int64.unsigned n) k. - -(** Add immediate *) - -Definition addimm_aux (insn: iregsp -> iregsp -> Z -> instruction) - (rd r1: iregsp) (n: Z) (k: code) := - let nlo := Zzero_ext 12 n in - let nhi := n - nlo in - if Z.eqb nhi 0 then - insn rd r1 nlo :: k - else if Z.eqb nlo 0 then - insn rd r1 nhi :: k - else - insn rd r1 nhi :: insn rd rd nlo :: k. - -Definition addimm32 (rd r1: ireg) (n: int) (k: code) : code := - let m := Int.neg n in - if Int.eq n (Int.zero_ext 24 n) then - addimm_aux (Paddimm W) rd r1 (Int.unsigned n) k - else if Int.eq m (Int.zero_ext 24 m) then - addimm_aux (Psubimm W) rd r1 (Int.unsigned m) k - else if Int.lt n Int.zero then - loadimm32 X16 m (Psub W rd r1 X16 SOnone :: k) - else - loadimm32 X16 n (Padd W rd r1 X16 SOnone :: k). - -Definition addimm64 (rd r1: iregsp) (n: int64) (k: code) : code := - let m := Int64.neg n in - if Int64.eq n (Int64.zero_ext 24 n) then - addimm_aux (Paddimm X) rd r1 (Int64.unsigned n) k - else if Int64.eq m (Int64.zero_ext 24 m) then - addimm_aux (Psubimm X) rd r1 (Int64.unsigned m) k - else if Int64.lt n Int64.zero then - loadimm64 X16 m (Psubext rd r1 X16 (EOuxtx Int.zero) :: k) - else - loadimm64 X16 n (Paddext rd r1 X16 (EOuxtx Int.zero) :: k). +Require Import Locations Compopts. +Require Import Mach Asm Asmblock Asmblockgen Machblockgen PseudoAsmblock PseudoAsmblockproof PostpassScheduling. -(** Logical immediate *) -Definition logicalimm32 - (insn1: ireg -> ireg0 -> Z -> instruction) - (insn2: ireg -> ireg0 -> ireg -> shift_op -> instruction) - (rd r1: ireg) (n: int) (k: code) : code := - if is_logical_imm32 n - then insn1 rd r1 (Int.unsigned n) :: k - else loadimm32 X16 n (insn2 rd r1 X16 SOnone :: k). - -Definition logicalimm64 - (insn1: ireg -> ireg0 -> Z -> instruction) - (insn2: ireg -> ireg0 -> ireg -> shift_op -> instruction) - (rd r1: ireg) (n: int64) (k: code) : code := - if is_logical_imm64 n - then insn1 rd r1 (Int64.unsigned n) :: k - else loadimm64 X16 n (insn2 rd r1 X16 SOnone :: k). - -(** Sign- or zero-extended arithmetic *) - -Definition transl_extension (ex: extension) (a: int) : extend_op := - match ex with Xsgn32 => EOsxtw a | Xuns32 => EOuxtw a end. - -Definition move_extended_base - (rd: ireg) (r1: ireg) (ex: extension) (k: code) : code := - match ex with - | Xsgn32 => Pcvtsw2x rd r1 :: k - | Xuns32 => Pcvtuw2x rd r1 :: k - end. - -Definition move_extended - (rd: ireg) (r1: ireg) (ex: extension) (a: int) (k: code) : code := - if Int.eq a Int.zero then - move_extended_base rd r1 ex k - else - move_extended_base rd r1 ex (Padd X rd XZR rd (SOlsl a) :: k). - -Definition arith_extended - (insnX: iregsp -> iregsp -> ireg -> extend_op -> instruction) - (insnS: ireg -> ireg0 -> ireg -> shift_op -> instruction) - (rd r1 r2: ireg) (ex: extension) (a: int) (k: code) : code := - if Int.ltu a (Int.repr 5) then - insnX rd r1 r2 (transl_extension ex a) :: k - else - move_extended_base X16 r2 ex (insnS rd r1 X16 (SOlsl a) :: k). - -(** Extended right shift *) - -Definition shrx32 (rd r1: ireg) (n: int) (k: code) : code := - if Int.eq n Int.zero then - Pmov rd r1 :: k - else if Int.eq n Int.one then - Padd W X16 r1 r1 (SOlsr (Int.repr 31)) :: - Porr W rd XZR X16 (SOasr n) :: k - else - Porr W X16 XZR r1 (SOasr (Int.repr 31)) :: - Padd W X16 r1 X16 (SOlsr (Int.sub Int.iwordsize n)) :: - Porr W rd XZR X16 (SOasr n) :: k. - -Definition shrx64 (rd r1: ireg) (n: int) (k: code) : code := - if Int.eq n Int.zero then - Pmov rd r1 :: k - else if Int.eq n Int.one then - Padd X X16 r1 r1 (SOlsr (Int.repr 63)) :: - Porr X rd XZR X16 (SOasr n) :: k - else - Porr X X16 XZR r1 (SOasr (Int.repr 63)) :: - Padd X X16 r1 X16 (SOlsr (Int.sub Int64.iwordsize' n)) :: - Porr X rd XZR X16 (SOasr n) :: k. - -(** Load the address [id + ofs] in [rd] *) - -Definition loadsymbol (rd: ireg) (id: ident) (ofs: ptrofs) (k: code) : code := - if Archi.pic_code tt then - if Ptrofs.eq ofs Ptrofs.zero then - Ploadsymbol rd id :: k - else - Ploadsymbol rd id :: addimm64 rd rd (Ptrofs.to_int64 ofs) k - else - Padrp rd id ofs :: Paddadr rd rd id ofs :: k. - -(** Translate a shifted operand *) - -Definition transl_shift (s: Op.shift) (a: int): Asm.shift_op := - match s with - | Slsl => SOlsl a - | Slsr => SOlsr a - | Sasr => SOasr a - | Sror => SOror a - end. - -(** Translation of a condition. Prepends to [k] the instructions - that evaluate the condition and leave its boolean result in one of - the bits of the condition register. The bit in question is - determined by the [crbit_for_cond] function. *) - -Definition transl_cond - (cond: condition) (args: list mreg) (k: code) := - match cond, args with - | (Ccomp c | Ccompu c), a1 :: a2 :: nil => - do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Pcmp W r1 r2 SOnone :: k) - | (Ccompshift c s a | Ccompushift c s a), a1 :: a2 :: nil => - do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Pcmp W r1 r2 (transl_shift s a) :: k) - | (Ccompimm c n | Ccompuimm c n), a1 :: nil => - do r1 <- ireg_of a1; - OK (if is_arith_imm32 n then - Pcmpimm W r1 (Int.unsigned n) :: k - else if is_arith_imm32 (Int.neg n) then - Pcmnimm W r1 (Int.unsigned (Int.neg n)) :: k - else - loadimm32 X16 n (Pcmp W r1 X16 SOnone :: k)) - | (Cmaskzero n | Cmasknotzero n), a1 :: nil => - do r1 <- ireg_of a1; - OK (if is_logical_imm32 n then - Ptstimm W r1 (Int.unsigned n) :: k - else - loadimm32 X16 n (Ptst W r1 X16 SOnone :: k)) - | (Ccompl c | Ccomplu c), a1 :: a2 :: nil => - do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Pcmp X r1 r2 SOnone :: k) - | (Ccomplshift c s a | Ccomplushift c s a), a1 :: a2 :: nil => - do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Pcmp X r1 r2 (transl_shift s a) :: k) - | (Ccomplimm c n | Ccompluimm c n), a1 :: nil => - do r1 <- ireg_of a1; - OK (if is_arith_imm64 n then - Pcmpimm X r1 (Int64.unsigned n) :: k - else if is_arith_imm64 (Int64.neg n) then - Pcmnimm X r1 (Int64.unsigned (Int64.neg n)) :: k - else - loadimm64 X16 n (Pcmp X r1 X16 SOnone :: k)) - | (Cmasklzero n | Cmasklnotzero n), a1 :: nil => - do r1 <- ireg_of a1; - OK (if is_logical_imm64 n then - Ptstimm X r1 (Int64.unsigned n) :: k - else - loadimm64 X16 n (Ptst X r1 X16 SOnone :: k)) - | Ccompf cmp, a1 :: a2 :: nil => - do r1 <- freg_of a1; do r2 <- freg_of a2; - OK (Pfcmp D r1 r2 :: k) - | Cnotcompf cmp, a1 :: a2 :: nil => - do r1 <- freg_of a1; do r2 <- freg_of a2; - OK (Pfcmp D r1 r2 :: k) - | Ccompfzero cmp, a1 :: nil => - do r1 <- freg_of a1; - OK (Pfcmp0 D r1 :: k) - | Cnotcompfzero cmp, a1 :: nil => - do r1 <- freg_of a1; - OK (Pfcmp0 D r1 :: k) - | Ccompfs cmp, a1 :: a2 :: nil => - do r1 <- freg_of a1; do r2 <- freg_of a2; - OK (Pfcmp S r1 r2 :: k) - | Cnotcompfs cmp, a1 :: a2 :: nil => - do r1 <- freg_of a1; do r2 <- freg_of a2; - OK (Pfcmp S r1 r2 :: k) - | Ccompfszero cmp, a1 :: nil => - do r1 <- freg_of a1; - OK (Pfcmp0 S r1 :: k) - | Cnotcompfszero cmp, a1 :: nil => - do r1 <- freg_of a1; - OK (Pfcmp0 S r1 :: k) - | _, _ => - Error(msg "Asmgen.transl_cond") - end. +Local Open Scope error_monad_scope. -Definition cond_for_signed_cmp (cmp: comparison) := - match cmp with - | Ceq => TCeq - | Cne => TCne - | Clt => TClt - | Cle => TCle - | Cgt => TCgt - | Cge => TCge - end. +(** * Translation from Asmblock to assembly language + Inspired from the KVX backend (see kvx/Asm.v and kvx/Asmgen.v) *) -Definition cond_for_unsigned_cmp (cmp: comparison) := - match cmp with - | Ceq => TCeq - | Cne => TCne - | Clt => TClo - | Cle => TCls - | Cgt => TChi - | Cge => TChs - end. +Module Asmblock_TRANSF. +(* STUB *) -Definition cond_for_float_cmp (cmp: comparison) := - match cmp with - | Ceq => TCeq - | Cne => TCne - | Clt => TCmi - | Cle => TCls - | Cgt => TCgt - | Cge => TCge +Definition ireg_of_preg (p : Asm.preg) : res ireg := + match p with + | DR (IR (RR1 r)) => OK r + | _ => Error (msg "Asmgen.ireg_of_preg") end. -Definition cond_for_float_not_cmp (cmp: comparison) := - match cmp with - | Ceq => TCne - | Cne => TCeq - | Clt => TCpl - | Cle => TChi - | Cgt => TCle - | Cge => TClt +Definition freg_of_preg (p : Asm.preg) : res freg := + match p with + | DR (FR r) => OK r + | _ => Error (msg "Asmgen.freg_of_preg") end. -Definition cond_for_cond (cond: condition) := - match cond with - | Ccomp cmp => cond_for_signed_cmp cmp - | Ccompu cmp => cond_for_unsigned_cmp cmp - | Ccompshift cmp s a => cond_for_signed_cmp cmp - | Ccompushift cmp s a => cond_for_unsigned_cmp cmp - | Ccompimm cmp n => cond_for_signed_cmp cmp - | Ccompuimm cmp n => cond_for_unsigned_cmp cmp - | Cmaskzero n => TCeq - | Cmasknotzero n => TCne - | Ccompl cmp => cond_for_signed_cmp cmp - | Ccomplu cmp => cond_for_unsigned_cmp cmp - | Ccomplshift cmp s a => cond_for_signed_cmp cmp - | Ccomplushift cmp s a => cond_for_unsigned_cmp cmp - | Ccomplimm cmp n => cond_for_signed_cmp cmp - | Ccompluimm cmp n => cond_for_unsigned_cmp cmp - | Cmasklzero n => TCeq - | Cmasklnotzero n => TCne - | Ccompf cmp => cond_for_float_cmp cmp - | Cnotcompf cmp => cond_for_float_not_cmp cmp - | Ccompfzero cmp => cond_for_float_cmp cmp - | Cnotcompfzero cmp => cond_for_float_not_cmp cmp - | Ccompfs cmp => cond_for_float_cmp cmp - | Cnotcompfs cmp => cond_for_float_not_cmp cmp - | Ccompfszero cmp => cond_for_float_cmp cmp - | Cnotcompfszero cmp => cond_for_float_not_cmp cmp +Definition iregsp_of_preg (p : Asm.preg) : res iregsp := + match p with + | DR (IR r) => OK r + | _ => Error (msg "Asmgen.iregsp_of_preg") end. -(** Translation of a conditional branch. Prepends to [k] the instructions - that evaluate the condition and ranch to [lbl] if it holds. - We recognize some conditional branches that can be implemented - without setting then testing condition flags. *) - -Definition transl_cond_branch_default - (c: condition) (args: list mreg) (lbl: label) (k: code) := - transl_cond c args (Pbc (cond_for_cond c) lbl :: k). - -Definition transl_cond_branch - (c: condition) (args: list mreg) (lbl: label) (k: code) := - match args, c with - | a1 :: nil, (Ccompimm Cne n | Ccompuimm Cne n) => - if Int.eq n Int.zero - then (do r1 <- ireg_of a1; OK (Pcbnz W r1 lbl :: k)) - else transl_cond_branch_default c args lbl k - | a1 :: nil, (Ccompimm Ceq n | Ccompuimm Ceq n) => - if Int.eq n Int.zero - then (do r1 <- ireg_of a1; OK (Pcbz W r1 lbl :: k)) - else transl_cond_branch_default c args lbl k - | a1 :: nil, (Ccomplimm Cne n | Ccompluimm Cne n) => - if Int64.eq n Int64.zero - then (do r1 <- ireg_of a1; OK (Pcbnz X r1 lbl :: k)) - else transl_cond_branch_default c args lbl k - | a1 :: nil, (Ccomplimm Ceq n | Ccompluimm Ceq n) => - if Int64.eq n Int64.zero - then (do r1 <- ireg_of a1; OK (Pcbz X r1 lbl :: k)) - else transl_cond_branch_default c args lbl k - | a1 :: nil, Cmaskzero n => - match Int.is_power2 n with - | Some bit => do r1 <- ireg_of a1; OK (Ptbz W r1 bit lbl :: k) - | None => transl_cond_branch_default c args lbl k +Definition basic_to_instruction (b: basic) : res Asm.instruction := + match b with + (* Aithmetic instructions *) + | PArith (PArithP (Padrp id ofs) rd) => do rd' <- ireg_of_preg rd; + OK (Asm.Padrp rd' id ofs) + | PArith (PArithP (Pmovz sz n pos) rd) => do rd' <- ireg_of_preg rd; + OK (Asm.Pmovz sz rd' n pos) + | PArith (PArithP (Pmovn sz n pos) rd) => do rd' <- ireg_of_preg rd; + OK (Asm.Pmovn sz rd' n pos) + | PArith (PArithP (Pfmovimms f) rd) => do rd' <- freg_of_preg rd; + OK (Asm.Pfmovimms rd' f) + | PArith (PArithP (Pfmovimmd f) rd) => do rd' <- freg_of_preg rd; + OK (Asm.Pfmovimmd rd' f) + + | PArith (PArithPP (Pmovk sz n pos) rd rs) => + if (Asm.preg_eq rd rs) then ( + do rd' <- ireg_of_preg rd; + OK (Asm.Pmovk sz rd' n pos) + ) else + Error (msg "Asmgen.basic_to_instruction: Pmovk uses a single register as both source and target") + | PArith (PArithPP Pmov rd rs) => do rd' <- iregsp_of_preg rd; + do rs' <- iregsp_of_preg rs; + OK (Asm.Pmov rd' rs') + | PArith (PArithPP (Paddadr id ofs) rd rs) => do rd' <- ireg_of_preg rd; + do rs' <- ireg_of_preg rs; + OK (Asm.Paddadr rd' rs' id ofs) + | PArith (PArithPP (Psbfiz sz r s) rd rs) => do rd' <- ireg_of_preg rd; + do rs' <- ireg_of_preg rs; + OK (Asm.Psbfiz sz rd' rs' r s) + | PArith (PArithPP (Psbfx sz r s) rd rs) => do rd' <- ireg_of_preg rd; + do rs' <- ireg_of_preg rs; + OK (Asm.Psbfx sz rd' rs' r s) + | PArith (PArithPP (Pubfiz sz r s) rd rs) => do rd' <- ireg_of_preg rd; + do rs' <- ireg_of_preg rs; + OK (Asm.Pubfiz sz rd' rs' r s) + | PArith (PArithPP (Pubfx sz r s) rd rs) => do rd' <- ireg_of_preg rd; + do rs' <- ireg_of_preg rs; + OK (Asm.Pubfx sz rd' rs' r s) + | PArith (PArithPP Pfmov rd rs) => do rd' <- freg_of_preg rd; + do rs' <- freg_of_preg rs; + OK (Asm.Pfmov rd' rs') + | PArith (PArithPP Pfcvtds rd rs) => do rd' <- freg_of_preg rd; + do rs' <- freg_of_preg rs; + OK (Asm.Pfcvtds rd' rs') + | PArith (PArithPP Pfcvtsd rd rs) => do rd' <- freg_of_preg rd; + do rs' <- freg_of_preg rs; + OK (Asm.Pfcvtsd rd' rs') + | PArith (PArithPP (Pfabs sz) rd rs) => do rd' <- freg_of_preg rd; + do rs' <- freg_of_preg rs; + OK (Asm.Pfabs sz rd' rs') + | PArith (PArithPP (Pfneg sz) rd rs) => do rd' <- freg_of_preg rd; + do rs' <- freg_of_preg rs; + OK (Asm.Pfneg sz rd' rs') + | PArith (PArithPP (Pscvtf fsz isz) rd rs) => do rd' <- freg_of_preg rd; + do rs' <- ireg_of_preg rs; + OK (Asm.Pscvtf fsz isz rd' rs') + | PArith (PArithPP (Pucvtf fsz isz) rd rs) => do rd' <- freg_of_preg rd; + do rs' <- ireg_of_preg rs; + OK (Asm.Pucvtf fsz isz rd' rs') + | PArith (PArithPP (Pfcvtzs isz fsz) rd rs) => do rd' <- ireg_of_preg rd; + do rs' <- freg_of_preg rs; + OK (Asm.Pfcvtzs isz fsz rd' rs') + | PArith (PArithPP (Pfcvtzu isz fsz) rd rs) => do rd' <- ireg_of_preg rd; + do rs' <- freg_of_preg rs; + OK (Asm.Pfcvtzu isz fsz rd' rs') + | PArith (PArithPP (Paddimm sz n) rd rs) => do rd' <- iregsp_of_preg rd; + do rs' <- iregsp_of_preg rs; + OK (Asm.Paddimm sz rd' rs' n) + | PArith (PArithPP (Psubimm sz n) rd rs) => do rd' <- iregsp_of_preg rd; + do rs' <- iregsp_of_preg rs; + OK (Asm.Psubimm sz rd' rs' n) + + | PArith (PArithPPP (Pasrv sz) rd r1 r2) => do rd' <- ireg_of_preg rd; + do r1' <- ireg_of_preg r1; + do r2' <- ireg_of_preg r2; + OK (Asm.Pasrv sz rd' r1' r2') + | PArith (PArithPPP (Plslv sz) rd r1 r2) => do rd' <- ireg_of_preg rd; + do r1' <- ireg_of_preg r1; + do r2' <- ireg_of_preg r2; + OK (Asm.Plslv sz rd' r1' r2') + | PArith (PArithPPP (Plsrv sz) rd r1 r2) => do rd' <- ireg_of_preg rd; + do r1' <- ireg_of_preg r1; + do r2' <- ireg_of_preg r2; + OK (Asm.Plsrv sz rd' r1' r2') + | PArith (PArithPPP (Prorv sz) rd r1 r2) => do rd' <- ireg_of_preg rd; + do r1' <- ireg_of_preg r1; + do r2' <- ireg_of_preg r2; + OK (Asm.Prorv sz rd' r1' r2') + | PArith (PArithPPP Psmulh rd r1 r2) => do rd' <- ireg_of_preg rd; + do r1' <- ireg_of_preg r1; + do r2' <- ireg_of_preg r2; + OK (Asm.Psmulh rd' r1' r2') + | PArith (PArithPPP Pumulh rd r1 r2) => do rd' <- ireg_of_preg rd; + do r1' <- ireg_of_preg r1; + do r2' <- ireg_of_preg r2; + OK (Asm.Pumulh rd' r1' r2') + | PArith (PArithPPP (Psdiv sz) rd r1 r2) => do rd' <- ireg_of_preg rd; + do r1' <- ireg_of_preg r1; + do r2' <- ireg_of_preg r2; + OK (Asm.Psdiv sz rd' r1' r2') + | PArith (PArithPPP (Pudiv sz) rd r1 r2) => do rd' <- ireg_of_preg rd; + do r1' <- ireg_of_preg r1; + do r2' <- ireg_of_preg r2; + OK (Asm.Pudiv sz rd' r1' r2') + | PArith (PArithPPP (Paddext x) rd r1 r2) => do rd' <- iregsp_of_preg rd; + do r1' <- iregsp_of_preg r1; + do r2' <- ireg_of_preg r2; + OK (Asm.Paddext rd' r1' r2' x) + | PArith (PArithPPP (Psubext x) rd r1 r2) => do rd' <- iregsp_of_preg rd; + do r1' <- iregsp_of_preg r1; + do r2' <- ireg_of_preg r2; + OK (Asm.Psubext rd' r1' r2' x) + | PArith (PArithPPP (Pfadd sz) rd r1 r2) => do rd' <- freg_of_preg rd; + do r1' <- freg_of_preg r1; + do r2' <- freg_of_preg r2; + OK (Asm.Pfadd sz rd' r1' r2') + | PArith (PArithPPP (Pfdiv sz) rd r1 r2) => do rd' <- freg_of_preg rd; + do r1' <- freg_of_preg r1; + do r2' <- freg_of_preg r2; + OK (Asm.Pfdiv sz rd' r1' r2') + | PArith (PArithPPP (Pfmul sz) rd r1 r2) => do rd' <- freg_of_preg rd; + do r1' <- freg_of_preg r1; + do r2' <- freg_of_preg r2; + OK (Asm.Pfmul sz rd' r1' r2') + | PArith (PArithPPP (Pfsub sz) rd r1 r2) => do rd' <- freg_of_preg rd; + do r1' <- freg_of_preg r1; + do r2' <- freg_of_preg r2; + OK (Asm.Pfsub sz rd' r1' r2') + + | PArith (PArithRR0 (Pandimm sz n) rd r1) => OK (Asm.Pandimm sz rd r1 n) + | PArith (PArithRR0 (Peorimm sz n) rd r1) => OK (Asm.Peorimm sz rd r1 n) + | PArith (PArithRR0 (Porrimm sz n) rd r1) => OK (Asm.Porrimm sz rd r1 n) + + + | PArith (PArithRR0R (Padd sz s) rd r1 r2) => OK (Asm.Padd sz rd r1 r2 s) + | PArith (PArithRR0R (Psub sz s) rd r1 r2) => OK (Asm.Psub sz rd r1 r2 s) + | PArith (PArithRR0R (Pand sz s) rd r1 r2) => OK (Asm.Pand sz rd r1 r2 s) + | PArith (PArithRR0R (Pbic sz s) rd r1 r2) => OK (Asm.Pbic sz rd r1 r2 s) + | PArith (PArithRR0R (Peon sz s) rd r1 r2) => OK (Asm.Peon sz rd r1 r2 s) + | PArith (PArithRR0R (Peor sz s) rd r1 r2) => OK (Asm.Peor sz rd r1 r2 s) + | PArith (PArithRR0R (Porr sz s) rd r1 r2) => OK (Asm.Porr sz rd r1 r2 s) + | PArith (PArithRR0R (Porn sz s) rd r1 r2) => OK (Asm.Porn sz rd r1 r2 s) + + | PArith (PArithARRRR0 (Pmadd sz) rd r1 r2 r3) => OK (Asm.Pmadd sz rd r1 r2 r3) + | PArith (PArithARRRR0 (Pmsub sz) rd r1 r2 r3) => OK (Asm.Pmsub sz rd r1 r2 r3) + + | PArith (PArithComparisonPP (Pcmpext x) r1 r2) => do r1' <- ireg_of_preg r1; + do r2' <- ireg_of_preg r2; + OK (Asm.Pcmpext r1' r2' x) + | PArith (PArithComparisonPP (Pcmnext x) r1 r2) => do r1' <- ireg_of_preg r1; + do r2' <- ireg_of_preg r2; + OK (Asm.Pcmnext r1' r2' x) + | PArith (PArithComparisonPP (Pfcmp sz) r1 r2) => do r1' <- freg_of_preg r1; + do r2' <- freg_of_preg r2; + OK (Asm.Pfcmp sz r1' r2') + + | PArith (PArithComparisonR0R (Pcmp is s) r1 r2) => OK (Asm.Pcmp is r1 r2 s) + | PArith (PArithComparisonR0R (Pcmn is s) r1 r2) => OK (Asm.Pcmn is r1 r2 s) + | PArith (PArithComparisonR0R (Ptst is s) r1 r2) => OK (Asm.Ptst is r1 r2 s) + + | PArith (PArithComparisonP (Pcmpimm sz n) r1) => do r1' <- ireg_of_preg r1; + OK (Asm.Pcmpimm sz r1' n) + | PArith (PArithComparisonP (Pcmnimm sz n) r1) => do r1' <- ireg_of_preg r1; + OK (Asm.Pcmnimm sz r1' n) + | PArith (PArithComparisonP (Ptstimm sz n) r1) => do r1' <- ireg_of_preg r1; + OK (Asm.Ptstimm sz r1' n) + | PArith (PArithComparisonP (Pfcmp0 sz) r1) => do r1' <- freg_of_preg r1; + OK (Asm.Pfcmp0 sz r1') + + | PArith (Pcset rd c) => OK (Asm.Pcset rd c) + | PArith (Pfmovi fsz rd r1) => OK (Asm.Pfmovi fsz rd r1) + | PArith (Pcsel rd r1 r2 c) => + match r1, r2 with + | IR r1', IR r2' => do rd' <- ireg_of_preg rd; + do r1'' <- ireg_of_preg r1'; + do r2'' <- ireg_of_preg r2'; + OK (Asm.Pcsel rd' r1'' r2'' c) + | FR r1', FR r2' => do rd' <- freg_of_preg rd; + do r1'' <- freg_of_preg r1'; + do r2'' <- freg_of_preg r2'; + OK (Asm.Pfsel rd' r1'' r2'' c) + | _, _ => Error (msg "Asmgen.basic_to_instruction: Pcsel is only defind on iregs and fregs.") end - | a1 :: nil, Cmasknotzero n => - match Int.is_power2 n with - | Some bit => do r1 <- ireg_of a1; OK (Ptbnz W r1 bit lbl :: k) - | None => transl_cond_branch_default c args lbl k - end - | a1 :: nil, Cmasklzero n => - match Int64.is_power2' n with - | Some bit => do r1 <- ireg_of a1; OK (Ptbz X r1 bit lbl :: k) - | None => transl_cond_branch_default c args lbl k - end - | a1 :: nil, Cmasklnotzero n => - match Int64.is_power2' n with - | Some bit => do r1 <- ireg_of a1; OK (Ptbnz X r1 bit lbl :: k) - | None => transl_cond_branch_default c args lbl k - end - | _, _ => - transl_cond_branch_default c args lbl k - end. - -(** Translation of the arithmetic operation [res <- op(args)]. - The corresponding instructions are prepended to [k]. *) + | PArith (Pfnmul fsz rd r1 r2) => OK (Asm.Pfnmul fsz rd r1 r2) -Definition transl_op - (op: operation) (args: list mreg) (res: mreg) (k: code) := - match op, args with - | Omove, a1 :: nil => - match preg_of res, preg_of a1 with - | IR r, IR a => OK (Pmov r a :: k) - | FR r, FR a => OK (Pfmov r a :: k) - | _ , _ => Error(msg "Asmgen.Omove") - end - | Ointconst n, nil => - do rd <- ireg_of res; - OK (loadimm32 rd n k) - | Olongconst n, nil => - do rd <- ireg_of res; - OK (loadimm64 rd n k) - | Ofloatconst f, nil => - do rd <- freg_of res; - OK (if Float.eq_dec f Float.zero - then Pfmovi D rd XZR :: k - else Pfmovimmd rd f :: k) - | Osingleconst f, nil => - do rd <- freg_of res; - OK (if Float32.eq_dec f Float32.zero - then Pfmovi S rd XZR :: k - else Pfmovimms rd f :: k) - | Oaddrsymbol id ofs, nil => - do rd <- ireg_of res; - OK (loadsymbol rd id ofs k) - | Oaddrstack ofs, nil => - do rd <- ireg_of res; - OK (addimm64 rd XSP (Ptrofs.to_int64 ofs) k) -(** 32-bit integer arithmetic *) - | Oshift s a, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (Porr W rd XZR r1 (transl_shift s a) :: k) - | Oadd, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Padd W rd r1 r2 SOnone :: k) - | Oaddshift s a, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Padd W rd r1 r2 (transl_shift s a) :: k) - | Oaddimm n, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (addimm32 rd r1 n k) - | Oneg, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (Psub W rd XZR r1 SOnone :: k) - | Onegshift s a, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (Psub W rd XZR r1 (transl_shift s a) :: k) - | Osub, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Psub W rd r1 r2 SOnone :: k) - | Osubshift s a, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Psub W rd r1 r2 (transl_shift s a) :: k) - | Omul, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Pmadd W rd r1 r2 XZR :: k) - | Omuladd, a1 :: a2 :: a3 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; do r3 <- ireg_of a3; - OK (Pmadd W rd r2 r3 r1 :: k) - | Omulsub, a1 :: a2 :: a3 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; do r3 <- ireg_of a3; - OK (Pmsub W rd r2 r3 r1 :: k) - | Odiv, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Psdiv W rd r1 r2 :: k) - | Odivu, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Pudiv W rd r1 r2 :: k) - | Oand, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Pand W rd r1 r2 SOnone :: k) - | Oandshift s a, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Pand W rd r1 r2 (transl_shift s a) :: k) - | Oandimm n, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (logicalimm32 (Pandimm W) (Pand W) rd r1 n k) - | Oor, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Porr W rd r1 r2 SOnone :: k) - | Oorshift s a, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Porr W rd r1 r2 (transl_shift s a) :: k) - | Oorimm n, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (logicalimm32 (Porrimm W) (Porr W) rd r1 n k) - | Oxor, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Peor W rd r1 r2 SOnone :: k) - | Oxorshift s a, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Peor W rd r1 r2 (transl_shift s a) :: k) - | Oxorimm n, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (logicalimm32 (Peorimm W) (Peor W) rd r1 n k) - | Onot, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (Porn W rd XZR r1 SOnone :: k) - | Onotshift s a, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (Porn W rd XZR r1 (transl_shift s a) :: k) - | Obic, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Pbic W rd r1 r2 SOnone :: k) - | Obicshift s a, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Pbic W rd r1 r2 (transl_shift s a) :: k) - | Oorn, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Porn W rd r1 r2 SOnone :: k) - | Oornshift s a, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Porn W rd r1 r2 (transl_shift s a) :: k) - | Oeqv, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Peon W rd r1 r2 SOnone :: k) - | Oeqvshift s a, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Peon W rd r1 r2 (transl_shift s a) :: k) - | Oshl, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Plslv W rd r1 r2 :: k) - | Oshr, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Pasrv W rd r1 r2 :: k) - | Oshru, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Plsrv W rd r1 r2 :: k) - | Oshrximm n, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (shrx32 rd r1 n k) - | Ozext s, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (Pubfiz W rd r1 Int.zero s :: k) - | Osext s, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (Psbfiz W rd r1 Int.zero s :: k) - | Oshlzext s a, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (Pubfiz W rd r1 a (Z.min s (Int.zwordsize - Int.unsigned a)) :: k) - | Oshlsext s a, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (Psbfiz W rd r1 a (Z.min s (Int.zwordsize - Int.unsigned a)) :: k) - | Ozextshr a s, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (Pubfx W rd r1 a (Z.min s (Int.zwordsize - Int.unsigned a)) :: k) - | Osextshr a s, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (Psbfx W rd r1 a (Z.min s (Int.zwordsize - Int.unsigned a)) :: k) -(** 64-bit integer arithmetic *) - | Oshiftl s a, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (Porr X rd XZR r1 (transl_shift s a) :: k) - | Oextend x a, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (move_extended rd r1 x a k) - (* [Omakelong] and [Ohighlong] should not occur *) - | Olowlong, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - assertion (ireg_eq rd r1); - OK (Pcvtx2w rd :: k) - | Oaddl, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Padd X rd r1 r2 SOnone :: k) - | Oaddlshift s a, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Padd X rd r1 r2 (transl_shift s a) :: k) - | Oaddlext x a, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (arith_extended Paddext (Padd X) rd r1 r2 x a k) - | Oaddlimm n, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (addimm64 rd r1 n k) - | Onegl, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (Psub X rd XZR r1 SOnone :: k) - | Oneglshift s a, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (Psub X rd XZR r1 (transl_shift s a) :: k) - | Osubl, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Psub X rd r1 r2 SOnone :: k) - | Osublshift s a, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Psub X rd r1 r2 (transl_shift s a) :: k) - | Osublext x a, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (arith_extended Psubext (Psub X) rd r1 r2 x a k) - | Omull, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Pmadd X rd r1 r2 XZR :: k) - | Omulladd, a1 :: a2 :: a3 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; do r3 <- ireg_of a3; - OK (Pmadd X rd r2 r3 r1 :: k) - | Omullsub, a1 :: a2 :: a3 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; do r3 <- ireg_of a3; - OK (Pmsub X rd r2 r3 r1 :: k) - | Omullhs, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Psmulh rd r1 r2 :: k) - | Omullhu, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Pumulh rd r1 r2 :: k) - | Odivl, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Psdiv X rd r1 r2 :: k) - | Odivlu, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Pudiv X rd r1 r2 :: k) - | Oandl, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Pand X rd r1 r2 SOnone :: k) - | Oandlshift s a, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Pand X rd r1 r2 (transl_shift s a) :: k) - | Oandlimm n, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (logicalimm64 (Pandimm X) (Pand X) rd r1 n k) - | Oorl, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Porr X rd r1 r2 SOnone :: k) - | Oorlshift s a, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Porr X rd r1 r2 (transl_shift s a) :: k) - | Oorlimm n, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (logicalimm64 (Porrimm X) (Porr X) rd r1 n k) - | Oxorl, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Peor X rd r1 r2 SOnone :: k) - | Oxorlshift s a, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Peor X rd r1 r2 (transl_shift s a) :: k) - | Oxorlimm n, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (logicalimm64 (Peorimm X) (Peor X) rd r1 n k) - | Onotl, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (Porn X rd XZR r1 SOnone :: k) - | Onotlshift s a, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (Porn X rd XZR r1 (transl_shift s a) :: k) - | Obicl, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Pbic X rd r1 r2 SOnone :: k) - | Obiclshift s a, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Pbic X rd r1 r2 (transl_shift s a) :: k) - | Oornl, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Porn X rd r1 r2 SOnone :: k) - | Oornlshift s a, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Porn X rd r1 r2 (transl_shift s a) :: k) - | Oeqvl, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Peon X rd r1 r2 SOnone :: k) - | Oeqvlshift s a, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Peon X rd r1 r2 (transl_shift s a) :: k) - | Oshll, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Plslv X rd r1 r2 :: k) - | Oshrl, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Pasrv X rd r1 r2 :: k) - | Oshrlu, a1 :: a2 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (Plsrv X rd r1 r2 :: k) - | Oshrlximm n, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (shrx64 rd r1 n k) - | Ozextl s, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (Pubfiz X rd r1 Int.zero s :: k) - | Osextl s, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (Psbfiz X rd r1 Int.zero s :: k) - | Oshllzext s a, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (Pubfiz X rd r1 a (Z.min s (Int64.zwordsize - Int.unsigned a)) :: k) - | Oshllsext s a, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (Psbfiz X rd r1 a (Z.min s (Int64.zwordsize - Int.unsigned a)) :: k) - | Ozextshrl a s, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (Pubfx X rd r1 a (Z.min s (Int64.zwordsize - Int.unsigned a)) :: k) - | Osextshrl a s, a1 :: nil => - do rd <- ireg_of res; do r1 <- ireg_of a1; - OK (Psbfx X rd r1 a (Z.min s (Int64.zwordsize - Int.unsigned a)) :: k) -(** 64-bit floating-point arithmetic *) - | Onegf, a1 :: nil => - do rd <- freg_of res; do rs <- freg_of a1; - OK (Pfneg D rd rs :: k) - | Oabsf, a1 :: nil => - do rd <- freg_of res; do rs <- freg_of a1; - OK (Pfabs D rd rs :: k) - | Oaddf, a1 :: a2 :: nil => - do rd <- freg_of res; do rs1 <- freg_of a1; do rs2 <- freg_of a2; - OK (Pfadd D rd rs1 rs2 :: k) - | Osubf, a1 :: a2 :: nil => - do rd <- freg_of res; do rs1 <- freg_of a1; do rs2 <- freg_of a2; - OK (Pfsub D rd rs1 rs2 :: k) - | Omulf, a1 :: a2 :: nil => - do rd <- freg_of res; do rs1 <- freg_of a1; do rs2 <- freg_of a2; - OK (Pfmul D rd rs1 rs2 :: k) - | Odivf, a1 :: a2 :: nil => - do rd <- freg_of res; do rs1 <- freg_of a1; do rs2 <- freg_of a2; - OK (Pfdiv D rd rs1 rs2 :: k) -(** 32-bit floating-point arithmetic *) - | Onegfs, a1 :: nil => - do rd <- freg_of res; do rs <- freg_of a1; - OK (Pfneg S rd rs :: k) - | Oabsfs, a1 :: nil => - do rd <- freg_of res; do rs <- freg_of a1; - OK (Pfabs S rd rs :: k) - | Oaddfs, a1 :: a2 :: nil => - do rd <- freg_of res; do rs1 <- freg_of a1; do rs2 <- freg_of a2; - OK (Pfadd S rd rs1 rs2 :: k) - | Osubfs, a1 :: a2 :: nil => - do rd <- freg_of res; do rs1 <- freg_of a1; do rs2 <- freg_of a2; - OK (Pfsub S rd rs1 rs2 :: k) - | Omulfs, a1 :: a2 :: nil => - do rd <- freg_of res; do rs1 <- freg_of a1; do rs2 <- freg_of a2; - OK (Pfmul S rd rs1 rs2 :: k) - | Odivfs, a1 :: a2 :: nil => - do rd <- freg_of res; do rs1 <- freg_of a1; do rs2 <- freg_of a2; - OK (Pfdiv S rd rs1 rs2 :: k) - | Osingleoffloat, a1 :: nil => - do rd <- freg_of res; do rs <- freg_of a1; - OK (Pfcvtsd rd rs :: k) - | Ofloatofsingle, a1 :: nil => - do rd <- freg_of res; do rs <- freg_of a1; - OK (Pfcvtds rd rs :: k) -(** Conversions between int and float *) - | Ointoffloat, a1 :: nil => - do rd <- ireg_of res; do rs <- freg_of a1; - OK (Pfcvtzs W D rd rs :: k) - | Ointuoffloat, a1 :: nil => - do rd <- ireg_of res; do rs <- freg_of a1; - OK (Pfcvtzu W D rd rs :: k) - | Ofloatofint, a1 :: nil => - do rd <- freg_of res; do rs <- ireg_of a1; - OK (Pscvtf D W rd rs :: k) - | Ofloatofintu, a1 :: nil => - do rd <- freg_of res; do rs <- ireg_of a1; - OK (Pucvtf D W rd rs :: k) - | Ointofsingle, a1 :: nil => - do rd <- ireg_of res; do rs <- freg_of a1; - OK (Pfcvtzs W S rd rs :: k) - | Ointuofsingle, a1 :: nil => - do rd <- ireg_of res; do rs <- freg_of a1; - OK (Pfcvtzu W S rd rs :: k) - | Osingleofint, a1 :: nil => - do rd <- freg_of res; do rs <- ireg_of a1; - OK (Pscvtf S W rd rs :: k) - | Osingleofintu, a1 :: nil => - do rd <- freg_of res; do rs <- ireg_of a1; - OK (Pucvtf S W rd rs :: k) - | Olongoffloat, a1 :: nil => - do rd <- ireg_of res; do rs <- freg_of a1; - OK (Pfcvtzs X D rd rs :: k) - | Olonguoffloat, a1 :: nil => - do rd <- ireg_of res; do rs <- freg_of a1; - OK (Pfcvtzu X D rd rs :: k) - | Ofloatoflong, a1 :: nil => - do rd <- freg_of res; do rs <- ireg_of a1; - OK (Pscvtf D X rd rs :: k) - | Ofloatoflongu, a1 :: nil => - do rd <- freg_of res; do rs <- ireg_of a1; - OK (Pucvtf D X rd rs :: k) - | Olongofsingle, a1 :: nil => - do rd <- ireg_of res; do rs <- freg_of a1; - OK (Pfcvtzs X S rd rs :: k) - | Olonguofsingle, a1 :: nil => - do rd <- ireg_of res; do rs <- freg_of a1; - OK (Pfcvtzu X S rd rs :: k) - | Osingleoflong, a1 :: nil => - do rd <- freg_of res; do rs <- ireg_of a1; - OK (Pscvtf S X rd rs :: k) - | Osingleoflongu, a1 :: nil => - do rd <- freg_of res; do rs <- ireg_of a1; - OK (Pucvtf S X rd rs :: k) -(** Boolean tests *) - | Ocmp c, _ => - do rd <- ireg_of res; - transl_cond c args (Pcset rd (cond_for_cond c) :: k) -(** Conditional move *) - | Osel cmp ty, a1 :: a2 :: args => - match preg_of res with - | IR r => - do r1 <- ireg_of a1; do r2 <- ireg_of a2; - transl_cond cmp args (Pcsel r r1 r2 (cond_for_cond cmp) :: k) - | FR r => - do r1 <- freg_of a1; do r2 <- freg_of a2; - transl_cond cmp args (Pfsel r r1 r2 (cond_for_cond cmp) :: k) - | _ => - Error(msg "Asmgen.Osel") - end - | _, _ => - Error(msg "Asmgen.transl_op") - end. + | PLoad Pldrw rd a => do rd' <- ireg_of_preg rd; OK (Asm.Pldrw rd' a) + | PLoad Pldrw_a rd a => do rd' <- ireg_of_preg rd; OK (Asm.Pldrw_a rd' a) + | PLoad Pldrx rd a => do rd' <- ireg_of_preg rd; OK (Asm.Pldrx rd' a) + | PLoad Pldrx_a rd a => do rd' <- ireg_of_preg rd; OK (Asm.Pldrx_a rd' a) + | PLoad (Pldrb sz) rd a => do rd' <- ireg_of_preg rd; OK (Asm.Pldrb sz rd' a) + | PLoad (Pldrsb sz) rd a => do rd' <- ireg_of_preg rd; OK (Asm.Pldrsb sz rd' a) + | PLoad (Pldrh sz) rd a => do rd' <- ireg_of_preg rd; OK (Asm.Pldrh sz rd' a) + | PLoad (Pldrsh sz) rd a => do rd' <- ireg_of_preg rd; OK (Asm.Pldrsh sz rd' a) + | PLoad Pldrzw rd a => do rd' <- ireg_of_preg rd; OK (Asm.Pldrzw rd' a) + | PLoad Pldrsw rd a => do rd' <- ireg_of_preg rd; OK (Asm.Pldrsw rd' a) -(** Translation of addressing modes *) + | PLoad Pldrs rd a => do rd' <- freg_of_preg rd; OK (Asm.Pldrs rd' a) + | PLoad Pldrd rd a => do rd' <- freg_of_preg rd; OK (Asm.Pldrd rd' a) + | PLoad Pldrd_a rd a => do rd' <- freg_of_preg rd; OK (Asm.Pldrd_a rd' a) -Definition offset_representable (sz: Z) (ofs: int64) : bool := - let isz := Int64.repr sz in - (** either unscaled 9-bit signed *) - Int64.eq ofs (Int64.sign_ext 9 ofs) || - (** or scaled 12-bit unsigned *) - (Int64.eq (Int64.modu ofs isz) Int64.zero - && Int64.ltu ofs (Int64.shl isz (Int64.repr 12))). - -Definition transl_addressing (sz: Z) (addr: Op.addressing) (args: list mreg) - (insn: Asm.addressing -> instruction) (k: code) : res code := - match addr, args with - | Aindexed ofs, a1 :: nil => - do r1 <- ireg_of a1; - if offset_representable sz ofs then - OK (insn (ADimm r1 ofs) :: k) - else - OK (loadimm64 X16 ofs (insn (ADreg r1 X16) :: k)) - | Aindexed2, a1 :: a2 :: nil => - do r1 <- ireg_of a1; do r2 <- ireg_of a2; - OK (insn (ADreg r1 r2) :: k) - | Aindexed2shift a, a1 :: a2 :: nil => - do r1 <- ireg_of a1; do r2 <- ireg_of a2; - if Int.eq a Int.zero then - OK (insn (ADreg r1 r2) :: k) - else if Int.eq (Int.shl Int.one a) (Int.repr sz) then - OK (insn (ADlsl r1 r2 a) :: k) - else - OK (Padd X X16 r1 r2 (SOlsl a) :: insn (ADimm X16 Int64.zero) :: k) - | Aindexed2ext x a, a1 :: a2 :: nil => - do r1 <- ireg_of a1; do r2 <- ireg_of a2; - if Int.eq a Int.zero || Int.eq (Int.shl Int.one a) (Int.repr sz) then - OK (insn (match x with Xsgn32 => ADsxt r1 r2 a - | Xuns32 => ADuxt r1 r2 a end) :: k) - else - OK (arith_extended Paddext (Padd X) X16 r1 r2 x a - (insn (ADimm X16 Int64.zero) :: k)) - | Aglobal id ofs, nil => - assertion (negb (Archi.pic_code tt)); - if Ptrofs.eq (Ptrofs.modu ofs (Ptrofs.repr sz)) Ptrofs.zero && symbol_is_aligned id sz - then OK (Padrp X16 id ofs :: insn (ADadr X16 id ofs) :: k) - else OK (loadsymbol X16 id ofs (insn (ADimm X16 Int64.zero) :: k)) - | Ainstack ofs, nil => - let ofs := Ptrofs.to_int64 ofs in - if offset_representable sz ofs then - OK (insn (ADimm XSP ofs) :: k) - else - OK (loadimm64 X16 ofs (insn (ADreg XSP X16) :: k)) - | _, _ => - Error(msg "Asmgen.transl_addressing") - end. + | PStore Pstrw r a => do r' <- ireg_of_preg r; OK (Asm.Pstrw r' a) + | PStore Pstrw_a r a => do r' <- ireg_of_preg r; OK (Asm.Pstrw_a r' a) + | PStore Pstrx r a => do r' <- ireg_of_preg r; OK (Asm.Pstrx r' a) + | PStore Pstrx_a r a => do r' <- ireg_of_preg r; OK (Asm.Pstrx_a r' a) + | PStore Pstrb r a => do r' <- ireg_of_preg r; OK (Asm.Pstrb r' a) + | PStore Pstrh r a => do r' <- ireg_of_preg r; OK (Asm.Pstrh r' a) -(** Translation of loads and stores *) + | PStore Pstrs r a => do r' <- freg_of_preg r; OK (Asm.Pstrs r' a) + | PStore Pstrd r a => do r' <- freg_of_preg r; OK (Asm.Pstrd r' a) + | PStore Pstrd_a r a => do r' <- freg_of_preg r; OK (Asm.Pstrd_a r' a) -Definition transl_load (trap: trapping_mode) - (chunk: memory_chunk) (addr: Op.addressing) - (args: list mreg) (dst: mreg) (k: code) : res code := - match trap with - | NOTRAP => Error (msg "Asmgen.transl_load non-trapping loads unsupported on aarch64") - | TRAP => - match chunk with - | Mint8unsigned => - do rd <- ireg_of dst; transl_addressing 1 addr args (Pldrb W rd) k - | Mint8signed => - do rd <- ireg_of dst; transl_addressing 1 addr args (Pldrsb W rd) k - | Mint16unsigned => - do rd <- ireg_of dst; transl_addressing 2 addr args (Pldrh W rd) k - | Mint16signed => - do rd <- ireg_of dst; transl_addressing 2 addr args (Pldrsh W rd) k - | Mint32 => - do rd <- ireg_of dst; transl_addressing 4 addr args (Pldrw rd) k - | Mint64 => - do rd <- ireg_of dst; transl_addressing 8 addr args (Pldrx rd) k - | Mfloat32 => - do rd <- freg_of dst; transl_addressing 4 addr args (Pldrs rd) k - | Mfloat64 => - do rd <- freg_of dst; transl_addressing 8 addr args (Pldrd rd) k - | Many32 => - do rd <- ireg_of dst; transl_addressing 4 addr args (Pldrw_a rd) k - | Many64 => - do rd <- ireg_of dst; transl_addressing 8 addr args (Pldrx_a rd) k - end - end. + | Pallocframe sz linkofs => OK (Asm.Pallocframe sz linkofs) + | Pfreeframe sz linkofs => OK (Asm.Pfreeframe sz linkofs) -Definition transl_store (chunk: memory_chunk) (addr: Op.addressing) - (args: list mreg) (src: mreg) (k: code) : res code := - match chunk with - | Mint8unsigned | Mint8signed => - do r1 <- ireg_of src; transl_addressing 1 addr args (Pstrb r1) k - | Mint16unsigned | Mint16signed => - do r1 <- ireg_of src; transl_addressing 2 addr args (Pstrh r1) k - | Mint32 => - do r1 <- ireg_of src; transl_addressing 4 addr args (Pstrw r1) k - | Mint64 => - do r1 <- ireg_of src; transl_addressing 8 addr args (Pstrx r1) k - | Mfloat32 => - do r1 <- freg_of src; transl_addressing 4 addr args (Pstrs r1) k - | Mfloat64 => - do r1 <- freg_of src; transl_addressing 8 addr args (Pstrd r1) k - | Many32 => - do r1 <- ireg_of src; transl_addressing 4 addr args (Pstrw_a r1) k - | Many64 => - do r1 <- ireg_of src; transl_addressing 8 addr args (Pstrx_a r1) k - end. + | Ploadsymbol rd id => OK (Asm.Ploadsymbol rd id) -(** Register-indexed loads and stores *) + | Pcvtsw2x rd r1 => OK (Asm.Pcvtsw2x rd r1) -Definition indexed_memory_access (insn: Asm.addressing -> instruction) - (sz: Z) (base: iregsp) (ofs: ptrofs) (k: code) := - let ofs := Ptrofs.to_int64 ofs in - if offset_representable sz ofs - then insn (ADimm base ofs) :: k - else loadimm64 X16 ofs (insn (ADreg base X16) :: k). + | Pcvtuw2x rd r1 => OK (Asm.Pcvtuw2x rd r1) -Definition loadind (base: iregsp) (ofs: ptrofs) (ty: typ) (dst: mreg) (k: code) := - match ty, preg_of dst with - | Tint, IR rd => OK (indexed_memory_access (Pldrw rd) 4 base ofs k) - | Tlong, IR rd => OK (indexed_memory_access (Pldrx rd) 8 base ofs k) - | Tsingle, FR rd => OK (indexed_memory_access (Pldrs rd) 4 base ofs k) - | Tfloat, FR rd => OK (indexed_memory_access (Pldrd rd) 8 base ofs k) - | Tany32, IR rd => OK (indexed_memory_access (Pldrw_a rd) 4 base ofs k) - | Tany64, IR rd => OK (indexed_memory_access (Pldrx_a rd) 8 base ofs k) - | Tany64, FR rd => OK (indexed_memory_access (Pldrd_a rd) 8 base ofs k) - | _, _ => Error (msg "Asmgen.loadind") + | Pcvtx2w rd => OK (Asm.Pcvtx2w rd) end. -Definition storeind (src: mreg) (base: iregsp) (ofs: ptrofs) (ty: typ) (k: code) := - match ty, preg_of src with - | Tint, IR rd => OK (indexed_memory_access (Pstrw rd) 4 base ofs k) - | Tlong, IR rd => OK (indexed_memory_access (Pstrx rd) 8 base ofs k) - | Tsingle, FR rd => OK (indexed_memory_access (Pstrs rd) 4 base ofs k) - | Tfloat, FR rd => OK (indexed_memory_access (Pstrd rd) 8 base ofs k) - | Tany32, IR rd => OK (indexed_memory_access (Pstrw_a rd) 4 base ofs k) - | Tany64, IR rd => OK (indexed_memory_access (Pstrx_a rd) 8 base ofs k) - | Tany64, FR rd => OK (indexed_memory_access (Pstrd_a rd) 8 base ofs k) - | _, _ => Error (msg "Asmgen.storeind") +Definition cf_instruction_to_instruction (cfi: cf_instruction) : Asm.instruction := + match cfi with + | Pb l => Asm.Pb l + | Pbc c lbl => Asm.Pbc c lbl + | Pbl id sg => Asm.Pbl id sg + | Pbs id sg => Asm.Pbs id sg + | Pblr r sg => Asm.Pblr r sg + | Pbr r sg => Asm.Pbr r sg + | Pret r => Asm.Pret r + | Pcbnz sz r lbl => Asm.Pcbnz sz r lbl + | Pcbz sz r lbl => Asm.Pcbz sz r lbl + | Ptbnz sz r n lbl => Asm.Ptbnz sz r n lbl + | Ptbz sz r n lbl => Asm.Ptbz sz r n lbl + | Pbtbl r1 tbl => Asm.Pbtbl r1 tbl end. -Definition loadptr (base: iregsp) (ofs: ptrofs) (dst: ireg) (k: code) := - indexed_memory_access (Pldrx dst) 8 base ofs k. - -Definition storeptr (src: ireg) (base: iregsp) (ofs: ptrofs) (k: code) := - indexed_memory_access (Pstrx src) 8 base ofs k. - -(** Function epilogue *) - -Definition make_epilogue (f: Mach.function) (k: code) := - (* FIXME - Cannot be used because memcpy destroys X30; - issue being discussed with X. Leroy *) - (* if is_leaf_function f - then Pfreeframe f.(fn_stacksize) f.(fn_link_ofs) :: k - else*) loadptr XSP f.(fn_retaddr_ofs) RA - (Pfreeframe f.(fn_stacksize) f.(fn_link_ofs) :: k). - -(** Translation of a Mach instruction. *) - -Definition transl_instr (f: Mach.function) (i: Mach.instruction) - (r29_is_parent: bool) (k: code) : res code := - match i with - | Mgetstack ofs ty dst => - loadind XSP ofs ty dst k - | Msetstack src ofs ty => - storeind src XSP ofs ty k - | Mgetparam ofs ty dst => - (* load via the frame pointer if it is valid *) - do c <- loadind X29 ofs ty dst k; - OK (if r29_is_parent then c else loadptr XSP f.(fn_link_ofs) X29 c) - | Mop op args res => - transl_op op args res k - | Mload trap chunk addr args dst => - transl_load trap chunk addr args dst k - | Mstore chunk addr args src => - transl_store chunk addr args src k - | Mcall sig (inl r) => - do r1 <- ireg_of r; OK (Pblr r1 sig :: k) - | Mcall sig (inr symb) => - OK (Pbl symb sig :: k) - | Mtailcall sig (inl r) => - do r1 <- ireg_of r; - OK (make_epilogue f (Pbr r1 sig :: k)) - | Mtailcall sig (inr symb) => - OK (make_epilogue f (Pbs symb sig :: k)) - | Mbuiltin ef args res => - OK (Pbuiltin ef (List.map (map_builtin_arg preg_of) args) (map_builtin_res preg_of res) :: k) - | Mlabel lbl => - OK (Plabel lbl :: k) - | Mgoto lbl => - OK (Pb lbl :: k) - | Mcond cond args lbl => - transl_cond_branch cond args lbl k - | Mjumptable arg tbl => - do r <- ireg_of arg; - OK (Pbtbl r tbl :: k) - | Mreturn => - OK (make_epilogue f (Pret RA :: k)) +Definition control_to_instruction (c: control) := + match c with + | PCtlFlow i => cf_instruction_to_instruction i + | Pbuiltin ef args res => Asm.Pbuiltin ef (List.map (map_builtin_arg DR) args) (map_builtin_res DR res) end. -(** Translation of a code sequence *) - -Definition it1_is_parent (before: bool) (i: Mach.instruction) : bool := - match i with - | Msetstack src ofs ty => before - | Mgetparam ofs ty dst => negb (mreg_eq dst R29) - | Mop op args res => before && negb (mreg_eq res R29) - | _ => false +Fixpoint unfold_label (ll: list label) := + match ll with + | nil => nil + | l :: ll => Plabel l :: unfold_label ll end. -(** This is the naive definition that we no longer use because it - is not tail-recursive. It is kept as specification. *) - -Fixpoint transl_code (f: Mach.function) (il: list Mach.instruction) (it1p: bool) := - match il with +Fixpoint unfold_body (lb: list basic) : res Asm.code := + match lb with | nil => OK nil - | i1 :: il' => - do k <- transl_code f il' (it1_is_parent it1p i1); - transl_instr f i1 it1p k + | b :: lb => + (* x_is: x's instructions *) + do b_is <- basic_to_instruction b; + do lb_is <- unfold_body lb; + OK (b_is :: lb_is) end. -(** This is an equivalent definition in continuation-passing style - that runs in constant stack space. *) - -Fixpoint transl_code_rec (f: Mach.function) (il: list Mach.instruction) - (it1p: bool) (k: code -> res code) := - match il with - | nil => k nil - | i1 :: il' => - transl_code_rec f il' (it1_is_parent it1p i1) - (fun c1 => do c2 <- transl_instr f i1 it1p c1; k c2) +Definition unfold_exit (oc: option control) := + match oc with + | None => nil + | Some c => control_to_instruction c :: nil end. -Definition transl_code' (f: Mach.function) (il: list Mach.instruction) (it1p: bool) := - transl_code_rec f il it1p (fun c => OK c). +Definition unfold_bblock (bb: bblock) := + let lbl := unfold_label (header bb) in + (* + * With this dynamically checked assumption on a previous optimization we + * can show that [Asmblock.label_pos] and [Asm.label_pos] retrieve the same + * exact address. Maintaining this property allows us to use the simple + * formulation of match_states defined as equality. + * Otherwise we would have to deal with the case of a basic block header + * that has multiple labels. Asmblock.label_pos will, for all labels, point + * to the same location at the beginning of the basic block. Asm.label_pos + * on the other hand could return a position pointing into the original + * basic block. + *) + (*if zle (list_length_z (header bb)) 1 then*) + do bo_is <- unfold_body (body bb); + OK (lbl ++ bo_is ++ unfold_exit (exit bb)). + (*else*) + (*Error (msg "Asmgen.unfold_bblock: Multiple labels were generated.").*) + +Fixpoint unfold (bbs: Asmblock.bblocks) : res Asm.code := + match bbs with + | nil => OK (nil) + | bb :: bbs' => + do bb_is <- unfold_bblock bb; + do bbs'_is <- unfold bbs'; + OK (bb_is ++ bbs'_is) + end. -(** Translation of a whole function. Note that we must check - that the generated code contains less than [2^32] instructions, - otherwise the offset part of the [PC] code pointer could wrap - around, leading to incorrect executions. *) +Definition transf_function (f: Asmblock.function) : res Asm.function := + do c <- unfold (Asmblock.fn_blocks f); + if zlt Ptrofs.max_unsigned (list_length_z c) + then Error (msg "Asmgen.trans_function: code size exceeded") + else OK {| Asm.fn_sig := Asmblock.fn_sig f; Asm.fn_code := c |}. -Definition transl_function (f: Mach.function) := - do c <- transl_code' f f.(Mach.fn_code) true; - OK (mkfunction f.(Mach.fn_sig) - (Pallocframe f.(fn_stacksize) f.(fn_link_ofs) :: - storeptr RA XSP f.(fn_retaddr_ofs) c)). +Definition transf_fundef (f: Asmblock.fundef) : res Asm.fundef := + transf_partial_fundef transf_function f. -Definition transf_function (f: Mach.function) : res Asm.function := - do tf <- transl_function f; - if zlt Ptrofs.max_unsigned (list_length_z tf.(fn_code)) - then Error (msg "code size exceeded") - else OK tf. +Definition transf_program (p: Asmblock.program) : res Asm.program := + transform_partial_program transf_fundef p. -Definition transf_fundef (f: Mach.fundef) : res Asm.fundef := - transf_partial_fundef transf_function f. +End Asmblock_TRANSF. Definition transf_program (p: Mach.program) : res Asm.program := - transform_partial_program transf_fundef p. + let mbp := Machblockgen.transf_program p in + do mbp' <- PseudoAsmblockproof.transf_program mbp; + do abp <- Asmblockgen.transf_program mbp'; + do abp' <- (time "PostpassScheduling total oracle+verification" PostpassScheduling.transf_program) abp; + Asmblock_TRANSF.transf_program abp'. diff --git a/aarch64/Asmgenproof.v b/aarch64/Asmgenproof.v index 6831509f..d062654b 100644 --- a/aarch64/Asmgenproof.v +++ b/aarch64/Asmgenproof.v @@ -1,24 +1,35 @@ -(* *********************************************************************) -(* *) -(* The Compcert verified compiler *) -(* *) -(* Xavier Leroy, Collège de France and INRIA Paris *) -(* *) -(* Copyright Institut National de Recherche en Informatique et en *) -(* Automatique. All rights reserved. This file is distributed *) -(* under the terms of the INRIA Non-Commercial License Agreement. *) -(* *) -(* *********************************************************************) - -(** Correctness proof for AArch64 code generation. *) +(* *************************************************************) +(* *) +(* The Compcert verified compiler *) +(* *) +(* Sylvain Boulmé Grenoble-INP, VERIMAG *) +(* Léo Gourdin UGA, VERIMAG *) +(* Justus Fasse UGA, VERIMAG *) +(* Xavier Leroy INRIA Paris-Rocquencourt *) +(* David Monniaux CNRS, VERIMAG *) +(* Cyril Six Kalray *) +(* *) +(* Copyright Kalray. Copyright VERIMAG. All rights reserved. *) +(* This file is distributed under the terms of the INRIA *) +(* Non-Commercial License Agreement. *) +(* *) +(* *************************************************************) Require Import Coqlib Errors. Require Import Integers Floats AST Linking. Require Import Values Memory Events Globalenvs Smallstep. -Require Import Op Locations Mach Conventions Asm. -Require Import Asmgen Asmgenproof0 Asmgenproof1. +Require Import Op Locations Machblock Conventions PseudoAsmblock PseudoAsmblockproof Asm Asmblock. +Require Machblockgenproof Asmblockgenproof PostpassSchedulingproof. +Require Import Asmgen. +Require Import Axioms. +Require Import IterList. +Require Import Ring. -Definition match_prog (p: Mach.program) (tp: Asm.program) := +Module Asmblock_PRESERVATION. + +Import Asmblock_TRANSF. + +Definition match_prog (p: Asmblock.program) (tp: Asm.program) := match_program (fun _ f tf => transf_fundef f = OK tf) eq p tp. Lemma transf_program_match: @@ -29,20 +40,36 @@ Qed. Section PRESERVATION. -Variable prog: Mach.program. +Variable prog: Asmblock.program. Variable tprog: Asm.program. Hypothesis TRANSF: match_prog prog tprog. Let ge := Genv.globalenv prog. Let tge := Genv.globalenv tprog. +Definition lk :aarch64_linker := {| Asmblock.symbol_low:=Asm.symbol_low tge; Asmblock.symbol_high:=Asm.symbol_high tge|}. + Lemma symbols_preserved: forall (s: ident), Genv.find_symbol tge s = Genv.find_symbol ge s. Proof (Genv.find_symbol_match TRANSF). +Lemma symbol_addresses_preserved: + forall (s: ident) (ofs: ptrofs), + Genv.symbol_address tge s ofs = Genv.symbol_address ge s ofs. +Proof. + intros; unfold Genv.symbol_address; rewrite symbols_preserved; reflexivity. +Qed. + Lemma senv_preserved: Senv.equiv ge tge. Proof (Genv.senv_match TRANSF). +Lemma symbol_high_low: forall (id: ident) (ofs: ptrofs), + Val.addl (Asmblock.symbol_high lk id ofs) (Asmblock.symbol_low lk id ofs) = Genv.symbol_address ge id ofs. +Proof. + unfold lk; simpl. intros; rewrite Asm.symbol_high_low; unfold Genv.symbol_address; + rewrite symbols_preserved; reflexivity. +Qed. + Lemma functions_translated: forall b f, Genv.find_funct_ptr ge b = Some f -> @@ -50,1052 +77,2320 @@ Lemma functions_translated: Genv.find_funct_ptr tge b = Some tf /\ transf_fundef f = OK tf. Proof (Genv.find_funct_ptr_transf_partial TRANSF). -Lemma functions_transl: - forall fb f tf, +Lemma internal_functions_translated: + forall b f, + Genv.find_funct_ptr ge b = Some (Internal f) -> + exists tf, + Genv.find_funct_ptr tge b = Some (Internal tf) /\ transf_function f = OK tf. +Proof. + intros; exploit functions_translated; eauto. + intros (x & FIND & TRANSf). + apply bind_inversion in TRANSf. + destruct TRANSf as (tf & TRANSf & X). + inv X. + eauto. +Qed. + +Lemma internal_functions_unfold: + forall b f, + Genv.find_funct_ptr ge b = Some (Internal f) -> + exists tc, + Genv.find_funct_ptr tge b = Some (Internal (Asm.mkfunction (fn_sig f) tc)) + /\ unfold (fn_blocks f) = OK tc + /\ list_length_z tc <= Ptrofs.max_unsigned. +Proof. + intros. + exploit internal_functions_translated; eauto. + intros (tf & FINDtf & TRANStf). + unfold transf_function in TRANStf. + monadInv TRANStf. + destruct (zlt _ _); try congruence. + inv EQ. inv EQ0. + eexists; intuition eauto. + omega. +Qed. + + +Inductive is_nth_inst (bb: bblock) (n:Z) (i:Asm.instruction): Prop := + | is_nth_label l: + list_nth_z (header bb) n = Some l -> + i = Asm.Plabel l -> + is_nth_inst bb n i + | is_nth_basic bi: + list_nth_z (body bb) (n - list_length_z (header bb)) = Some bi -> + basic_to_instruction bi = OK i -> + is_nth_inst bb n i + | is_nth_ctlflow cfi: + (exit bb) = Some cfi -> + n = size bb - 1 -> + i = control_to_instruction cfi -> + is_nth_inst bb n i. + +(* Asmblock and Asm share the same definition of state *) +Definition match_states (s1 s2 : state) := s1 = s2. + +Inductive match_internal: forall n, state -> state -> Prop := + | match_internal_intro n rs1 m1 rs2 m2 + (MEM: m1 = m2) + (AG: forall r, r <> PC -> rs1 r = rs2 r) + (AGPC: Val.offset_ptr (rs1 PC) (Ptrofs.repr n) = rs2 PC) + : match_internal n (State rs1 m1) (State rs2 m2). + +Lemma match_internal_set_parallel: + forall n rs1 m1 rs2 m2 r val, + match_internal n (State rs1 m1) (State rs2 m2) -> + r <> PC -> + match_internal n (State (rs1#r <- val) m1) (State (rs2#r <- val ) m2). +Proof. + intros n rs1 m1 rs2 m2 r v MI. + inversion MI; constructor; auto. + - intros r' NOTPC. + unfold Pregmap.set; rewrite AG. reflexivity. assumption. + - unfold Pregmap.set; destruct (PregEq.eq PC r); congruence. +Qed. + +Lemma agree_match_states: + forall rs1 m1 rs2 m2, + match_states (State rs1 m1) (State rs2 m2) -> + forall r : preg, rs1#r = rs2#r. +Proof. + intros. + unfold match_states in *. + assert (rs1 = rs2) as EQ. { congruence. } + rewrite EQ. reflexivity. +Qed. + +Lemma match_states_set_parallel: + forall rs1 m1 rs2 m2 r v, + match_states (State rs1 m1) (State rs2 m2) -> + match_states (State (rs1#r <- v) m1) (State (rs2#r <- v) m2). +Proof. + intros; unfold match_states in *. + assert (rs1 = rs2) as RSEQ. { congruence. } + assert (m1 = m2) as MEQ. { congruence. } + rewrite RSEQ in *; rewrite MEQ in *; unfold Pregmap.set; reflexivity. +Qed. + +(* match_internal from match_states *) +Lemma mi_from_ms: + forall rs1 m1 rs2 m2 b ofs, + match_states (State rs1 m1) (State rs2 m2) -> + rs1#PC = Vptr b ofs -> + match_internal 0 (State rs1 m1) (State rs2 m2). +Proof. + intros rs1 m1 rs2 m2 b ofs MS PCVAL. + inv MS; constructor; auto; unfold Val.offset_ptr; + rewrite PCVAL; rewrite Ptrofs.add_zero; reflexivity. +Qed. + +Lemma transf_initial_states: + forall s1, Asmblock.initial_state prog s1 -> + exists s2, Asm.initial_state tprog s2 /\ match_states s1 s2. +Proof. + intros ? INIT_s1. + inversion INIT_s1 as (m, ?, ge0, rs). unfold ge0 in *. + econstructor; split. + - econstructor. + eapply (Genv.init_mem_transf_partial TRANSF); eauto. + - rewrite (match_program_main TRANSF); rewrite symbol_addresses_preserved. + unfold rs; reflexivity. +Qed. + +Lemma transf_final_states: + forall s1 s2 r, + match_states s1 s2 -> Asmblock.final_state s1 r -> Asm.final_state s2 r. +Proof. + intros s1 s2 r MATCH FINAL_s1. + inv FINAL_s1; inv MATCH; constructor; assumption. +Qed. + +Definition max_pos (f : Asm.function) := list_length_z f.(Asm.fn_code). + +Lemma functions_bound_max_pos: forall fb f tf, Genv.find_funct_ptr ge fb = Some (Internal f) -> transf_function f = OK tf -> - Genv.find_funct_ptr tge fb = Some (Internal tf). + max_pos tf <= Ptrofs.max_unsigned. +Proof. + intros fb f tf FINDf TRANSf. + unfold transf_function in TRANSf. + apply bind_inversion in TRANSf. + destruct TRANSf as (c & TRANSf). + destruct TRANSf as (_ & TRANSf). + destruct (zlt _ _). + - inversion TRANSf. + - unfold max_pos. + assert (Asm.fn_code tf = c) as H. { inversion TRANSf as (H'); auto. } + rewrite H; omega. +Qed. + +Lemma one_le_max_unsigned: + 1 <= Ptrofs.max_unsigned. +Proof. + unfold Ptrofs.max_unsigned; simpl; unfold Ptrofs.wordsize; + unfold Wordsize_Ptrofs.wordsize; destruct Archi.ptr64; simpl; omega. +Qed. + +(* NB: does not seem useful anymore, with the [exec_header_simulation] proof below +Lemma match_internal_exec_label: + forall n rs1 m1 rs2 m2 l fb f tf, + Genv.find_funct_ptr ge fb = Some (Internal f) -> + transf_function f = OK tf -> + match_internal n (State rs1 m1) (State rs2 m2) -> + n >= 0 -> + (* There is no step if n is already max_pos *) + n < (max_pos tf) -> + exists rs2' m2', Asm.exec_instr tge tf (Asm.Plabel l) rs2 m2 = Next rs2' m2' + /\ match_internal (n+1) (State rs1 m1) (State rs2' m2'). +Proof. + intros. (* XXX auto generated names *) + unfold Asm.exec_instr. + eexists; eexists; split; eauto. + inversion H1; constructor; auto. + - intros; unfold Asm.nextinstr; unfold Pregmap.set; + destruct (PregEq.eq r PC); auto; contradiction. + - unfold Asm.nextinstr; rewrite Pregmap.gss; unfold Ptrofs.one. + rewrite <- AGPC; rewrite Val.offset_ptr_assoc; unfold Ptrofs.add; + rewrite Ptrofs.unsigned_repr. rewrite Ptrofs.unsigned_repr; trivial. + + split. + * apply Z.le_0_1. + * apply one_le_max_unsigned. + + split. + * apply Z.ge_le; assumption. + * rewrite <- functions_bound_max_pos; eauto; omega. +Qed. +*) + +Lemma incrPC_agree_but_pc: + forall rs r ofs, + r <> PC -> + (incrPC ofs rs)#r = rs#r. +Proof. + intros rs r ofs NOTPC. + unfold incrPC; unfold Pregmap.set; destruct (PregEq.eq r PC). + - contradiction. + - reflexivity. +Qed. + +Lemma bblock_non_empty bb: body bb <> nil \/ exit bb <> None. +Proof. + destruct bb. simpl. + unfold non_empty_bblockb in correct. + unfold non_empty_body, non_empty_exit, Is_true in correct. + destruct body, exit. + - right. discriminate. + - contradiction. + - right. discriminate. + - left. discriminate. +Qed. + +Lemma list_length_z_aux_increase A (l: list A): forall acc, + list_length_z_aux l acc >= acc. +Proof. + induction l; simpl; intros. + - omega. + - generalize (IHl (Z.succ acc)). omega. +Qed. + +Lemma bblock_size_aux_pos bb: list_length_z (body bb) + Z.of_nat (length_opt (exit bb)) >= 1. +Proof. + destruct (bblock_non_empty bb), (body bb) as [|hd tl], (exit bb); simpl; + try (congruence || omega); + unfold list_length_z; simpl; + generalize (list_length_z_aux_increase _ tl 1); omega. +Qed. + + +Lemma list_length_add_acc A (l : list A) acc: + list_length_z_aux l acc = (list_length_z l) + acc. +Proof. + unfold list_length_z, list_length_z_aux. simpl. + fold list_length_z_aux. + rewrite (list_length_z_aux_shift l acc 0). + omega. +Qed. + +Lemma list_length_z_cons A hd (tl : list A): + list_length_z (hd :: tl) = list_length_z tl + 1. +Proof. + unfold list_length_z; simpl; rewrite list_length_add_acc; reflexivity. +Qed. + +(*Lemma length_agree A (l : list A):*) + (*list_length_z l = Z.of_nat (length l).*) +(*Proof.*) + (*induction l as [| ? l IH]; intros.*) + (*- unfold list_length_z; reflexivity.*) + (*- simpl; rewrite list_length_z_cons, Zpos_P_of_succ_nat; omega.*) +(*Qed.*) + +Lemma bblock_size_aux bb: size bb = list_length_z (header bb) + list_length_z (body bb) + Z.of_nat (length_opt (exit bb)). +Proof. + unfold size. + repeat (rewrite list_length_z_nat). repeat (rewrite Nat2Z.inj_add). reflexivity. +Qed. + +Lemma header_size_lt_block_size bb: + list_length_z (header bb) < size bb. +Proof. + rewrite bblock_size_aux. + generalize (bblock_non_empty bb); intros NEMPTY; destruct NEMPTY as [HDR|EXIT]. + - destruct (body bb); try contradiction; rewrite list_length_z_cons; + repeat rewrite list_length_z_nat; omega. + - destruct (exit bb); try contradiction; simpl; repeat rewrite list_length_z_nat; omega. +Qed. + +Lemma body_size_le_block_size bb: + list_length_z (body bb) <= size bb. Proof. - intros. exploit functions_translated; eauto. intros [tf' [A B]]. - monadInv B. rewrite H0 in EQ; inv EQ; auto. + rewrite bblock_size_aux; repeat rewrite list_length_z_nat; omega. Qed. -(** * Properties of control flow *) -Lemma transf_function_no_overflow: - forall f tf, - transf_function f = OK tf -> list_length_z tf.(fn_code) <= Ptrofs.max_unsigned. +Lemma bblock_size_pos bb: size bb >= 1. Proof. - intros. monadInv H. destruct (zlt Ptrofs.max_unsigned (list_length_z x.(fn_code))); inv EQ0. + rewrite (bblock_size_aux bb). + generalize (bblock_size_aux_pos bb). + generalize (list_length_z_pos (header bb)). omega. Qed. -Lemma exec_straight_exec: - forall fb f c ep tf tc c' rs m rs' m', - transl_code_at_pc ge (rs PC) fb f c ep tf tc -> - exec_straight tge tf tc rs m c' rs' m' -> - plus step tge (State rs m) E0 (State rs' m'). -Proof. - intros. inv H. - eapply exec_straight_steps_1; eauto. - eapply transf_function_no_overflow; eauto. - eapply functions_transl; eauto. -Qed. - -Lemma exec_straight_at: - forall fb f c ep tf tc c' ep' tc' rs m rs' m', - transl_code_at_pc ge (rs PC) fb f c ep tf tc -> - transl_code f c' ep' = OK tc' -> - exec_straight tge tf tc rs m tc' rs' m' -> - transl_code_at_pc ge (rs' PC) fb f c' ep' tf tc'. -Proof. - intros. inv H. - exploit exec_straight_steps_2; eauto. - eapply transf_function_no_overflow; eauto. - eapply functions_transl; eauto. - intros [ofs' [PC' CT']]. - rewrite PC'. constructor; auto. -Qed. - -(** The following lemmas show that the translation from Mach to Asm - preserves labels, in the sense that the following diagram commutes: -<< - translation - Mach code ------------------------ Asm instr sequence - | | - | Mach.find_label lbl find_label lbl | - | | - v v - Mach code tail ------------------- Asm instr seq tail - translation ->> - The proof demands many boring lemmas showing that Asm constructor - functions do not introduce new labels. -*) +Lemma unfold_car_cdr bb bbs tc: + unfold (bb :: bbs) = OK tc -> + exists tbb tc', unfold_bblock bb = OK tbb + /\ unfold bbs = OK tc' + /\ unfold (bb :: bbs) = OK (tbb ++ tc'). +Proof. + intros UNFOLD. + assert (UF := UNFOLD). + unfold unfold in UNFOLD. + apply bind_inversion in UNFOLD. destruct UNFOLD as (? & UBB). destruct UBB as (UBB & REST). + apply bind_inversion in REST. destruct REST as (? & UNFOLD'). + fold unfold in UNFOLD'. destruct UNFOLD' as (UNFOLD' & UNFOLD). + rewrite <- UNFOLD in UF. + eauto. +Qed. -Section TRANSL_LABEL. +Lemma unfold_cdr bb bbs tc: + unfold (bb :: bbs) = OK tc -> + exists tc', unfold bbs = OK tc'. +Proof. + intros; exploit unfold_car_cdr; eauto. intros (_ & ? & _ & ? & _). + eexists; eauto. +Qed. -Remark loadimm_z_label: forall sz rd l k, tail_nolabel k (loadimm_z sz rd l k). -Proof. - intros; destruct l as [ | [n1 p1] l]; simpl; TailNoLabel. - induction l as [ | [n p] l]; simpl; TailNoLabel. +Lemma unfold_car bb bbs tc: + unfold (bb :: bbs) = OK tc -> + exists tbb, unfold_bblock bb = OK tbb. +Proof. + intros; exploit unfold_car_cdr; eauto. intros (? & _ & ? & _ & _). + eexists; eauto. Qed. -Remark loadimm_n_label: forall sz rd l k, tail_nolabel k (loadimm_n sz rd l k). -Proof. - intros; destruct l as [ | [n1 p1] l]; simpl; TailNoLabel. - induction l as [ | [n p] l]; simpl; TailNoLabel. +Lemma all_blocks_translated: + forall bbs tc, + unfold bbs = OK tc -> + forall bb, In bb bbs -> + exists c, unfold_bblock bb = OK c. +Proof. + induction bbs as [| bb bbs IHbbs]. + - contradiction. + - intros ? UNFOLD ? IN. + (* unfold proceeds by unfolding the basic block at the head of the list and + * then recurring *) + exploit unfold_car_cdr; eauto. intros (? & ? & ? & ? & _). + (* basic block is either in head or tail *) + inversion IN as [EQ | NEQ]. + + rewrite <- EQ; eexists; eauto. + + eapply IHbbs; eauto. Qed. -Remark loadimm_label: forall sz rd n k, tail_nolabel k (loadimm sz rd n k). +Lemma entire_body_translated: + forall lbi tc, + unfold_body lbi = OK tc -> + forall bi, In bi lbi -> + exists bi', basic_to_instruction bi = OK bi'. Proof. - unfold loadimm; intros. destruct Nat.leb; [apply loadimm_z_label|apply loadimm_n_label]. + induction lbi as [| a lbi IHlbi]. + - intros. contradiction. + - intros tc UNFOLD_BODY bi IN. + unfold unfold_body in UNFOLD_BODY. apply bind_inversion in UNFOLD_BODY. + destruct UNFOLD_BODY as (? & TRANSbi & REST). + apply bind_inversion in REST. destruct REST as (? & UNFOLD_BODY' & ?). + fold unfold_body in UNFOLD_BODY'. + + inversion IN as [EQ | NEQ]. + + rewrite <- EQ; eauto. + + eapply IHlbi; eauto. Qed. -Hint Resolve loadimm_label: labels. -Remark loadimm32_label: forall r n k, tail_nolabel k (loadimm32 r n k). +Lemma bblock_in_bblocks bbs bb: forall + tc pos + (UNFOLD: unfold bbs = OK tc) + (FINDBB: find_bblock pos bbs = Some bb), + In bb bbs. Proof. - unfold loadimm32; intros. destruct (is_logical_imm32 n); TailNoLabel. + induction bbs as [| b bbs IH]. + - intros. inversion FINDBB. + - destruct pos. + + intros. inversion FINDBB as (EQ). rewrite <- EQ. apply in_eq. + + intros. + exploit unfold_cdr; eauto. intros (tc' & UNFOLD'). + unfold find_bblock in FINDBB. simpl in FINDBB. + fold find_bblock in FINDBB. + apply in_cons. eapply IH; eauto. + + intros. inversion FINDBB. Qed. -Hint Resolve loadimm32_label: labels. -Remark loadimm64_label: forall r n k, tail_nolabel k (loadimm64 r n k). +Lemma blocks_translated tc pos bbs bb: forall + (UNFOLD: unfold bbs = OK tc) + (FINDBB: find_bblock pos bbs = Some bb), + exists tbb, unfold_bblock bb = OK tbb. Proof. - unfold loadimm64; intros. destruct (is_logical_imm64 n); TailNoLabel. + intros; exploit bblock_in_bblocks; eauto; intros; + eapply all_blocks_translated; eauto. Qed. -Hint Resolve loadimm64_label: labels. -Remark addimm_aux: forall insn rd r1 n k, - (forall rd r1 n, nolabel (insn rd r1 n)) -> - tail_nolabel k (addimm_aux insn rd r1 n k). +(*Lemma size_header b pos f bb: forall*) + (*(FINDF: Genv.find_funct_ptr ge b = Some (Internal f))*) + (*(FINDBB: find_bblock pos (fn_blocks f) = Some bb),*) + (*list_length_z (header bb) <= 1.*) +(*Proof.*) + (*intros.*) + (*exploit internal_functions_unfold; eauto.*) + (*intros (tc & FINDtf & TRANStf & ?).*) + (*exploit blocks_translated; eauto. intros TBB.*) + + (*unfold unfold_bblock in TBB.*) + (*destruct (zle (list_length_z (header bb)) 1).*) + (*- assumption.*) + (*[>- destruct TBB as (? & TBB). discriminate TBB.<]*) +(*[>Qed.<]*) +(*Admitted.*) + +Lemma list_nth_z_neg A (l: list A): forall n, + n < 0 -> list_nth_z l n = None. Proof. - unfold addimm_aux; intros. - destruct Z.eqb. TailNoLabel. destruct Z.eqb; TailNoLabel. + induction l; simpl; auto. + intros n H; destruct (zeq _ _); (try eapply IHl); omega. Qed. -Remark addimm32_label: forall rd r1 n k, tail_nolabel k (addimm32 rd r1 n k). +Lemma find_bblock_neg bbs: forall pos, + pos < 0 -> find_bblock pos bbs = None. Proof. - unfold addimm32; intros. - destruct Int.eq. apply addimm_aux; intros; red; auto. - destruct Int.eq. apply addimm_aux; intros; red; auto. - destruct Int.lt; eapply tail_nolabel_trans; TailNoLabel. + induction bbs; simpl; auto. + intros. destruct (zlt pos 0). { reflexivity. } + destruct (zeq pos 0); contradiction. Qed. -Hint Resolve addimm32_label: labels. -Remark addimm64_label: forall rd r1 n k, tail_nolabel k (addimm64 rd r1 n k). +Lemma equal_header_size bb: + length (header bb) = length (unfold_label (header bb)). Proof. - unfold addimm64; intros. - destruct Int64.eq. apply addimm_aux; intros; red; auto. - destruct Int64.eq. apply addimm_aux; intros; red; auto. - destruct Int64.lt; eapply tail_nolabel_trans; TailNoLabel. + induction (header bb); auto. + simpl. rewrite IHl. auto. Qed. -Hint Resolve addimm64_label: labels. -Remark logicalimm32_label: forall insn1 insn2 rd r1 n k, - (forall rd r1 n, nolabel (insn1 rd r1 n)) -> - (forall rd r1 r2 s, nolabel (insn2 rd r1 r2 s)) -> - tail_nolabel k (logicalimm32 insn1 insn2 rd r1 n k). +Lemma equal_body_size: + forall bb tb, + unfold_body (body bb) = OK tb -> + length (body bb) = length tb. Proof. - unfold logicalimm32; intros. - destruct (is_logical_imm32 n). TailNoLabel. eapply tail_nolabel_trans; TailNoLabel. + intros bb. induction (body bb). + - simpl. intros ? H. inversion H. auto. + - intros tb H. simpl in H. apply bind_inversion in H. destruct H as (? & BI & TAIL). + apply bind_inversion in TAIL. destruct TAIL as (tb' & BODY' & CONS). inv CONS. + simpl. specialize (IHl tb' BODY'). rewrite IHl. reflexivity. Qed. -Remark logicalimm64_label: forall insn1 insn2 rd r1 n k, - (forall rd r1 n, nolabel (insn1 rd r1 n)) -> - (forall rd r1 r2 s, nolabel (insn2 rd r1 r2 s)) -> - tail_nolabel k (logicalimm64 insn1 insn2 rd r1 n k). +Lemma equal_exit_size bb: + length_opt (exit bb) = length (unfold_exit (exit bb)). Proof. - unfold logicalimm64; intros. - destruct (is_logical_imm64 n). TailNoLabel. eapply tail_nolabel_trans; TailNoLabel. + destruct (exit bb); trivial. Qed. -Remark move_extended_label: forall rd r1 ex a k, tail_nolabel k (move_extended rd r1 ex a k). +Lemma bblock_size_preserved bb tb: + unfold_bblock bb = OK tb -> + size bb = list_length_z tb. Proof. - unfold move_extended, move_extended_base; intros. destruct Int.eq, ex; TailNoLabel. + unfold unfold_bblock. intros UNFOLD_BBLOCK. + (*destruct (zle (list_length_z (header bb)) 1). 2: { inversion UNFOLD_BBLOCK. }*) + apply bind_inversion in UNFOLD_BBLOCK. destruct UNFOLD_BBLOCK as (? & UNFOLD_BODY & CONS). + inversion CONS. + unfold size. + rewrite equal_header_size, equal_exit_size. + erewrite equal_body_size; eauto. + rewrite list_length_z_nat. + repeat (rewrite app_length). + rewrite plus_assoc. auto. Qed. -Hint Resolve move_extended_label: labels. -Remark arith_extended_label: forall insnX insnS rd r1 r2 ex a k, - (forall rd r1 r2 x, nolabel (insnX rd r1 r2 x)) -> - (forall rd r1 r2 s, nolabel (insnS rd r1 r2 s)) -> - tail_nolabel k (arith_extended insnX insnS rd r1 r2 ex a k). +Lemma size_of_blocks_max_pos_aux: + forall bbs tbbs pos bb, + find_bblock pos bbs = Some bb -> + unfold bbs = OK tbbs -> + pos + size bb <= list_length_z tbbs. Proof. - unfold arith_extended; intros. destruct Int.ltu. - TailNoLabel. - destruct ex; simpl; TailNoLabel. + induction bbs as [| bb ? IHbbs]. + - intros tbbs ? ? FINDBB; inversion FINDBB. + - simpl; intros tbbs pos bb' FINDBB UNFOLD. + apply bind_inversion in UNFOLD; destruct UNFOLD as (tbb & UNFOLD_BBLOCK & H). + apply bind_inversion in H; destruct H as (tbbs' & UNFOLD & CONS). + inv CONS. + destruct (zlt pos 0). { discriminate FINDBB. } + destruct (zeq pos 0). + + inv FINDBB. + exploit bblock_size_preserved; eauto; intros SIZE; rewrite SIZE. + repeat (rewrite list_length_z_nat). rewrite app_length, Nat2Z.inj_add. + omega. + + generalize (IHbbs tbbs' (pos - size bb) bb' FINDBB UNFOLD). intros IH. + exploit bblock_size_preserved; eauto; intros SIZE. + repeat (rewrite list_length_z_nat); rewrite app_length. + rewrite Nat2Z.inj_add; repeat (rewrite <- list_length_z_nat). + omega. Qed. -Remark loadsymbol_label: forall r id ofs k, tail_nolabel k (loadsymbol r id ofs k). +Lemma size_of_blocks_max_pos pos f tf bi: + find_bblock pos (fn_blocks f) = Some bi -> + transf_function f = OK tf -> + pos + size bi <= max_pos tf. Proof. - intros; unfold loadsymbol. - destruct (Archi.pic_code tt); TailNoLabel. destruct Ptrofs.eq; TailNoLabel. -Qed. -Hint Resolve loadsymbol_label: labels. + unfold transf_function, max_pos. + intros FINDBB UNFOLD. + apply bind_inversion in UNFOLD. destruct UNFOLD as (? & UNFOLD & H). + destruct (zlt Ptrofs.max_unsigned (list_length_z x)). { discriminate H. } + inv H. simpl. + eapply size_of_blocks_max_pos_aux; eauto. +Qed. -Remark transl_cond_label: forall cond args k c, - transl_cond cond args k = OK c -> tail_nolabel k c. +Lemma unfold_bblock_not_nil bb: + unfold_bblock bb = OK nil -> False. Proof. - unfold transl_cond; intros; destruct cond; TailNoLabel. -- destruct is_arith_imm32; TailNoLabel. destruct is_arith_imm32; TailNoLabel. eapply tail_nolabel_trans; TailNoLabel. -- destruct is_arith_imm32; TailNoLabel. destruct is_arith_imm32; TailNoLabel. eapply tail_nolabel_trans; TailNoLabel. -- destruct is_logical_imm32; TailNoLabel. eapply tail_nolabel_trans; TailNoLabel. -- destruct is_logical_imm32; TailNoLabel. eapply tail_nolabel_trans; TailNoLabel. -- destruct is_arith_imm64; TailNoLabel. destruct is_arith_imm64; TailNoLabel. eapply tail_nolabel_trans; TailNoLabel. -- destruct is_arith_imm64; TailNoLabel. destruct is_arith_imm64; TailNoLabel. eapply tail_nolabel_trans; TailNoLabel. -- destruct is_logical_imm64; TailNoLabel. eapply tail_nolabel_trans; TailNoLabel. -- destruct is_logical_imm64; TailNoLabel. eapply tail_nolabel_trans; TailNoLabel. + intros. + exploit bblock_size_preserved; eauto. unfold list_length_z; simpl. intros SIZE. + generalize (bblock_size_pos bb). intros SIZE'. omega. Qed. -Remark transl_cond_branch_default_label: forall cond args lbl k c, - transl_cond_branch_default cond args lbl k = OK c -> tail_nolabel k c. +(* same proof as list_nth_z_range (Coqlib) *) +Lemma find_instr_range: + forall c n i, + Asm.find_instr n c = Some i -> 0 <= n < list_length_z c. Proof. - unfold transl_cond_branch_default; intros. - eapply tail_nolabel_trans; [eapply transl_cond_label;eauto|TailNoLabel]. + induction c; simpl; intros. + discriminate. + rewrite list_length_z_cons. destruct (zeq n 0). + generalize (list_length_z_pos c); omega. + exploit IHc; eauto. omega. Qed. -Hint Resolve transl_cond_branch_default_label: labels. -Remark transl_cond_branch_label: forall cond args lbl k c, - transl_cond_branch cond args lbl k = OK c -> tail_nolabel k c. +Lemma find_instr_tail: + forall tbb pos c i, + Asm.find_instr pos c = Some i -> + Asm.find_instr (pos + list_length_z tbb) (tbb ++ c) = Some i. Proof. - unfold transl_cond_branch; intros; destruct args; TailNoLabel; destruct cond; TailNoLabel. -- destruct c0; TailNoLabel. -- destruct c0; TailNoLabel. -- destruct (Int.is_power2 n); TailNoLabel. -- destruct (Int.is_power2 n); TailNoLabel. -- destruct c0; TailNoLabel. -- destruct c0; TailNoLabel. -- destruct (Int64.is_power2' n); TailNoLabel. -- destruct (Int64.is_power2' n); TailNoLabel. + induction tbb as [| ? ? IHtbb]. + - intros. unfold list_length_z; simpl. rewrite Z.add_0_r. assumption. + - intros. rewrite list_length_z_cons. simpl. + destruct (zeq (pos + (list_length_z tbb + 1)) 0). + + exploit find_instr_range; eauto. intros POS_RANGE. + generalize (list_length_z_pos tbb). omega. + + replace (pos + (list_length_z tbb + 1) - 1) with (pos + list_length_z tbb) by omega. + eapply IHtbb; eauto. Qed. -Remark transl_op_label: - forall op args r k c, - transl_op op args r k = OK c -> tail_nolabel k c. +Lemma size_of_blocks_bounds fb pos f bi: + Genv.find_funct_ptr ge fb = Some (Internal f) -> + find_bblock pos (fn_blocks f) = Some bi -> + pos + size bi <= Ptrofs.max_unsigned. Proof. - unfold transl_op; intros; destruct op; TailNoLabel. -- destruct (preg_of r); try discriminate; destruct (preg_of m); inv H; TailNoLabel. -- destruct (Float.eq_dec n Float.zero); TailNoLabel. -- destruct (Float32.eq_dec n Float32.zero); TailNoLabel. -- apply logicalimm32_label; unfold nolabel; auto. -- apply logicalimm32_label; unfold nolabel; auto. -- apply logicalimm32_label; unfold nolabel; auto. -- unfold shrx32. destruct (Int.eq _ _); try destruct (Int.eq _ _); TailNoLabel. -- apply arith_extended_label; unfold nolabel; auto. -- apply arith_extended_label; unfold nolabel; auto. -- apply logicalimm64_label; unfold nolabel; auto. -- apply logicalimm64_label; unfold nolabel; auto. -- apply logicalimm64_label; unfold nolabel; auto. -- unfold shrx64. destruct (Int.eq _ _); try destruct (Int.eq _ _); TailNoLabel. -- eapply tail_nolabel_trans. eapply transl_cond_label; eauto. TailNoLabel. -- destruct (preg_of r); try discriminate; TailNoLabel; - (eapply tail_nolabel_trans; [eapply transl_cond_label; eauto | TailNoLabel]). + intros; exploit internal_functions_translated; eauto. + intros (tf & _ & TRANSf). + assert (pos + size bi <= max_pos tf). { eapply size_of_blocks_max_pos; eauto. } + assert (max_pos tf <= Ptrofs.max_unsigned). { eapply functions_bound_max_pos; eauto. } + omega. Qed. -Remark transl_addressing_label: - forall sz addr args insn k c, - transl_addressing sz addr args insn k = OK c -> - (forall ad, nolabel (insn ad)) -> - tail_nolabel k c. +Lemma find_instr_bblock_tail: + forall tbb bb pos c i, + Asm.find_instr pos c = Some i -> + unfold_bblock bb = OK tbb -> + Asm.find_instr (pos + size bb ) (tbb ++ c) = Some i. Proof. - unfold transl_addressing; intros; destruct addr; TailNoLabel; - eapply tail_nolabel_trans; TailNoLabel. - eapply tail_nolabel_trans. apply arith_extended_label; unfold nolabel; auto. TailNoLabel. + induction tbb. + - intros. exploit unfold_bblock_not_nil; eauto. intros. contradiction. + - intros. simpl. + destruct (zeq (pos + size bb) 0). + + (* absurd *) + exploit find_instr_range; eauto. intros POS_RANGE. + generalize (bblock_size_pos bb). intros SIZE. omega. + + erewrite bblock_size_preserved; eauto. + rewrite list_length_z_cons. + replace (pos + (list_length_z tbb + 1) - 1) with (pos + list_length_z tbb) by omega. + apply find_instr_tail; auto. Qed. -Remark transl_load_label: - forall trap chunk addr args dst k c, - transl_load trap chunk addr args dst k = OK c -> tail_nolabel k c. +Lemma list_nth_z_find_label: + forall (ll : list label) il n l, + list_nth_z ll n = Some l -> + Asm.find_instr n ((unfold_label ll) ++ il) = Some (Asm.Plabel l). Proof. - unfold transl_load; intros; destruct trap; try discriminate; destruct chunk; TailNoLabel; eapply transl_addressing_label; eauto; unfold nolabel; auto. + induction ll. + - intros. inversion H. + - intros. simpl. + destruct (zeq n 0) as [Z | NZ]. + + inversion H as (H'). rewrite Z in H'. simpl in H'. inv H'. reflexivity. + + simpl in H. destruct (zeq n 0). { contradiction. } + apply IHll; auto. Qed. -Remark transl_store_label: - forall chunk addr args src k c, - transl_store chunk addr args src k = OK c -> tail_nolabel k c. +Lemma list_nth_z_find_bi: + forall lbi bi tlbi n bi' exit, + list_nth_z lbi n = Some bi -> + unfold_body lbi = OK tlbi -> + basic_to_instruction bi = OK bi' -> + Asm.find_instr n (tlbi ++ exit) = Some bi'. Proof. - unfold transl_store; intros; destruct chunk; TailNoLabel; eapply transl_addressing_label; eauto; unfold nolabel; auto. + induction lbi. + - intros. inversion H. + - simpl. intros. + apply bind_inversion in H0. destruct H0 as (? & ? & ?). + apply bind_inversion in H2. destruct H2 as (? & ? & ?). + destruct (zeq n 0) as [Z | NZ]. + + destruct n. + * inversion H as (BI). rewrite BI in *. + inversion H3. simpl. congruence. + * (* absurd *) congruence. + * (* absurd *) congruence. + + inv H3. simpl. destruct (zeq n 0). { contradiction. } + eapply IHlbi; eauto. Qed. -Remark indexed_memory_access_label: - forall insn sz base ofs k, - (forall ad, nolabel (insn ad)) -> - tail_nolabel k (indexed_memory_access insn sz base ofs k). +Lemma list_nth_z_find_bi_with_header: + forall ll lbi bi tlbi n bi' (rest : list Asm.instruction), + list_nth_z lbi (n - list_length_z ll) = Some bi -> + unfold_body lbi = OK tlbi -> + basic_to_instruction bi = OK bi' -> + Asm.find_instr n ((unfold_label ll) ++ (tlbi) ++ (rest)) = Some bi'. Proof. - unfold indexed_memory_access; intros. destruct offset_representable. - TailNoLabel. - eapply tail_nolabel_trans; TailNoLabel. + induction ll. + - unfold list_length_z. simpl. intros. + replace (n - 0) with n in H by omega. eapply list_nth_z_find_bi; eauto. + - intros. simpl. destruct (zeq n 0). + + rewrite list_length_z_cons in H. rewrite e in H. + replace (0 - (list_length_z ll + 1)) with (-1 - (list_length_z ll)) in H by omega. + generalize (list_length_z_pos ll). intros. + rewrite list_nth_z_neg in H; try omega. inversion H. + + rewrite list_length_z_cons in H. + replace (n - (list_length_z ll + 1)) with (n -1 - (list_length_z ll)) in H by omega. + eapply IHll; eauto. Qed. -Remark loadind_label: - forall base ofs ty dst k c, - loadind base ofs ty dst k = OK c -> tail_nolabel k c. +(* XXX unused *) +Lemma range_list_nth_z: + forall (A: Type) (l: list A) n, + 0 <= n < list_length_z l -> + exists x, list_nth_z l n = Some x. Proof. - unfold loadind; intros. - destruct ty, (preg_of dst); inv H; apply indexed_memory_access_label; intros; exact I. + induction l. + - intros. unfold list_length_z in H. simpl in H. omega. + - intros n. destruct (zeq n 0). + + intros. simpl. destruct (zeq n 0). { eauto. } contradiction. + + intros H. rewrite list_length_z_cons in H. + simpl. destruct (zeq n 0). { contradiction. } + replace (Z.pred n) with (n - 1) by omega. + eapply IHl; omega. Qed. -Remark storeind_label: - forall src base ofs ty k c, - storeind src base ofs ty k = OK c -> tail_nolabel k c. +Lemma list_nth_z_n_too_big: + forall (A: Type) (l: list A) n, + 0 <= n -> + list_nth_z l n = None -> + n >= list_length_z l. Proof. - unfold storeind; intros. - destruct ty, (preg_of src); inv H; apply indexed_memory_access_label; intros; exact I. + induction l. + - intros. unfold list_length_z. simpl. omega. + - intros. rewrite list_length_z_cons. + simpl in H0. + destruct (zeq n 0) as [N | N]. + + inversion H0. + + (* XXX there must be a more elegant way to prove this simple fact *) + assert (n > 0). { omega. } + assert (0 <= n - 1). { omega. } + generalize (IHl (n - 1)). intros IH. + assert (n - 1 >= list_length_z l). { auto. } + assert (n > list_length_z l); omega. Qed. -Remark loadptr_label: - forall base ofs dst k, tail_nolabel k (loadptr base ofs dst k). +Lemma find_instr_past_header: + forall labels n rest, + list_nth_z labels n = None -> + Asm.find_instr n (unfold_label labels ++ rest) = + Asm.find_instr (n - list_length_z labels) rest. Proof. - intros. apply indexed_memory_access_label. unfold nolabel; auto. + induction labels as [| label labels' IH]. + - unfold list_length_z; simpl; intros; rewrite Z.sub_0_r; reflexivity. + - intros. simpl. destruct (zeq n 0) as [N | N]. + + rewrite N in H. inversion H. + + rewrite list_length_z_cons. + replace (n - (list_length_z labels' + 1)) with (n - 1 - list_length_z labels') by omega. + simpl in H. destruct (zeq n 0). { contradiction. } + replace (Z.pred n) with (n - 1) in H by omega. + apply IH; auto. Qed. -Remark storeptr_label: - forall src base ofs k, tail_nolabel k (storeptr src base ofs k). +(* very similar to find_instr_past_header *) +Lemma find_instr_past_body: + forall lbi n tlbi rest, + list_nth_z lbi n = None -> + unfold_body lbi = OK tlbi -> + Asm.find_instr n (tlbi ++ rest) = + Asm.find_instr (n - list_length_z lbi) rest. Proof. - intros. apply indexed_memory_access_label. unfold nolabel; auto. + induction lbi. + - unfold list_length_z; simpl; intros ? ? ? ? H. inv H; rewrite Z.sub_0_r; reflexivity. + - intros n tlib ? NTH UNFOLD_BODY. + unfold unfold_body in UNFOLD_BODY. apply bind_inversion in UNFOLD_BODY. + destruct UNFOLD_BODY as (? & BI & H). + apply bind_inversion in H. destruct H as (? & UNFOLD_BODY' & CONS). + fold unfold_body in UNFOLD_BODY'. inv CONS. + simpl; destruct (zeq n 0) as [N|N]. + + rewrite N in NTH; inversion NTH. + + rewrite list_length_z_cons. + replace (n - (list_length_z lbi + 1)) with (n - 1 - list_length_z lbi) by omega. + simpl in NTH. destruct (zeq n 0). { contradiction. } + replace (Z.pred n) with (n - 1) in NTH by omega. + apply IHlbi; auto. Qed. -Remark make_epilogue_label: - forall f k, tail_nolabel k (make_epilogue f k). +Lemma n_beyond_body: + forall bb n, + 0 <= n < size bb -> + list_nth_z (header bb) n = None -> + list_nth_z (body bb) (n - list_length_z (header bb)) = None -> + n >= Z.of_nat (length (header bb) + length (body bb)). Proof. - unfold make_epilogue; intros. - (* FIXME destruct is_leaf_function. - { TailNoLabel. } *) - eapply tail_nolabel_trans. - apply loadptr_label. - TailNoLabel. + intros. + assert (0 <= n). { omega. } + generalize (list_nth_z_n_too_big label (header bb) n H2 H0). intros. + generalize (list_nth_z_n_too_big _ (body bb) (n - list_length_z (header bb))). intros. + unfold size in H. + + assert (0 <= n - list_length_z (header bb)). { omega. } + assert (n - list_length_z (header bb) >= list_length_z (body bb)). { apply H4; auto. } + + assert (n >= list_length_z (header bb) + list_length_z (body bb)). { omega. } + rewrite Nat2Z.inj_add. + repeat (rewrite <- list_length_z_nat). assumption. Qed. -Lemma transl_instr_label: - forall f i ep k c, - transl_instr f i ep k = OK c -> - match i with Mlabel lbl => c = Plabel lbl :: k | _ => tail_nolabel k c end. +Lemma exec_arith_instr_dont_move_PC ai rs rs': forall + (BASIC: exec_arith_instr lk ai rs = rs'), + rs PC = rs' PC. Proof. - unfold transl_instr; intros; destruct i; TailNoLabel. -- eapply loadind_label; eauto. -- eapply storeind_label; eauto. -- destruct ep. eapply loadind_label; eauto. - eapply tail_nolabel_trans. apply loadptr_label. eapply loadind_label; eauto. -- eapply transl_op_label; eauto. -- eapply transl_load_label; eauto. -- eapply transl_store_label; eauto. -- destruct s0; monadInv H; TailNoLabel. -- destruct s0; monadInv H; (eapply tail_nolabel_trans; [eapply make_epilogue_label|TailNoLabel]). -- eapply transl_cond_branch_label; eauto. -- eapply tail_nolabel_trans; [eapply make_epilogue_label|TailNoLabel]. + destruct ai; simpl; intros; + try (rewrite <- BASIC; rewrite Pregmap.gso; auto; discriminate). + - destruct i; simpl in BASIC. + + unfold compare_long in BASIC; rewrite <- BASIC. + repeat rewrite Pregmap.gso; try discriminate. reflexivity. + + unfold compare_long in BASIC; rewrite <- BASIC. + repeat rewrite Pregmap.gso; try discriminate. reflexivity. + + destruct sz; + try (unfold compare_single in BASIC || unfold compare_float in BASIC); + destruct (rs r1), (rs r2); + try (rewrite <- BASIC; repeat rewrite Pregmap.gso; try (discriminate || reflexivity)). + - destruct i; simpl in BASIC; destruct is; + try (unfold compare_int in BASIC || unfold compare_long in BASIC); + try (rewrite <- BASIC; repeat rewrite Pregmap.gso; try (discriminate || reflexivity)). + - destruct i; simpl in BASIC; destruct sz; + try (unfold compare_single in BASIC || unfold compare_float in BASIC); + destruct (rs r1); + try (rewrite <- BASIC; repeat rewrite Pregmap.gso; try (discriminate || reflexivity)). + - destruct fsz; rewrite <- BASIC; rewrite Pregmap.gso; try (discriminate || reflexivity). + - destruct fsz; rewrite <- BASIC; rewrite Pregmap.gso; try (discriminate || reflexivity). Qed. -Lemma transl_instr_label': - forall lbl f i ep k c, - transl_instr f i ep k = OK c -> - find_label lbl c = if Mach.is_label lbl i then Some k else find_label lbl k. +Lemma exec_basic_dont_move_PC bi rs m rs' m': forall + (BASIC: exec_basic lk ge bi rs m = Next rs' m'), + rs PC = rs' PC. Proof. - intros. exploit transl_instr_label; eauto. - destruct i; try (intros [A B]; apply B). - intros. subst c. simpl. auto. + destruct bi; simpl; intros. + - inv BASIC. exploit exec_arith_instr_dont_move_PC; eauto. + - unfold exec_load in BASIC. + destruct Mem.loadv. 2: { discriminate BASIC. } + inv BASIC. rewrite Pregmap.gso; try discriminate; auto. + - unfold exec_store in BASIC. + destruct Mem.storev. 2: { discriminate BASIC. } + inv BASIC; reflexivity. + - destruct Mem.alloc, Mem.store. 2: { discriminate BASIC. } + inv BASIC. repeat (rewrite Pregmap.gso; try discriminate). reflexivity. + - destruct Mem.loadv. 2: { discriminate BASIC. } + destruct rs, Mem.free; try discriminate BASIC. + inv BASIC; rewrite Pregmap.gso; try discriminate; auto. + - inv BASIC; rewrite Pregmap.gso; try discriminate; auto. + - inv BASIC; rewrite Pregmap.gso; try discriminate; auto. + - inv BASIC; rewrite Pregmap.gso; try discriminate; auto. + - inv BASIC; rewrite Pregmap.gso; try discriminate; auto. Qed. -Lemma transl_code_label: - forall lbl f c ep tc, - transl_code f c ep = OK tc -> - match Mach.find_label lbl c with - | None => find_label lbl tc = None - | Some c' => exists tc', find_label lbl tc = Some tc' /\ transl_code f c' false = OK tc' - end. +Lemma exec_body_dont_move_PC_aux: + forall bis rs m rs' m' + (BODY: exec_body lk ge bis rs m = Next rs' m'), + rs PC = rs' PC. Proof. - induction c; simpl; intros. - inv H. auto. - monadInv H. rewrite (transl_instr_label' lbl _ _ _ _ _ EQ0). - generalize (Mach.is_label_correct lbl a). - destruct (Mach.is_label lbl a); intros. - subst a. simpl in EQ. exists x; auto. - eapply IHc; eauto. + induction bis. + - intros; inv BODY; reflexivity. + - simpl; intros. + remember (exec_basic lk ge a rs m) as bi eqn:BI; destruct bi. 2: { discriminate BODY. } + symmetry in BI; destruct s in BODY, BI; simpl in BODY, BI. + exploit exec_basic_dont_move_PC; eauto; intros AGPC; rewrite AGPC. + eapply IHbis; eauto. Qed. -Lemma transl_find_label: - forall lbl f tf, - transf_function f = OK tf -> - match Mach.find_label lbl f.(Mach.fn_code) with - | None => find_label lbl tf.(fn_code) = None - | Some c => exists tc, find_label lbl tf.(fn_code) = Some tc /\ transl_code f c false = OK tc - end. +Lemma exec_body_dont_move_PC bb rs m rs' m': forall + (BODY: exec_body lk ge (body bb) rs m = Next rs' m'), + rs PC = rs' PC. +Proof. apply exec_body_dont_move_PC_aux. Qed. + +Lemma find_instr_bblock: + forall n lb pos bb tlb + (FINDBB: find_bblock pos lb = Some bb) + (UNFOLD: unfold lb = OK tlb) + (SIZE: 0 <= n < size bb), + exists i, is_nth_inst bb n i /\ Asm.find_instr (pos+n) tlb = Some i. Proof. - intros. monadInv H. destruct (zlt Ptrofs.max_unsigned (list_length_z x.(fn_code))); inv EQ0. - monadInv EQ. rewrite transl_code'_transl_code in EQ0. unfold fn_code. - simpl. destruct (storeptr_label X30 XSP (fn_retaddr_ofs f) x) as [A B]; rewrite B. - eapply transl_code_label; eauto. + induction lb as [| b lb IHlb]. + - intros. inversion FINDBB. + - intros pos bb tlb FINDBB UNFOLD SIZE. + destruct pos. + + inv FINDBB. simpl. + exploit unfold_car_cdr; eauto. intros (tbb & tlb' & UNFOLD_BBLOCK & UNFOLD' & UNFOLD_cons). + rewrite UNFOLD in UNFOLD_cons. inversion UNFOLD_cons. + unfold unfold_bblock in UNFOLD_BBLOCK. + (*destruct (zle (list_length_z (header bb)) 1). 2: { inversion UNFOLD_BBLOCK. }*) + apply bind_inversion in UNFOLD_BBLOCK. + destruct UNFOLD_BBLOCK as (? & UNFOLD_BODY & H). + inversion H as (UNFOLD_BBLOCK). + remember (list_nth_z (header bb) n) as label_opt eqn:LBL. destruct label_opt. + * (* nth instruction is a label *) + eexists; split. { eapply is_nth_label; eauto. } + inversion UNFOLD_cons. + symmetry in LBL. + rewrite <- app_assoc. + apply list_nth_z_find_label; auto. + * remember (list_nth_z (body bb) (n - list_length_z (header bb))) as bi_opt eqn:BI. + destruct bi_opt. + -- (* nth instruction is a basic instruction *) + exploit list_nth_z_in; eauto. intros INBB. + exploit entire_body_translated; eauto. intros BI'. + destruct BI'. + eexists; split. + ++ eapply is_nth_basic; eauto. + ++ repeat (rewrite <- app_assoc). eapply list_nth_z_find_bi_with_header; eauto. + -- (* nth instruction is the exit instruction *) + generalize n_beyond_body. intros TEMP. + assert (n >= Z.of_nat (Datatypes.length (header bb) + + Datatypes.length (body bb))) as NGE. { auto. } clear TEMP. + remember (exit bb) as exit_opt eqn:EXIT. destruct exit_opt. + ++ rewrite <- app_assoc. rewrite find_instr_past_header; auto. + rewrite <- app_assoc. erewrite find_instr_past_body; eauto. + assert (SIZE' := SIZE). + unfold size in SIZE. rewrite <- EXIT in SIZE. simpl in SIZE. + destruct SIZE as (LOWER & UPPER). + repeat (rewrite Nat2Z.inj_add in UPPER). + repeat (rewrite <- list_length_z_nat in UPPER). repeat (rewrite Nat2Z.inj_add in NGE). + repeat (rewrite <- list_length_z_nat in NGE). simpl in UPPER. + assert (n = list_length_z (header bb) + list_length_z (body bb)). { omega. } + assert (n = size bb - 1). { + unfold size. rewrite <- EXIT. simpl. + repeat (rewrite Nat2Z.inj_add). repeat (rewrite <- list_length_z_nat). simpl. omega. + } + symmetry in EXIT. + eexists; split. + ** eapply is_nth_ctlflow; eauto. + ** simpl. + destruct (zeq (n - list_length_z (header bb) - list_length_z (body bb)) 0). { reflexivity. } + (* absurd *) omega. + ++ (* absurd *) + unfold size in SIZE. rewrite <- EXIT in SIZE. simpl in SIZE. + destruct SIZE as (? & SIZE'). rewrite Nat.add_0_r in SIZE'. omega. + + unfold find_bblock in FINDBB; simpl in FINDBB; fold find_bblock in FINDBB. + inversion UNFOLD as (UNFOLD'). + apply bind_inversion in UNFOLD'. destruct UNFOLD' as (? & (UNFOLD_BBLOCK' & UNFOLD')). + apply bind_inversion in UNFOLD'. destruct UNFOLD' as (? & (UNFOLD' & TLB)). + inversion TLB. + generalize (IHlb _ _ _ FINDBB UNFOLD'). intros IH. + destruct IH as (? & (IH_is_nth & IH_find_instr)); eauto. + eexists; split. + * apply IH_is_nth. + * replace (Z.pos p + n) with (Z.pos p + n - size b + size b) by omega. + eapply find_instr_bblock_tail; try assumption. + replace (Z.pos p + n - size b) with (Z.pos p - size b + n) by omega. + apply IH_find_instr. + + (* absurd *) + generalize (Pos2Z.neg_is_neg p). intros. exploit (find_bblock_neg (b :: lb)); eauto. + rewrite FINDBB. intros CONTRA. inversion CONTRA. Qed. -End TRANSL_LABEL. +Lemma exec_header_simulation b ofs f bb rs m: forall + (ATPC: rs PC = Vptr b ofs) + (FINDF: Genv.find_funct_ptr ge b = Some (Internal f)) + (FINDBB: find_bblock (Ptrofs.unsigned ofs) (fn_blocks f) = Some bb), + exists s', star Asm.step tge (State rs m) E0 s' + /\ match_internal (list_length_z (header bb)) (State rs m) s'. +Proof. +Admitted. + (* intros. + exploit internal_functions_unfold; eauto. + intros (tc & FINDtf & TRANStf & _). + induction (header bb) eqn:EQhead. + + eexists; split. + - eapply star_refl. + - split; eauto. + unfold list_length_z; rewrite !ATPC; simpl. + rewrite Ptrofs.add_zero; auto. + + assert (Lgen: list_length_z (header bb) < (size bb)) by eapply header_size_lt_block_size. + assert (Lpos: list_length_z (l) >= 0) by eapply list_length_z_pos. + assert (Lsmaller: list_length_z (l) < list_length_z (header bb)). + { rewrite EQhead. rewrite list_length_z_cons. omega. } + + + + exploit (find_instr_bblock (list_length_z (l))); eauto. + { generalize (bblock_size_pos bb). rewrite EQhead in *. intros. omega. } + intros (i & NTH & FIND_INSTR). + inv NTH. + - eexists. split. eapply star_one. eapply Asm.exec_step_internal; eauto. + inv FIND_INSTR. + eapply list_nth_z_range in H. rewrite EQhead in H. + eapply Nat.lt_neq in H0. -(** A valid branch in a piece of Mach code translates to a valid ``go to'' - transition in the generated Asm code. *) -Lemma find_label_goto_label: - forall f tf lbl rs m c' b ofs, - Genv.find_funct_ptr ge b = Some (Internal f) -> - transf_function f = OK tf -> - rs PC = Vptr b ofs -> - Mach.find_label lbl f.(Mach.fn_code) = Some c' -> - exists tc', exists rs', - goto_label tf lbl rs m = Next rs' m - /\ transl_code_at_pc ge (rs' PC) b f c' false tf tc' - /\ forall r, r <> PC -> rs'#r = rs#r. -Proof. - intros. exploit (transl_find_label lbl f tf); eauto. rewrite H2. - intros [tc [A B]]. - exploit label_pos_code_tail; eauto. instantiate (1 := 0). - intros [pos' [P [Q R]]]. - exists tc; exists (rs#PC <- (Vptr b (Ptrofs.repr pos'))). - split. unfold goto_label. rewrite P. rewrite H1. auto. - split. rewrite Pregmap.gss. constructor; auto. - rewrite Ptrofs.unsigned_repr. replace (pos' - 0) with pos' in Q. - auto. omega. - generalize (transf_function_no_overflow _ _ H0). omega. - intros. apply Pregmap.gso; auto. -Qed. - -(** Existence of return addresses *) + -Lemma return_address_exists: - forall f sg ros c, is_tail (Mcall sg ros :: c) f.(Mach.fn_code) -> - exists ra, return_address_offset f c ra. + + + + + + + + + + + + + + + + + + + intros. + exploit internal_functions_unfold; eauto. + intros (tc & FINDtf & TRANStf & _). + (*assert (BNDhead: list_length_z (header bb) <= 1). { eapply size_header; eauto. }*) + destruct (header bb) as [|l[|]] eqn: EQhead. + + (* header nil *) + eexists; split. + - eapply star_refl. + - split; eauto. + unfold list_length_z; rewrite !ATPC; simpl. + rewrite Ptrofs.add_zero; auto. + + (* header one *) + assert (Lhead: list_length_z (header bb) = 1). { rewrite EQhead; unfold list_length_z; simpl. auto. } + exploit (find_instr_bblock 0); eauto. + { generalize (bblock_size_pos bb). omega. } + intros (i & NTH & FIND_INSTR). + inv NTH. + * rewrite EQhead in H; simpl in H. inv H. + cutrewrite (Ptrofs.unsigned ofs + 0 = Ptrofs.unsigned ofs) in FIND_INSTR; try omega. + eexists. split. + - eapply star_one. + eapply Asm.exec_step_internal; eauto. + simpl; eauto. + - unfold list_length_z; simpl. split; eauto. + intros r; destruct r; simpl; congruence || auto. + * (* absurd case *) + erewrite list_nth_z_neg in * |-; [ congruence | rewrite Lhead; omega]. + * (* absurd case *) + rewrite bblock_size_aux, Lhead in *. generalize (bblock_size_aux_pos bb). omega. + + (* absurd case *) + assert (Lgen: list_length_z (header bb) < (size bb)) by eapply header_size_lt_block_size. + assert (Ll1pos: list_length_z (l1) >= 0) by eapply list_length_z_pos. + assert (Lpos: list_length_z (header bb) - 1 > 0). + { rewrite EQhead. erewrite !list_length_z_cons. omega. } + exploit (find_instr_bblock (list_length_z (l :: l0 :: l1))); eauto. + { generalize (bblock_size_pos bb). rewrite EQhead in *. intros. omega. } + intros (i & NTH & FIND_INSTR). + inv NTH. + (*eapply list_nth_z_range in H. rewrite EQhead in H. destruct H.*) + (*eapply Nat.lt_neq in H0.*) + * rewrite EQhead in *; simpl in H. + assert ((list_length_z (l :: l0 :: l1) - 1) <> 0) by omega. + destruct zeq. + - rewrite e in FIND_INSTR. cutrewrite (Ptrofs.unsigned ofs + 0 = Ptrofs.unsigned ofs) in FIND_INSTR; try omega. + - destruct zeq; try (rewrite <- Z.sub_1_r in e; congruence). + inv H. eexists; split. + { eapply star_one. eapply list_nth_z_find_label in H2. + erewrite find_instr_past_header in H2. + assert (Z.pred (Z.pred (list_length_z (l :: l0 :: l1))) = list_length_z l1). + { erewrite <- !Z.sub_1_r. erewrite !list_length_z_cons. omega. } + replace (Z.pred (Z.pred (list_length_z (l :: l0 :: l1))) - list_length_z l1) with (0) in H2 by omega. + rewrite <- FIND_INSTR in H2. + unfold find_instr in H2. + destruct tc eqn:HTC. + { simpl in *. inversion FIND_INSTR. } + { simpl in *. + + destruct zeq eqn:HZEQ. + + { fold find_instr in H2. assert (0 <= Ptrofs.unsigned ofs <= Ptrofs.max_unsigned) by eapply Ptrofs.unsigned_range_2. assert (list_length_z (l :: l0 :: l1) > 0) by omega. + assert (Ptrofs.unsigned ofs = - list_length_z (l :: l0 :: l1)) by omega. + assert (Ptrofs.unsigned ofs = 0) by omega. + assert (list_length_z (l :: l0 :: l1) = 0) by omega. congruence. } + { simpl in *. + rewrite H4 in H5. + + eapply Asm.exec_step_internal; eauto. + + destruct zeq. + - inv H. eexists. split. + assert (list_length_z (l :: l2 :: l1) - 1 = 1) by omega. rewrite H in *. + { eapply star_one. exploit (find_instr_bblock 0); eauto; try omega. + intros (i' & NTH' & FIND_INSTR'). + eapply Asm.exec_step_internal; eauto. + + + inv H. + cutrewrite (Ptrofs.unsigned ofs + 0 = Ptrofs.unsigned ofs) in FIND_INSTR; try omega. + eexists. split. + - eapply star_one. + eapply Asm.exec_step_internal; eauto. + simpl; eauto. + - unfold list_length_z; simpl. split. eauto. + intros r; destruct r; simpl; congruence || auto. + * (* absurd case *) + erewrite list_nth_z_neg in * |-; [ congruence | rewrite Lhead; omega]. + * (* absurd case *) + rewrite bblock_size_aux, Lhead in *. generalize (bblock_size_aux_pos bb). omega. + unfold list_length_z in BNDhead. simpl in *. + generalize (list_length_z_aux_increase _ l1 2); omega. +Qed.*) + +Lemma eval_addressing_preserved a rs1 rs2: + (forall r : preg, r <> PC -> rs1 r = rs2 r) -> + eval_addressing lk a rs1 = Asm.eval_addressing tge a rs2. Proof. - intros. eapply Asmgenproof0.return_address_exists; eauto. -- intros. exploit transl_instr_label; eauto. - destruct i; try (intros [A B]; apply A). intros. subst c0. repeat constructor. -- intros. monadInv H0. - destruct (zlt Ptrofs.max_unsigned (list_length_z x.(fn_code))); inv EQ0. monadInv EQ. - rewrite transl_code'_transl_code in EQ0. - exists x; exists true; split; auto. unfold fn_code. - constructor. apply (storeptr_label X30 XSP (fn_retaddr_ofs f0) x). -- exact transf_function_no_overflow. -Qed. - -(** * Proof of semantic preservation *) - -(** Semantic preservation is proved using simulation diagrams - of the following form. -<< - st1 --------------- st2 - | | - t| *|t - | | - v v - st1'--------------- st2' ->> - The invariant is the [match_states] predicate below, which includes: -- The Asm code pointed by the PC register is the translation of - the current Mach code sequence. -- Mach register values and Asm register values agree. -*) + intros EQ. + destruct a; simpl; try (rewrite !EQ; congruence). auto. +Qed. -Inductive match_states: Mach.state -> Asm.state -> Prop := - | match_states_intro: - forall s fb sp c ep ms m m' rs f tf tc - (STACKS: match_stack ge s) - (FIND: Genv.find_funct_ptr ge fb = Some (Internal f)) - (MEXT: Mem.extends m m') - (AT: transl_code_at_pc ge (rs PC) fb f c ep tf tc) - (AG: agree ms sp rs) - (DXP: ep = true -> rs#X29 = parent_sp s) - (LEAF: is_leaf_function f = true -> rs#RA = parent_ra s), - match_states (Mach.State s fb sp c ms m) - (Asm.State rs m') - | match_states_call: - forall s fb ms m m' rs - (STACKS: match_stack ge s) - (MEXT: Mem.extends m m') - (AG: agree ms (parent_sp s) rs) - (ATPC: rs PC = Vptr fb Ptrofs.zero) - (ATLR: rs RA = parent_ra s), - match_states (Mach.Callstate s fb ms m) - (Asm.State rs m') - | match_states_return: - forall s ms m m' rs - (STACKS: match_stack ge s) - (MEXT: Mem.extends m m') - (AG: agree ms (parent_sp s) rs) - (ATPC: rs PC = parent_ra s), - match_states (Mach.Returnstate s ms m) - (Asm.State rs m'). - -Lemma exec_straight_steps: - forall s fb f rs1 i c ep tf tc m1' m2 m2' sp ms2, - match_stack ge s -> - Mem.extends m2 m2' -> - Genv.find_funct_ptr ge fb = Some (Internal f) -> - transl_code_at_pc ge (rs1 PC) fb f (i :: c) ep tf tc -> - (forall k c (TR: transl_instr f i ep k = OK c), - exists rs2, - exec_straight tge tf c rs1 m1' k rs2 m2' - /\ agree ms2 sp rs2 - /\ (it1_is_parent ep i = true -> rs2#X29 = parent_sp s) - /\ (is_leaf_function f = true -> rs2#RA = parent_ra s)) -> - exists st', - plus step tge (State rs1 m1') E0 st' /\ - match_states (Mach.State s fb sp c ms2 m2) st'. -Proof. - intros. inversion H2. subst. monadInv H7. - exploit H3; eauto. intros [rs2 [A [B [C D]]]]. - exists (State rs2 m2'); split. - - eapply exec_straight_exec; eauto. - - econstructor; eauto. eapply exec_straight_at; eauto. -Qed. - -Lemma exec_straight_steps_goto: - forall s fb f rs1 i c ep tf tc m1' m2 m2' sp ms2 lbl c', - match_stack ge s -> - Mem.extends m2 m2' -> - Genv.find_funct_ptr ge fb = Some (Internal f) -> - Mach.find_label lbl f.(Mach.fn_code) = Some c' -> - transl_code_at_pc ge (rs1 PC) fb f (i :: c) ep tf tc -> - it1_is_parent ep i = false -> - (forall k c (TR: transl_instr f i ep k = OK c), - exists jmp, exists k', exists rs2, - exec_straight tge tf c rs1 m1' (jmp :: k') rs2 m2' - /\ agree ms2 sp rs2 - /\ exec_instr tge tf jmp rs2 m2' = goto_label tf lbl rs2 m2' - /\ (is_leaf_function f = true -> rs2#RA = parent_ra s)) -> - exists st', - plus step tge (State rs1 m1') E0 st' /\ - match_states (Mach.State s fb sp c' ms2 m2) st'. -Proof. - intros. inversion H3. subst. monadInv H9. - exploit H5; eauto. intros [jmp [k' [rs2 [A [B [C D]]]]]]. - generalize (functions_transl _ _ _ H7 H8); intro FN. - generalize (transf_function_no_overflow _ _ H8); intro NOOV. - exploit exec_straight_steps_2; eauto. - intros [ofs' [PC2 CT2]]. - exploit find_label_goto_label; eauto. - intros [tc' [rs3 [GOTO [AT' OTH]]]]. - exists (State rs3 m2'); split. - eapply plus_right'. - eapply exec_straight_steps_1; eauto. - econstructor; eauto. - eapply find_instr_tail. eauto. - rewrite C. eexact GOTO. - traceEq. - econstructor; eauto. - apply agree_exten with rs2; auto with asmgen. - congruence. - rewrite OTH by congruence; auto. -Qed. - -Lemma exec_straight_opt_steps_goto: - forall s fb f rs1 i c ep tf tc m1' m2 m2' sp ms2 lbl c', - match_stack ge s -> - Mem.extends m2 m2' -> - Genv.find_funct_ptr ge fb = Some (Internal f) -> - Mach.find_label lbl f.(Mach.fn_code) = Some c' -> - transl_code_at_pc ge (rs1 PC) fb f (i :: c) ep tf tc -> - it1_is_parent ep i = false -> - (forall k c (TR: transl_instr f i ep k = OK c), - exists jmp, exists k', exists rs2, - exec_straight_opt tge tf c rs1 m1' (jmp :: k') rs2 m2' - /\ agree ms2 sp rs2 - /\ exec_instr tge tf jmp rs2 m2' = goto_label tf lbl rs2 m2' - /\ (is_leaf_function f = true -> rs2#RA = parent_ra s)) -> - exists st', - plus step tge (State rs1 m1') E0 st' /\ - match_states (Mach.State s fb sp c' ms2 m2) st'. -Proof. - intros. inversion H3. subst. monadInv H9. - exploit H5; eauto. intros [jmp [k' [rs2 [A [B [C D]]]]]]. - generalize (functions_transl _ _ _ H7 H8); intro FN. - generalize (transf_function_no_overflow _ _ H8); intro NOOV. - inv A. -- exploit find_label_goto_label; eauto. - intros [tc' [rs3 [GOTO [AT' OTH]]]]. - exists (State rs3 m2'); split. - apply plus_one. econstructor; eauto. - eapply find_instr_tail. eauto. - rewrite C. eexact GOTO. - econstructor; eauto. - apply agree_exten with rs2; auto with asmgen. - congruence. - rewrite OTH by congruence; auto. -- exploit exec_straight_steps_2; eauto. - intros [ofs' [PC2 CT2]]. - exploit find_label_goto_label; eauto. - intros [tc' [rs3 [GOTO [AT' OTH]]]]. - exists (State rs3 m2'); split. - eapply plus_right'. - eapply exec_straight_steps_1; eauto. - econstructor; eauto. - eapply find_instr_tail. eauto. - rewrite C. eexact GOTO. - traceEq. - econstructor; eauto. - apply agree_exten with rs2; auto with asmgen. - congruence. - rewrite OTH by congruence; auto. -Qed. - -(** We need to show that, in the simulation diagram, we cannot - take infinitely many Mach transitions that correspond to zero - transitions on the Asm side. Actually, all Mach transitions - correspond to at least one Asm transition, except the - transition from [Machsem.Returnstate] to [Machsem.State]. - So, the following integer measure will suffice to rule out - the unwanted behaviour. *) - -Definition measure (s: Mach.state) : nat := - match s with - | Mach.State _ _ _ _ _ _ => 0%nat - | Mach.Callstate _ _ _ _ => 0%nat - | Mach.Returnstate _ _ _ => 1%nat +Ltac next_stuck_cong := try (unfold Next, Stuck in *; congruence). + +Ltac inv_ok_eq := + repeat match goal with + | [EQ: OK ?x = OK ?y |- _ ] + => inversion EQ; clear EQ; subst + end. + +Ltac reg_rwrt := + match goal with + | [e: DR _ = DR _ |- _ ] + => rewrite e in * end. -Remark preg_of_not_X29: forall r, negb (mreg_eq r R29) = true -> IR X29 <> preg_of r. -Proof. - intros. change (IR X29) with (preg_of R29). red; intros. - exploit preg_of_injective; eauto. intros; subst r; discriminate. -Qed. - -Lemma sp_val': forall ms sp rs, agree ms sp rs -> sp = rs XSP. -Proof. - intros. eapply sp_val; eauto. -Qed. - -(** This is the simulation diagram. We prove it by case analysis on the Mach transition. *) - -Theorem step_simulation: - forall S1 t S2, Mach.step return_address_offset ge S1 t S2 -> - forall S1' (MS: match_states S1 S1') (WF: wf_state ge S1), - (exists S2', plus step tge S1' t S2' /\ match_states S2 S2') - \/ (measure S2 < measure S1 /\ t = E0 /\ match_states S2 S1')%nat. -Proof. - induction 1; intros; inv MS. - -- (* Mlabel *) - left; eapply exec_straight_steps; eauto; intros. - monadInv TR. econstructor; split. apply exec_straight_one. simpl; eauto. auto. - split. { apply agree_nextinstr; auto. } - split. { simpl; congruence. } - rewrite nextinstr_inv by congruence; assumption. - -- (* Mgetstack *) - unfold load_stack in H. - exploit Mem.loadv_extends; eauto. intros [v' [A B]]. - rewrite (sp_val _ _ _ AG) in A. - left; eapply exec_straight_steps; eauto. intros. simpl in TR. - exploit loadind_correct; eauto with asmgen. intros [rs' [P [Q [R S]]]]. - exists rs'; split. eauto. - split. { eapply agree_set_mreg; eauto with asmgen. congruence. } - split. { simpl; congruence. } - rewrite S. assumption. - -- (* Msetstack *) - unfold store_stack in H. - assert (Val.lessdef (rs src) (rs0 (preg_of src))) by (eapply preg_val; eauto). - exploit Mem.storev_extends; eauto. intros [m2' [A B]]. - left; eapply exec_straight_steps; eauto. - rewrite (sp_val _ _ _ AG) in A. intros. simpl in TR. - exploit storeind_correct; eauto with asmgen. intros [rs' [P [Q R]]]. - exists rs'; split. eauto. - split. eapply agree_undef_regs; eauto with asmgen. - simpl; intros. - split. rewrite Q; auto with asmgen. - rewrite R. assumption. - -- (* Mgetparam *) - assert (f0 = f) by congruence; subst f0. - unfold load_stack in *. - exploit Mem.loadv_extends. eauto. eexact H0. auto. - intros [parent' [A B]]. rewrite (sp_val' _ _ _ AG) in A. - exploit lessdef_parent_sp; eauto. clear B; intros B; subst parent'. - exploit Mem.loadv_extends. eauto. eexact H1. auto. - intros [v' [C D]]. -Opaque loadind. - left; eapply exec_straight_steps; eauto; intros. monadInv TR. - destruct ep. -(* X30 contains parent *) - exploit loadind_correct. eexact EQ. - instantiate (2 := rs0). simpl; rewrite DXP; eauto. simpl; congruence. - intros [rs1 [P [Q [R S]]]]. - exists rs1; split. eauto. - split. eapply agree_set_mreg. eapply agree_set_mreg; eauto. congruence. auto with asmgen. - simpl; split; intros. - { rewrite R; auto with asmgen. - apply preg_of_not_X29; auto. +Ltac destruct_reg_inv := + repeat match goal with + | [ H : match ?reg with _ => _ end = _ |- _ ] + => simpl in *; destruct reg; try congruence; try inv_ok_eq; try reg_rwrt + end. + +Ltac destruct_ireg_inv := + repeat match goal with + | [ H : match ?reg with _ => _ end = _ |- _ ] + => destruct reg as [[r|]|]; try congruence; try inv_ok_eq; subst + end. + +Ltac destruct_reg_size := + simpl in *; + match goal with + | [ |- context [ match ?reg with _ => _ end ] ] + => destruct reg; try congruence + end. + +Ltac find_rwrt_ag := + simpl in *; + match goal with + | [ AG: forall r, r <> ?PC -> _ r = _ r |- _ ] + => repeat rewrite <- AG; try congruence + end. + +Ltac inv_matchi := + match goal with + | [ MATCHI : match_internal _ _ _ |- _ ] + => inversion MATCHI; subst; find_rwrt_ag + end. + +Ltac destruct_ir0_reg := + match goal with + | [ |- context [ ir0 _ _ ?r ] ] + => unfold ir0 in *; destruct r; find_rwrt_ag; eauto + end. + +Ltac pc_not_sp := + match goal with + | [ |- ?PC <> ?SP ] + => destruct (PregEq.eq SP PC); repeat congruence; discriminate + end. + +Ltac update_x_access_x := + subst; rewrite !Pregmap.gss; auto. + +Ltac update_x_access_r := + rewrite !Pregmap.gso; auto. + +Lemma nextinstr_agree_but_pc rs1 rs2: forall + (AG: forall r, r <> PC -> rs1 r = rs2 r), + forall r, r <> PC -> rs1 r = Asm.nextinstr rs2 r. +Proof. + intros; unfold Asm.nextinstr in *; rewrite Pregmap.gso in *; eauto. +Qed. + +Lemma ptrofs_nextinstr_agree rs1 rs2 n: forall + (BOUNDED : 0 <= n <= Ptrofs.max_unsigned) + (AGPC : Val.offset_ptr (rs1 PC) (Ptrofs.repr n) = rs2 PC), + Val.offset_ptr (rs1 PC) (Ptrofs.repr (n + 1)) = Asm.nextinstr rs2 PC. +Proof. + intros; unfold Asm.nextinstr; rewrite Pregmap.gss. + rewrite <- Ptrofs.unsigned_one; rewrite <- (Ptrofs.unsigned_repr n); eauto; + rewrite <- Ptrofs.add_unsigned; rewrite <- Val.offset_ptr_assoc; rewrite AGPC; eauto. +Qed. + +Lemma load_preserved n rs1 m1 rs1' m1' rs2 m2 rd chk f a: forall + (BOUNDED: 0 <= n <= Ptrofs.max_unsigned) + (MATCHI: match_internal n (State rs1 m1) (State rs2 m2)) + (HLOAD: exec_load lk chk f a rd rs1 m1 = Next rs1' m1'), + exists (rs2' : regset) (m2' : mem), Asm.exec_load tge chk f a rd rs2 m2 = Next rs2' m2' + /\ match_internal (n + 1) (State rs1' m1') (State rs2' m2'). +Proof. + intros. + unfold exec_load, Asm.exec_load in *. + inversion MATCHI as [n0 r1 mx1 r2 mx2 EQM EQR EQPC]; subst. + rewrite <- (eval_addressing_preserved a rs1 rs2); auto. + destruct (Mem.loadv _ _ _). + + inversion HLOAD; auto. repeat (econstructor; eauto). + * eapply nextinstr_agree_but_pc; intros. + destruct (PregEq.eq r rd); try update_x_access_x; try update_x_access_r. + * eapply ptrofs_nextinstr_agree; eauto. + + next_stuck_cong. +Qed. + +Lemma store_preserved n rs1 m1 rs1' m1' rs2 m2 rd chk a: forall + (BOUNDED: 0 <= n <= Ptrofs.max_unsigned) + (MATCHI: match_internal n (State rs1 m1) (State rs2 m2)) + (HSTORE: exec_store lk chk a rd rs1 m1 = Next rs1' m1'), + exists (rs2' : regset) (m2' : mem), Asm.exec_store tge chk a rd rs2 m2 = Next rs2' m2' + /\ match_internal (n + 1) (State rs1' m1') (State rs2' m2'). +Proof. + intros. + unfold exec_store, Asm.exec_store in *. + inversion MATCHI as [n0 r1 mx1 r2 mx2 EQM EQR EQPC]; subst. + rewrite <- (eval_addressing_preserved a rs1 rs2); auto. + destruct (Mem.storev _ _ _ _). + + inversion HSTORE; auto. repeat (econstructor; eauto). + * eapply nextinstr_agree_but_pc; intros. + subst. apply EQR. auto. + * eapply ptrofs_nextinstr_agree; subst; eauto. + + next_stuck_cong. +Qed. + +Lemma next_inst_preserved n rs1 m1 rs1' m1' rs2 m2 (x: dreg) v: forall + (BOUNDED: 0 <= n <= Ptrofs.max_unsigned) + (MATCHI: match_internal n (State rs1 m1) (State rs2 m2)) + (NEXTI: Next rs1 # x <- v m1 = Next rs1' m1'), + exists (rs2' : regset) (m2' : mem), + Next (Asm.nextinstr rs2 # x <- v) m2 = Next rs2' m2' + /\ match_internal (n + 1) (State rs1' m1') (State rs2' m2'). +Proof. + intros. + inversion MATCHI as [n0 r1 mx1 r2 mx2 EQM EQR EQPC]; subst. + inversion NEXTI. repeat (econstructor; eauto). + * eapply nextinstr_agree_but_pc; intros. + destruct (PregEq.eq r x); try update_x_access_x; try update_x_access_r. + * eapply ptrofs_nextinstr_agree; eauto. +Qed. + +Lemma match_internal_nextinstr_switch: + forall n s rs2 m2 r v, + r <> PC -> + match_internal n s (State ((Asm.nextinstr rs2)#r <- v) m2) -> + match_internal n s (State (Asm.nextinstr (rs2#r <- v)) m2). +Proof. + unfold Asm.nextinstr; intros n s rs2 m2 r v NOTPC1 MI. + inversion MI; subst; constructor; auto. + - eapply nextinstr_agree_but_pc; intros. + rewrite AG; try congruence. + destruct (PregEq.eq r r0); try update_x_access_x; try update_x_access_r. + - rewrite !Pregmap.gss, !Pregmap.gso; try congruence. + rewrite AGPC. + rewrite Pregmap.gso, Pregmap.gss; try congruence. +Qed. + +Lemma match_internal_nextinstr_set_parallel: + forall n rs1 m1 rs2 m2 r v1 v2, + r <> PC -> + match_internal n (State rs1 m1) (State (Asm.nextinstr rs2) m2) -> + v1 = v2 -> + match_internal n (State (rs1#r <- v1) m1) (State (Asm.nextinstr (rs2#r <- v2)) m2). +Proof. + intros; subst; eapply match_internal_nextinstr_switch; eauto. + intros; eapply match_internal_set_parallel; eauto. +Qed. + +Lemma exec_basic_simulation: + forall tf n rs1 m1 rs1' m1' rs2 m2 bi tbi + (BOUNDED: 0 <= n <= Ptrofs.max_unsigned) + (BASIC: exec_basic lk ge bi rs1 m1 = Next rs1' m1') + (MATCHI: match_internal n (State rs1 m1) (State rs2 m2)) + (TRANSBI: basic_to_instruction bi = OK tbi), + exists rs2' m2', Asm.exec_instr tge tf tbi + rs2 m2 = Next rs2' m2' + /\ match_internal (n + 1) (State rs1' m1') (State rs2' m2'). +Proof. + intros. + destruct bi. + { (* PArith *) + simpl in *; destruct i. + 1,2,3,4,5,6: (* PArithP, PArithPP, PArithPPP, PArithRR0R, PArithRR0, PArithARRRR0 *) + destruct i; + try (destruct sumbool_rec; try congruence); + try (monadInv TRANSBI); + try (destruct_reg_inv); + try (inv_matchi); + try (exploit next_inst_preserved; eauto); + try (repeat destruct_reg_size); + try (destruct_ir0_reg). + { (* PArithComparisonPP *) + destruct i; + try (monadInv TRANSBI); + try (inv_matchi); + try (destruct_reg_inv); + simpl in *. + 1,2: (* compare_long *) + inversion BASIC; clear BASIC; subst; + eexists; eexists; split; eauto; + unfold compare_long; + repeat (eapply match_internal_nextinstr_set_parallel; [ congruence | idtac | try (rewrite !AG; congruence)]); + try (econstructor; eauto); + try (eapply nextinstr_agree_but_pc; eauto); + try (eapply ptrofs_nextinstr_agree; eauto). + + destruct sz. + - (* compare_single *) + unfold compare_single in BASIC. + destruct (rs1 x), (rs1 x0); + inversion BASIC; + eexists; eexists; split; eauto; + repeat (eapply match_internal_nextinstr_set_parallel; [ congruence | idtac | try (rewrite !AG; congruence)]); + try (econstructor; eauto); + try (eapply nextinstr_agree_but_pc; eauto); + try (eapply ptrofs_nextinstr_agree; eauto). + - (* compare_float *) + unfold compare_float in BASIC. + destruct (rs1 x), (rs1 x0); + inversion BASIC; + eexists; eexists; split; eauto; + repeat (eapply match_internal_nextinstr_set_parallel; [ congruence | idtac | try (rewrite !AG; congruence)]); + try (econstructor; eauto); + try (eapply nextinstr_agree_but_pc; eauto); + try (eapply ptrofs_nextinstr_agree; eauto). } + 1,2: (* PArithComparisonR0R, PArithComparisonP *) + destruct i; + try (monadInv TRANSBI); + try (inv_matchi); + try (destruct_reg_inv); + try (destruct_reg_size); + simpl in *; + inversion BASIC; clear BASIC; subst; + eexists; eexists; split; eauto; + unfold compare_long, compare_int, compare_float, compare_single; + try (destruct_reg_size); + repeat (eapply match_internal_nextinstr_set_parallel; [ congruence | idtac | try (rewrite !AG; congruence)]); + try (econstructor; eauto); + try (destruct_ir0_reg); + try (eapply nextinstr_agree_but_pc; eauto); + try (eapply ptrofs_nextinstr_agree; eauto). + { (* Pcset *) + try (monadInv TRANSBI); + try (inv_matchi). + try (exploit next_inst_preserved; eauto); + try (simpl in *; intros; + unfold if_opt_bool_val in *; unfold eval_testcond in *; + rewrite <- !AG; try congruence; eauto). } + { (* Pfmovi *) + try (monadInv TRANSBI); + try (inv_matchi); + try (destruct_reg_size); + try (destruct_ir0_reg); + try (exploit next_inst_preserved; eauto). } + { (* Pcsel *) + try (destruct_reg_inv); + try (monadInv TRANSBI); + try (destruct_reg_inv); + try (inv_matchi); + try (exploit next_inst_preserved; eauto); + simpl in *; intros; + unfold if_opt_bool_val in *; unfold eval_testcond in *; + rewrite <- !AG; try congruence; eauto. } + { (* Pfnmul *) + try (monadInv TRANSBI); + try (inv_matchi); + try (destruct_reg_size); + try (exploit next_inst_preserved; eauto); + try (find_rwrt_ag). } } + { (* PLoad *) + destruct ld; monadInv TRANSBI; try destruct_ireg_inv; exploit load_preserved; eauto; + intros; simpl in *; destruct sz; eauto. } + { (* PStore *) + destruct st; monadInv TRANSBI; try destruct_ireg_inv; exploit store_preserved; eauto; + simpl in *; inv_matchi; find_rwrt_ag. } + { (* Pallocframe *) + monadInv TRANSBI; + inv_matchi; try pc_not_sp; + destruct sz eqn:EQSZ; + destruct Mem.alloc eqn:EQALLOC; + destruct Mem.store eqn:EQSTORE; inversion BASIC; try pc_not_sp; + eexists; eexists; split; eauto; + repeat (eapply match_internal_nextinstr_set_parallel; [ try (pc_not_sp; congruence) | idtac | try (reflexivity)]); + try (econstructor; eauto); + try (eapply nextinstr_agree_but_pc; eauto); + try (eapply ptrofs_nextinstr_agree; eauto). } + { (* Pfreeframe *) + monadInv TRANSBI; + inv_matchi; try pc_not_sp; + destruct sz eqn:EQSZ; + destruct Mem.loadv eqn:EQLOAD; + destruct (rs1 SP) eqn:EQRS1SP; + try (destruct Mem.free eqn:EQFREE); + inversion BASIC; try pc_not_sp; + eexists; eexists; split; eauto; + repeat (eapply match_internal_nextinstr_set_parallel; [ try (pc_not_sp; congruence) | idtac | try (reflexivity)]); + try (econstructor; eauto); + try (eapply nextinstr_agree_but_pc; eauto); + try (eapply ptrofs_nextinstr_agree; eauto). } + 1,2,3,4: (* Ploadsymbol, Pcvtsw2x, Pcvtuw2x, Pcvtx2w *) + try (monadInv TRANSBI); + try (inv_matchi); + try (exploit next_inst_preserved; eauto); + rewrite symbol_addresses_preserved; eauto; + try (find_rwrt_ag). +Qed. + +Lemma find_basic_instructions b ofs f bb tc: forall + (FINDF: Genv.find_funct_ptr ge b = Some (Internal f)) + (FINDBB: find_bblock (Ptrofs.unsigned ofs) (fn_blocks f) = Some bb) + (UNFOLD: unfold (fn_blocks f) = OK tc), + forall n, + (n < length (body bb))%nat -> + exists (i : Asm.instruction) (bi : basic), + list_nth_z (body bb) (Z.of_nat n) = Some bi + /\ basic_to_instruction bi = OK i + /\ Asm.find_instr (Ptrofs.unsigned ofs + + (list_length_z (header bb)) + + Z.of_nat n) tc + = Some i. +Proof. + intros until n; intros NLT. + exploit internal_functions_unfold; eauto. + intros (tc' & FINDtf & TRANStf & _). + assert (tc' = tc) by congruence; subst. + exploit (find_instr_bblock (list_length_z (header bb) + Z.of_nat n)); eauto. + { unfold size; split. + - rewrite list_length_z_nat; omega. + - repeat (rewrite list_length_z_nat). repeat (rewrite Nat2Z.inj_add). omega. } + intros (i & NTH & FIND_INSTR). + exists i; intros. + inv NTH. + - (* absurd *) apply list_nth_z_range in H; omega. + - exists bi; + rewrite Z.add_simpl_l in H; + rewrite Z.add_assoc in FIND_INSTR; + intuition. + - (* absurd *) rewrite bblock_size_aux in H0; + rewrite H in H0; simpl in H0; repeat rewrite list_length_z_nat in H0; omega. +Qed. + +(** "is_tail" auxiliary lemma about is_tail to move in IterList ou Coqlib (déplacer aussi Machblockgenproof.is_tail_app_inv) ? *) + +Lemma is_tail_app_right A (l2 l1: list A): is_tail l1 (l2++l1). +Proof. + intros; eapply Machblockgenproof.is_tail_app_inv; econstructor. +Qed. + +Lemma is_tail_app_def A (l1 l2: list A): + is_tail l1 l2 -> exists l3, l2 = l3 ++ l1. +Proof. + induction 1 as [|x l1 l2]; simpl. + - exists nil; simpl; auto. + - destruct IHis_tail as (l3 & EQ); rewrite EQ. + exists (x::l3); simpl; auto. +Qed. + +Lemma is_tail_bound A (l1 l2: list A): + is_tail l1 l2 -> (length l1 <= length l2)%nat. +Proof. + intros H; destruct (is_tail_app_def _ _ _ H) as (l3 & EQ). + subst; rewrite app_length. + omega. +Qed. + +Lemma is_tail_list_nth_z A (l1 l2: list A): + is_tail l1 l2 -> list_nth_z l2 ((list_length_z l2) - (list_length_z l1)) = list_nth_z l1 0. +Proof. + induction 1; simpl. + - replace (list_length_z c - list_length_z c) with 0; omega || auto. + - assert (X: list_length_z (i :: c2) > list_length_z c1). + { rewrite !list_length_z_nat, <- Nat2Z.inj_gt. + exploit is_tail_bound; simpl; eauto. + omega. } + destruct (zeq (list_length_z (i :: c2) - list_length_z c1) 0) as [Y|Y]; try omega. + replace (Z.pred (list_length_z (i :: c2) - list_length_z c1)) with (list_length_z c2 - list_length_z c1); auto. + rewrite list_length_z_cons. + omega. +Qed. + +(* TODO: remplacer find_basic_instructions directement par ce lemme ? *) +Lemma find_basic_instructions_alt b ofs f bb tc n: forall + (FINDF: Genv.find_funct_ptr ge b = Some (Internal f)) + (FINDBB: find_bblock (Ptrofs.unsigned ofs) (fn_blocks f) = Some bb) + (UNFOLD: unfold (fn_blocks f) = OK tc) + (BOUND: 0 <= n < list_length_z (body bb)), + exists (i : Asm.instruction) (bi : basic), + list_nth_z (body bb) n = Some bi + /\ basic_to_instruction bi = OK i + /\ Asm.find_instr (Ptrofs.unsigned ofs + + (list_length_z (header bb)) + + n) tc + = Some i. +Proof. + intros; assert ((Z.to_nat n) < length (body bb))%nat. + { rewrite Nat2Z.inj_lt, <- list_length_z_nat, Z2Nat.id; try omega. } + exploit find_basic_instructions; eauto. + rewrite Z2Nat.id; try omega. intros (i & bi & X). + eexists; eexists; intuition eauto. +Qed. + +Lemma header_body_tail_bound: forall (a: basic) (li: list basic) bb ofs + (BOUNDBB : Ptrofs.unsigned ofs + size bb <= Ptrofs.max_unsigned) + (BDYLENPOS : 0 <= list_length_z (body bb) - list_length_z (a :: li) < + list_length_z (body bb)), +0 <= list_length_z (header bb) + list_length_z (body bb) - list_length_z (a :: li) <= +Ptrofs.max_unsigned. +Proof. + intros. + assert (HBBPOS: list_length_z (header bb) >= 0) by eapply list_length_z_pos. + assert (HBBSIZE: list_length_z (header bb) < size bb) by eapply header_size_lt_block_size. + assert (OFSBOUND: 0 <= Ptrofs.unsigned ofs <= Ptrofs.max_unsigned) by eapply Ptrofs.unsigned_range_2. + assert (BBSIZE: size bb <= Ptrofs.max_unsigned) by omega. + unfold size in BBSIZE. + rewrite !Nat2Z.inj_add in BBSIZE. + rewrite <- !list_length_z_nat in BBSIZE. + omega. +Qed. + +(* A more general version of the exec_body_simulation_plus lemma below. + This generalization is necessary for the induction proof inside the body. +*) +Lemma exec_body_simulation_plus_gen li: forall b ofs f bb rs m s2 rs' m' + (BLI: is_tail li (body bb)) + (ATPC: rs PC = Vptr b ofs) + (FINDF: Genv.find_funct_ptr ge b = Some (Internal f)) + (FINDBB: find_bblock (Ptrofs.unsigned ofs) (fn_blocks f) = Some bb) + (NEMPTY_BODY: li <> nil) + (MATCHI: match_internal ((list_length_z (header bb)) + (list_length_z (body bb)) - (list_length_z li)) (State rs m) s2) + (BODY: exec_body lk ge li rs m = Next rs' m'), + exists s2', plus Asm.step tge s2 E0 s2' + /\ match_internal (size bb - (Z.of_nat (length_opt (exit bb)))) (State rs' m') s2'. +Proof. + induction li as [|a li]; simpl; try congruence. + intros. + assert (BDYLENPOS: 0 <= (list_length_z (body bb) - list_length_z (a::li)) < list_length_z (body bb)). { + assert (Z.of_nat O < list_length_z (a::li) <= list_length_z (body bb)); try omega. + rewrite !list_length_z_nat; split. + - rewrite <- Nat2Z.inj_lt. simpl. omega. + - rewrite <- Nat2Z.inj_le; eapply is_tail_bound; eauto. } - { rewrite S; auto. } - -(* X30 does not contain parent *) - exploit loadptr_correct. eexact A. simpl; congruence. intros [rs1 [P [Q R]]]. - exploit loadind_correct. eexact EQ. instantiate (2 := rs1). simpl; rewrite Q. eauto. simpl; congruence. - intros [rs2 [S [T [U V]]]]. - exists rs2; split. eapply exec_straight_trans; eauto. - split. eapply agree_set_mreg. eapply agree_set_mreg. eauto. eauto. - instantiate (1 := rs1#X29 <- (rs2#X29)). intros. - rewrite Pregmap.gso; auto with asmgen. - congruence. - intros. unfold Pregmap.set. destruct (PregEq.eq r' X29). congruence. auto with asmgen. - split; simpl; intros. rewrite U; auto with asmgen. - apply preg_of_not_X29; auto. - rewrite V. rewrite R by congruence. auto. - -- (* Mop *) - assert (eval_operation tge sp op (map rs args) m = Some v). - { rewrite <- H. apply eval_operation_preserved. exact symbols_preserved. } - exploit eval_operation_lessdef. eapply preg_vals; eauto. eauto. eexact H0. - intros [v' [A B]]. rewrite (sp_val _ _ _ AG) in A. - left; eapply exec_straight_steps; eauto; intros. simpl in TR. - exploit transl_op_correct; eauto. intros [rs2 [P [Q [R S]]]]. - exists rs2; split. eauto. split. - apply agree_set_undef_mreg with rs0; auto. - apply Val.lessdef_trans with v'; auto. - split; simpl; intros. InvBooleans. - rewrite R; auto. apply preg_of_not_X29; auto. -Local Transparent destroyed_by_op. - destruct op; try exact I; simpl; congruence. - rewrite S. - auto. -- (* Mload *) - destruct trap. + exploit internal_functions_unfold; eauto. + intros (tc & FINDtf & TRANStf & _). + exploit find_basic_instructions_alt; eauto. + intros (tbi & (bi & (NTHBI & TRANSBI & FIND_INSTR))). + exploit is_tail_list_nth_z; eauto. + rewrite NTHBI; simpl. + intros X; inversion X; subst; clear X NTHBI. + destruct (exec_basic _ _ _ _ _) eqn:EXEC_BASIC; next_stuck_cong. + destruct s as (rs1 & m1); simpl in *. + destruct s2 as (rs2 & m2); simpl in *. + assert (BOUNDBBMAX: Ptrofs.unsigned ofs + size bb <= Ptrofs.max_unsigned) + by (eapply size_of_blocks_bounds; eauto). + exploit header_body_tail_bound; eauto. intros BDYTAIL. + exploit exec_basic_simulation; eauto. + intros (rs_next' & m_next' & EXEC_INSTR & MI_NEXT). + exploit exec_basic_dont_move_PC; eauto. intros AGPC. + inversion MI_NEXT as [A B C D E M_NEXT_AGREE RS_NEXT_AGREE ATPC_NEXT PC_OFS_NEXT RS RS']. + subst A. subst B. subst C. subst D. subst E. + rewrite ATPC in AGPC. symmetry in AGPC, ATPC_NEXT. + + inv MATCHI. symmetry in AGPC0. + rewrite ATPC in AGPC0. + unfold Val.offset_ptr in AGPC0. + + simpl in FIND_INSTR. + (* Execute internal step. *) + exploit (Asm.exec_step_internal tge b); eauto. { - assert (Op.eval_addressing tge sp addr (map rs args) = Some a). - { rewrite <- H. apply eval_addressing_preserved. exact symbols_preserved. } - exploit eval_addressing_lessdef. eapply preg_vals; eauto. eexact H1. - intros [a' [A B]]. rewrite (sp_val _ _ _ AG) in A. - exploit Mem.loadv_extends; eauto. intros [v' [C D]]. - left; eapply exec_straight_steps; eauto; intros. simpl in TR. - exploit transl_load_correct; eauto. intros [rs2 [P [Q [R S]]]]. - exists rs2; split. eauto. - split. eapply agree_set_undef_mreg; eauto. congruence. - split. simpl; congruence. - rewrite S. assumption. + rewrite Ptrofs.add_unsigned. + repeat (rewrite Ptrofs.unsigned_repr); try omega. + 2: { + assert (BOUNDOFS: 0 <= Ptrofs.unsigned ofs <= Ptrofs.max_unsigned) by eapply Ptrofs.unsigned_range_2. + assert (list_length_z (body bb) <= size bb) by eapply body_size_le_block_size. + assert (list_length_z (header bb) + list_length_z (body bb) <= size bb). + { generalize bblock_size_aux. intros. rewrite H0. generalize bblock_size_aux. intros. omega. } + omega. } + try rewrite list_length_z_nat; try split; + simpl; rewrite <- !list_length_z_nat; + replace (Ptrofs.unsigned ofs + (list_length_z (header bb) + list_length_z (body bb) - + list_length_z (a :: li))) with (Ptrofs.unsigned ofs + list_length_z (header bb) + + (list_length_z (body bb) - list_length_z (a :: li))) by omega; + try assumption; try omega. } + + (* This is our STEP hypothesis. *) + intros STEP_NEXT. + destruct li as [|a' li]; simpl in *. + - (* case of a single instruction in li: this our base case in the induction *) + inversion BODY; subst. + eexists; split. + + apply plus_one. eauto. + + constructor; auto. + rewrite ATPC_NEXT. + apply f_equal. + apply f_equal. + rewrite bblock_size_aux, list_length_z_cons; simpl. + omega. + - exploit (IHli b ofs f bb rs1 m_next' (State rs_next' m_next')); congruence || eauto. + + exploit is_tail_app_def; eauto. + intros (l3 & EQ); rewrite EQ. + exploit (is_tail_app_right _ (l3 ++ a::nil)). + rewrite <- app_assoc; simpl; eauto. + + constructor; auto. + rewrite ATPC_NEXT. + apply f_equal. + apply f_equal. + rewrite! list_length_z_cons; simpl. + omega. + + intros (s2' & LAST_STEPS & LAST_MATCHS). + eexists. split; eauto. + eapply plus_left'; eauto. +Qed. + +Lemma exec_body_simulation_plus b ofs f bb rs m s2 rs' m': forall + (ATPC: rs PC = Vptr b ofs) + (FINDF: Genv.find_funct_ptr ge b = Some (Internal f)) + (FINDBB: find_bblock (Ptrofs.unsigned ofs) (fn_blocks f) = Some bb) + (NEMPTY_BODY: body bb <> nil) + (MATCHI: match_internal (list_length_z (header bb)) (State rs m) s2) + (BODY: exec_body lk ge (body bb) rs m = Next rs' m'), + exists s2', plus Asm.step tge s2 E0 s2' + /\ match_internal (size bb - (Z.of_nat (length_opt (exit bb)))) (State rs' m') s2'. +Proof. + intros. + exploit exec_body_simulation_plus_gen; eauto. + - constructor. + - replace (list_length_z (header bb) + list_length_z (body bb) - list_length_z (body bb)) with (list_length_z (header bb)); auto. + omega. +Qed. + +Lemma exec_body_simulation_star b ofs f bb rs m s2 rs' m': forall + (ATPC: rs PC = Vptr b ofs) + (FINDF: Genv.find_funct_ptr ge b = Some (Internal f)) + (FINDBB: find_bblock (Ptrofs.unsigned ofs) (fn_blocks f) = Some bb) + (MATCHI: match_internal (list_length_z (header bb)) (State rs m) s2) + (BODY: exec_body lk ge (body bb) rs m = Next rs' m'), + exists s2', star Asm.step tge s2 E0 s2' + /\ match_internal (size bb - (Z.of_nat (length_opt (exit bb)))) (State rs' m') s2'. +Proof. + intros. + destruct (body bb) eqn: Hbb. + - simpl in BODY. inv BODY. + eexists. split. + eapply star_refl; eauto. + assert (EQ: (size bb - Z.of_nat (length_opt (exit bb))) = list_length_z (header bb)). + { rewrite bblock_size_aux. rewrite Hbb; unfold list_length_z; simpl. omega. } + rewrite EQ; eauto. + - exploit exec_body_simulation_plus; congruence || eauto. + { rewrite Hbb; eauto. } + intros (s2' & PLUS & MATCHI'). + eexists; split; eauto. + eapply plus_star; eauto. +Qed. + +Lemma list_nth_z_range_exceeded A (l : list A) n: + n >= list_length_z l -> + list_nth_z l n = None. +Proof. + intros N. + remember (list_nth_z l n) as opt eqn:H. symmetry in H. + destruct opt; auto. + exploit list_nth_z_range; eauto. omega. +Qed. + +Lemma label_in_header_list lbl a: + is_label lbl a = true -> list_length_z (header a) <= 1 -> header a = lbl :: nil. +Proof. + intros. + eapply is_label_correct_true in H. + destruct (header a). + - eapply in_nil in H. contradiction. + - rewrite list_length_z_cons in H0. + assert (list_length_z l0 >= 0) by eapply list_length_z_pos. + assert (list_length_z l0 = 0) by omega. + rewrite list_length_z_nat in H2. + assert (Datatypes.length l0 = 0%nat) by omega. + eapply length_zero_iff_nil in H3. subst. + unfold In in H. destruct H. + + subst; eauto. + + destruct H. +Qed. + +Lemma no_label_in_basic_inst: forall a lbl x, + basic_to_instruction a = OK x -> Asm.is_label lbl x = false. +Proof. + intros. + destruct a; simpl in *; + repeat destruct i; simpl in *; + try (try destruct_reg_inv; monadInv H; simpl in *; reflexivity). +Qed. + +Lemma label_pos_body bdy: forall c1 c2 z ex lbl + (HUNF : unfold_body bdy = OK c2), + Asm.label_pos lbl (z + Z.of_nat ((Datatypes.length bdy) + length_opt ex)) c1 = Asm.label_pos lbl (z) ((c2 ++ unfold_exit ex) ++ c1). +Proof. + induction bdy. + - intros. inversion HUNF. simpl in *. + destruct ex eqn:EQEX. + + simpl in *. unfold Asm.is_label. destruct c; simpl; try congruence. + destruct i; simpl; try congruence. + + simpl in *. ring_simplify (z + 0). auto. + - intros. inversion HUNF; clear HUNF. monadInv H0. simpl in *. + erewrite no_label_in_basic_inst; eauto. rewrite <- IHbdy; eauto. + erewrite Zpos_P_of_succ_nat. + apply f_equal2; auto. omega. +Qed. + +Lemma asm_label_pos_header: forall z a x0 x1 lbl + (HUNF: unfold_body (body a) = OK x1), + Asm.label_pos lbl (z + size a) x0 = + Asm.label_pos lbl (z + list_length_z (header a)) ((x1 ++ unfold_exit (exit a)) ++ x0). +Proof. + intros. + unfold size. + rewrite <- plus_assoc. rewrite Nat2Z.inj_add. + rewrite list_length_z_nat. + replace (z + (Z.of_nat (Datatypes.length (header a)) + Z.of_nat (Datatypes.length (body a) + length_opt (exit a)))) with (z + Z.of_nat (Datatypes.length (header a)) + Z.of_nat (Datatypes.length (body a) + length_opt (exit a))) by omega. + eapply (label_pos_body (body a) x0 x1 (z + Z.of_nat (Datatypes.length (header a))) (exit a) lbl). auto. +Qed. + +Lemma header_size_cons_nil: forall (l0: label) (l1: list label) + (HSIZE: list_length_z (l0 :: l1) <= 1), + l1 = nil. +Proof. + intros. + destruct l1; try congruence. rewrite !list_length_z_cons in HSIZE. + assert (list_length_z l1 >= 0) by eapply list_length_z_pos. + assert (list_length_z l1 + 1 + 1 >= 2) by omega. + assert (2 <= 1) by omega. contradiction H1. omega. +Qed. + +(*Lemma unfold_label_not_nil: forall a lbl*) + (*(HIN: In lbl (header a)),*) + (*unfold_label (header a) <> nil.*) +(*Proof.*) + (*intros. induction (header a).*) + (*- contradiction.*) + (*- destruct (peq lbl a0);*) + (*simpl; unfold not; intros; generalize nil_cons; intros;*) + (*specialize (H0 label a0 l); unfold not in H0; congruence.*) +(*Qed.*) + +(*Lemma label_pos_in a: forall lbl z*) + (*(EQLBL: In lbl (header a)),*) + (*Asm.label_pos lbl z (unfold_label (header a)) = Some z.*) +(*Proof.*) + (*intros.*) + (*induction (Asm.label_pos _ _ _) eqn:Hind.*) + (*- induction (unfold_label (header a)) eqn:Hunf.*) + (*+ eapply unfold_label_not_nil in EQLBL. congruence.*) + (*+ simpl in *. *) + (*destruct (Asm.is_label _ _) eqn:Hlbla.*) + (** symmetry. assumption.*) + (** apply IHl.*) + + (*induction (header a).*) + (** apply in_nil in EQLBL. contradiction.*) + (** simpl in *.*) + (*- unfold Asm.label_pos.*) + (*destruct (Asm.is_label) eqn:EQis; try reflexivity.*) + (*destruct (peq lbl (PLabel a0)).*) + +Lemma label_pos_preserved_gen bbs: forall lbl c z + (HUNF: unfold bbs = OK c), + label_pos lbl z bbs = Asm.label_pos lbl z c. +Proof. +Admitted. +(* induction bbs. + - intros. simpl in *. inversion HUNF. simpl. reflexivity. + - intros. simpl in *. monadInv HUNF. unfold unfold_bblock in EQ. + (*destruct (zle _ _); try congruence.*) + monadInv EQ. + destruct (is_label _ _) eqn:EQLBL. + erewrite <- is_label_correct_true in EQLBL. + + induction (Asm.label_pos) eqn:Hind. + * + + induction (header a) eqn:Hhead. + * apply in_nil in EQLBL. contradiction. + * simpl in *. destruct peq; try reflexivity. + erewrite IHl. + erewrite label_in_header_list; eauto. + simpl in *. destruct (peq lbl lbl); try congruence. + + erewrite IHbbs; eauto. + rewrite (asm_label_pos_header z a x0 x1 lbl); auto. + unfold is_label in *. + destruct (header a). + * replace (z + list_length_z (@nil label)) with (z); eauto. + unfold list_length_z. simpl. omega. + * eapply header_size_cons_nil in l as HL1. + subst. simpl in *. destruct (in_dec _ _); try congruence. + simpl in *. + destruct (peq _ _); try intuition congruence. +Qed.*) + +Lemma label_pos_preserved f lbl z tf: forall + (FINDF: transf_function f = OK tf), + label_pos lbl z (fn_blocks f) = Asm.label_pos lbl z (Asm.fn_code tf). +Proof. + intros. + eapply label_pos_preserved_gen. + unfold transf_function in FINDF. monadInv FINDF. + destruct zlt; try congruence. inversion EQ0. eauto. +Qed. + +Lemma goto_label_preserved bb rs1 m1 rs1' m1' rs2 m2 lbl f tf v: forall + (FINDF: transf_function f = OK tf) + (BOUNDED: size bb <= Ptrofs.max_unsigned) + (MATCHI: match_internal (size bb - 1) (State rs1 m1) (State rs2 m2)) + (HGOTO: goto_label f lbl (incrPC v rs1) m1 = Next rs1' m1'), + exists (rs2' : regset) (m2' : mem), Asm.goto_label tf lbl rs2 m2 = Next rs2' m2' + /\ match_states (State rs1' m1') (State rs2' m2'). +Proof. + intros. + unfold goto_label, Asm.goto_label in *. + rewrite <- (label_pos_preserved f); auto. + inversion MATCHI as [n0 r1 mx1 r2 mx2 EQM EQR EQPC]; subst. + destruct label_pos; next_stuck_cong. + destruct (incrPC v rs1 PC) eqn:INCRPC; next_stuck_cong. + inversion HGOTO; auto. repeat (econstructor; eauto). + rewrite <- EQPC. + unfold incrPC in *. + rewrite !Pregmap.gss in *. + destruct (rs1 PC) eqn:EQRS1; simpl in *; try congruence. + replace (rs2 # PC <- (Vptr b0 (Ptrofs.repr z))) with ((rs1 # PC <- (Vptr b0 (Ptrofs.add i0 v))) # PC <- (Vptr b (Ptrofs.repr z))); auto. + eapply functional_extensionality. intros. + destruct (PregEq.eq x PC); subst. + rewrite !Pregmap.gss. congruence. + rewrite !Pregmap.gso; auto. +Qed. + +Lemma next_inst_incr_pc_preserved bb rs1 m1 rs1' m1' rs2 m2 f tf: forall + (FINDF: transf_function f = OK tf) + (BOUNDED: size bb <= Ptrofs.max_unsigned) + (MATCHI: match_internal (size bb - 1) (State rs1 m1) (State rs2 m2)) + (NEXT: Next (incrPC (Ptrofs.repr (size bb)) rs1) m2 = Next rs1' m1'), + exists (rs2' : regset) (m2' : mem), + Next (Asm.nextinstr rs2) m2 = Next rs2' m2' + /\ match_states (State rs1' m1') (State rs2' m2'). +Proof. + intros; simpl in *; unfold incrPC in NEXT; + inv_matchi; + assert (size bb >= 1) by eapply bblock_size_pos; + assert (0 <= size bb - 1 <= Ptrofs.max_unsigned) by omega; + inversion NEXT; subst; + eexists; eexists; split; eauto. + assert (rs1 # PC <- (Val.offset_ptr (rs1 PC) (Ptrofs.repr (size bb))) = Asm.nextinstr rs2). { + unfold Pregmap.set. apply functional_extensionality. + intros x. destruct (PregEq.eq x PC). + -- unfold Asm.nextinstr. rewrite <- AGPC. + rewrite Val.offset_ptr_assoc. rewrite Ptrofs.add_unsigned. + rewrite (Ptrofs.unsigned_repr (size bb - 1)); try omega. + rewrite Ptrofs.unsigned_one. + replace (size bb - 1 + 1) with (size bb) by omega. + rewrite e. rewrite Pregmap.gss. + reflexivity. + -- eapply nextinstr_agree_but_pc; eauto. } + rewrite H1. econstructor. +Qed. + +Lemma pc_reg_overwrite: forall (r: ireg) rs1 m1 rs2 m2 bb + (MATCHI: match_internal (size bb - 1) (State rs1 m1) (State rs2 m2)), + rs2 # PC <- (rs2 r) = + (rs1 # PC <- (Val.offset_ptr (rs1 PC) (Ptrofs.repr (size bb)))) # PC <- + (rs1 r). +Proof. + intros. + unfold Pregmap.set; apply functional_extensionality. + intros x; destruct (PregEq.eq x PC) as [X | X]; try discriminate; inv_matchi. +Qed. + +Lemma exec_cfi_simulation: + forall bb f tf rs1 m1 rs1' m1' rs2 m2 cfi + (SIZE: size bb <= Ptrofs.max_unsigned) + (FINDF: transf_function f = OK tf) + (* Warning: Asmblock's PC is assumed to be already pointing on the next instruction ! *) + (CFI: exec_cfi ge f cfi (incrPC (Ptrofs.repr (size bb)) rs1) m1 = Next rs1' m1') + (MATCHI: match_internal (size bb - 1) (State rs1 m1) (State rs2 m2)), + exists rs2' m2', Asm.exec_instr tge tf (cf_instruction_to_instruction cfi) + rs2 m2 = Next rs2' m2' + /\ match_states (State rs1' m1') (State rs2' m2'). +Proof. + intros. + assert (BBPOS: size bb >= 1) by eapply bblock_size_pos. + destruct cfi; inv CFI; simpl. + - (* Pb *) + exploit goto_label_preserved; eauto. + - (* Pbc *) + inv_matchi. + unfold eval_testcond in *. destruct c; + erewrite !incrPC_agree_but_pc in H0; try rewrite <- !AG; try congruence. + all: + destruct_reg_size; + try destruct b eqn:EQB. + 1,4,7,10,13,16,19,22,25,28,31,34: + exploit goto_label_preserved; eauto. + 1,3,5,7,9,11,13,15,17,19,21,23: + exploit next_inst_incr_pc_preserved; eauto. + all: repeat (econstructor; eauto). + - (* Pbl *) + eexists; eexists; split; eauto. + assert ( ((incrPC (Ptrofs.repr (size bb)) rs1) # X30 <- (incrPC (Ptrofs.repr (size bb)) rs1 PC)) + # PC <- (Genv.symbol_address ge id Ptrofs.zero) + = (rs2 # X30 <- (Val.offset_ptr (rs2 PC) Ptrofs.one)) + # PC <- (Genv.symbol_address tge id Ptrofs.zero) + ) as EQRS. { + unfold incrPC. unfold Pregmap.set. simpl. apply functional_extensionality. + intros x. destruct (PregEq.eq x PC). + * rewrite symbol_addresses_preserved. reflexivity. + * destruct (PregEq.eq x X30). + -- inv MATCHI. rewrite <- AGPC. rewrite Val.offset_ptr_assoc. + unfold Ptrofs.add, Ptrofs.one. repeat (rewrite Ptrofs.unsigned_repr); try omega. + replace (size bb - 1 + 1) with (size bb) by omega. reflexivity. + -- inv MATCHI; rewrite AG; try assumption; reflexivity. + } rewrite EQRS; inv MATCHI; reflexivity. + - (* Pbs *) + eexists; eexists; split; eauto. + assert ( (incrPC (Ptrofs.repr (size bb)) rs1) # PC <- + (Genv.symbol_address ge id Ptrofs.zero) + = rs2 # PC <- (Genv.symbol_address tge id Ptrofs.zero) + ) as EQRS. { + unfold incrPC, Pregmap.set. rewrite symbol_addresses_preserved. inv MATCHI. + apply functional_extensionality. intros x. destruct (PregEq.eq x PC); auto. + } rewrite EQRS; inv MATCHI; reflexivity. + - (* Pblr *) + eexists; eexists; split; eauto. + unfold incrPC. rewrite Pregmap.gss. rewrite Pregmap.gso; try discriminate. + assert ( (rs2 # X30 <- (Val.offset_ptr (rs2 PC) Ptrofs.one)) # PC <- (rs2 r) + = ((rs1 # PC <- (Val.offset_ptr (rs1 PC) (Ptrofs.repr (size bb)))) + # X30 <- (Val.offset_ptr (rs1 PC) (Ptrofs.repr (size bb)))) + # PC <- (rs1 r) + ) as EQRS. { + unfold Pregmap.set. apply functional_extensionality. + intros x; destruct (PregEq.eq x PC) as [X | X]. + - inv_matchi; rewrite AG; auto. + - destruct (PregEq.eq x X30) as [X' | X']. + + inversion MATCHI; subst. rewrite <- AGPC. + rewrite Val.offset_ptr_assoc. unfold Ptrofs.one. + rewrite Ptrofs.add_unsigned. rewrite Ptrofs.unsigned_repr; try omega. rewrite Ptrofs.unsigned_repr; try omega. + rewrite Z.sub_add; reflexivity. + + inv_matchi. + } rewrite EQRS. inv_matchi. + - (* Pbr *) + eexists; eexists; split; eauto. + unfold incrPC. rewrite Pregmap.gso; try discriminate. + rewrite (pc_reg_overwrite r rs1 m1' rs2 m2 bb); auto. + inv_matchi. + - (* Pret *) + eexists; eexists; split; eauto. + unfold incrPC. rewrite Pregmap.gso; try discriminate. + rewrite (pc_reg_overwrite r rs1 m1' rs2 m2 bb); auto. + inv_matchi. + - (* Pcbnz *) + inv_matchi. + unfold eval_neg_branch in *. + erewrite incrPC_agree_but_pc in H0; try congruence. + destruct eval_testzero; next_stuck_cong. + destruct b. + * exploit next_inst_incr_pc_preserved; eauto. + * exploit goto_label_preserved; eauto. + - (* Pcbz *) + inv_matchi. + unfold eval_branch in *. + erewrite incrPC_agree_but_pc in H0; try congruence. + destruct eval_testzero; next_stuck_cong. + destruct b. + * exploit goto_label_preserved; eauto. + * exploit next_inst_incr_pc_preserved; eauto. + - (* Ptbnbz *) + inv_matchi. + unfold eval_branch in *. + erewrite incrPC_agree_but_pc in H0; try congruence. + destruct eval_testbit; next_stuck_cong. + destruct b. + * exploit goto_label_preserved; eauto. + * exploit next_inst_incr_pc_preserved; eauto. + - (* Ptbz *) + inv_matchi. + unfold eval_neg_branch in *. + erewrite incrPC_agree_but_pc in H0; try congruence. + destruct eval_testbit; next_stuck_cong. + destruct b. + * exploit next_inst_incr_pc_preserved; eauto. + * exploit goto_label_preserved; eauto. + - (* Pbtbl *) + assert (rs2 # X16 <- Vundef r1 = (incrPC (Ptrofs.repr (size bb)) rs1) # X16 <- Vundef r1) + as EQUNDEFX16. { + unfold incrPC, Pregmap.set. + destruct (PregEq.eq r1 X16) as [X16 | X16]; auto. + destruct (PregEq.eq r1 PC) as [PC' | PC']; try discriminate. + inv MATCHI; rewrite AG; auto. + } rewrite <- EQUNDEFX16 in H0. + destruct_reg_inv; next_stuck_cong. + unfold goto_label, Asm.goto_label in *. + rewrite <- (label_pos_preserved f); auto. + inversion MATCHI; subst. + destruct label_pos; next_stuck_cong. + destruct (((incrPC (Ptrofs.repr (size bb)) rs1) # X16 <- Vundef) # X17 <- Vundef PC) eqn:INCRPC; next_stuck_cong. + inversion H0; auto. repeat (econstructor; eauto). + rewrite !Pregmap.gso; try congruence. + rewrite <- AGPC. + unfold incrPC in *. + destruct (rs1 PC) eqn:EQRS1; simpl in *; try discriminate. + replace (((rs2 # X16 <- Vundef) # X17 <- Vundef) # PC <- (Vptr b0 (Ptrofs.repr z))) with + ((((rs1 # PC <- (Vptr b0 (Ptrofs.add i1 (Ptrofs.repr (size bb))))) # X16 <- + Vundef) # X17 <- Vundef) # PC <- (Vptr b (Ptrofs.repr z))); auto. + eapply functional_extensionality; intros x. + destruct (PregEq.eq x PC); subst. + + rewrite Pregmap.gso in INCRPC; try congruence. + rewrite Pregmap.gso in INCRPC; try congruence. + rewrite Pregmap.gss in INCRPC. + rewrite !Pregmap.gss in *; congruence. + + rewrite Pregmap.gso; auto. + rewrite (Pregmap.gso (i := x) (j := PC)); auto. + destruct (PregEq.eq x X17); subst. + * rewrite !Pregmap.gss; auto. + * rewrite !(Pregmap.gso (i := x) (j:= X17)); auto. destruct (PregEq.eq x X16); subst. + -- rewrite !Pregmap.gss; auto. + -- rewrite !Pregmap.gso; auto. +Qed. + +Lemma last_instruction_cannot_be_label bb: + list_nth_z (header bb) (size bb - 1) = None. +Proof. + assert (list_length_z (header bb) <= size bb - 1). { + rewrite bblock_size_aux. generalize (bblock_size_aux_pos bb). omega. } - - (* Mload notrap1 *) - inv AT. simpl in *. unfold bind in *. destruct (transl_code _ _ _) in *; discriminate. - -- (* Mload notrap *) - inv AT. simpl in *. unfold bind in *. destruct (transl_code _ _ _) in *; discriminate. - -- (* Mload notrap *) - inv AT. simpl in *. unfold bind in *. destruct (transl_code _ _ _) in *; discriminate. - -- (* Mstore *) - assert (Op.eval_addressing tge sp addr (map rs args) = Some a). - { rewrite <- H. apply eval_addressing_preserved. exact symbols_preserved. } - exploit eval_addressing_lessdef. eapply preg_vals; eauto. eexact H1. - intros [a' [A B]]. rewrite (sp_val _ _ _ AG) in A. - assert (Val.lessdef (rs src) (rs0 (preg_of src))) by (eapply preg_val; eauto). - exploit Mem.storev_extends; eauto. intros [m2' [C D]]. - left; eapply exec_straight_steps; eauto. - intros. simpl in TR. exploit transl_store_correct; eauto. intros [rs2 [P [Q R]]]. - exists rs2; split. eauto. - split. eapply agree_undef_regs; eauto with asmgen. - split. simpl; congruence. - rewrite R. assumption. - -- (* Mcall *) - assert (f0 = f) by congruence. subst f0. - inv AT. - assert (NOOV: list_length_z tf.(fn_code) <= Ptrofs.max_unsigned). - { eapply transf_function_no_overflow; eauto. } - destruct ros as [rf|fid]; simpl in H; monadInv H5. -+ (* Indirect call *) - assert (rs rf = Vptr f' Ptrofs.zero). - { destruct (rs rf); try discriminate. - revert H; predSpec Ptrofs.eq Ptrofs.eq_spec i Ptrofs.zero; intros; congruence. } - assert (rs0 x0 = Vptr f' Ptrofs.zero). - { exploit ireg_val; eauto. rewrite H5; intros LD; inv LD; auto. } - generalize (code_tail_next_int _ _ _ _ NOOV H6). intro CT1. - assert (TCA: transl_code_at_pc ge (Vptr fb (Ptrofs.add ofs Ptrofs.one)) fb f c false tf x). - { econstructor; eauto. } - exploit return_address_offset_correct; eauto. intros; subst ra. - left; econstructor; split. - apply plus_one. eapply exec_step_internal. Simpl. rewrite <- H2; simpl; eauto. - eapply functions_transl; eauto. eapply find_instr_tail; eauto. - simpl. eauto. - econstructor; eauto. - econstructor; eauto. - eapply agree_sp_def; eauto. - simpl. eapply agree_exten; eauto. intros. Simpl. - Simpl. rewrite <- H2. auto. -+ (* Direct call *) - generalize (code_tail_next_int _ _ _ _ NOOV H6). intro CT1. - assert (TCA: transl_code_at_pc ge (Vptr fb (Ptrofs.add ofs Ptrofs.one)) fb f c false tf x). - econstructor; eauto. - exploit return_address_offset_correct; eauto. intros; subst ra. - left; econstructor; split. - apply plus_one. eapply exec_step_internal. eauto. - eapply functions_transl; eauto. eapply find_instr_tail; eauto. - simpl. unfold Genv.symbol_address. rewrite symbols_preserved. rewrite H. eauto. - econstructor; eauto. - econstructor; eauto. - eapply agree_sp_def; eauto. - simpl. eapply agree_exten; eauto. intros. Simpl. - Simpl. rewrite <- H2. auto. - -- (* Mtailcall *) - assert (f0 = f) by congruence. subst f0. - inversion AT; subst. - assert (NOOV: list_length_z tf.(fn_code) <= Ptrofs.max_unsigned). - { eapply transf_function_no_overflow; eauto. } - exploit Mem.loadv_extends. eauto. eexact H1. auto. simpl. intros [parent' [A B]]. - destruct ros as [rf|fid]; simpl in H; monadInv H7. -+ (* Indirect call *) - assert (rs rf = Vptr f' Ptrofs.zero). - { destruct (rs rf); try discriminate. - revert H; predSpec Ptrofs.eq Ptrofs.eq_spec i Ptrofs.zero; intros; congruence. } - assert (rs0 x0 = Vptr f' Ptrofs.zero). - { exploit ireg_val; eauto. rewrite H7; intros LD; inv LD; auto. } - exploit make_epilogue_correct; eauto. intros (rs1 & m1 & U & V & W & X & Y & Z). - exploit exec_straight_steps_2; eauto using functions_transl. - intros (ofs' & P & Q). - left; econstructor; split. - (* execution *) - eapply plus_right'. eapply exec_straight_exec; eauto. - econstructor. eexact P. eapply functions_transl; eauto. eapply find_instr_tail. eexact Q. - simpl. reflexivity. - traceEq. - (* match states *) - econstructor; eauto. - apply agree_set_other; auto with asmgen. - Simpl. rewrite Z by (rewrite <- (ireg_of_eq _ _ EQ1); eauto with asmgen). assumption. -+ (* Direct call *) - exploit make_epilogue_correct; eauto. intros (rs1 & m1 & U & V & W & X & Y & Z). - exploit exec_straight_steps_2; eauto using functions_transl. - intros (ofs' & P & Q). - left; econstructor; split. - (* execution *) - eapply plus_right'. eapply exec_straight_exec; eauto. - econstructor. eexact P. eapply functions_transl; eauto. eapply find_instr_tail. eexact Q. - simpl. reflexivity. - traceEq. - (* match states *) - econstructor; eauto. - apply agree_set_other; auto with asmgen. - Simpl. unfold Genv.symbol_address. rewrite symbols_preserved. rewrite H. auto. - -- (* Mbuiltin *) - inv AT. monadInv H4. - exploit functions_transl; eauto. intro FN. - generalize (transf_function_no_overflow _ _ H3); intro NOOV. - exploit builtin_args_match; eauto. intros [vargs' [P Q]]. - exploit external_call_mem_extends; eauto. - intros [vres' [m2' [A [B [C D]]]]]. - left. econstructor; split. apply plus_one. - eapply exec_step_builtin. eauto. eauto. - eapply find_instr_tail; eauto. - erewrite <- sp_val by eauto. - eapply eval_builtin_args_preserved with (ge1 := ge); eauto. exact symbols_preserved. - eapply external_call_symbols_preserved; eauto. apply senv_preserved. - eauto. - econstructor; eauto. - instantiate (2 := tf); instantiate (1 := x). - unfold nextinstr. rewrite Pregmap.gss. - rewrite set_res_other. rewrite undef_regs_other_2. - rewrite <- H1. simpl. econstructor; eauto. - eapply code_tail_next_int; eauto. - rewrite preg_notin_charact. intros. auto with asmgen. - auto with asmgen. - apply agree_nextinstr. eapply agree_set_res; auto. - eapply agree_undef_regs; eauto. intros. rewrite undef_regs_other_2; auto. - congruence. - - Simpl. - rewrite set_res_other by trivial. - rewrite undef_regs_other. - assumption. - intro. - rewrite in_map_iff. - intros (x0 & PREG & IN). - subst r'. - intro. - apply (preg_of_not_RA x0). - congruence. - -- (* Mgoto *) - assert (f0 = f) by congruence. subst f0. - inv AT. monadInv H4. - exploit find_label_goto_label; eauto. intros [tc' [rs' [GOTO [AT2 INV]]]]. - left; exists (State rs' m'); split. - apply plus_one. econstructor; eauto. - eapply functions_transl; eauto. - eapply find_instr_tail; eauto. - simpl; eauto. - econstructor; eauto. - eapply agree_exten; eauto with asmgen. - congruence. - - rewrite INV by congruence. - assumption. - -- (* Mcond true *) - assert (f0 = f) by congruence. subst f0. - exploit eval_condition_lessdef. eapply preg_vals; eauto. eauto. eauto. intros EC. - left; eapply exec_straight_opt_steps_goto; eauto. - intros. simpl in TR. - exploit transl_cond_branch_correct; eauto. intros (rs' & jmp & A & B & C & D). - exists jmp; exists k; exists rs'. - split. eexact A. - split. apply agree_exten with rs0; auto with asmgen. - split. - exact B. - rewrite D. exact LEAF. - -- (* Mcond false *) - exploit eval_condition_lessdef. eapply preg_vals; eauto. eauto. eauto. intros EC. - left; eapply exec_straight_steps; eauto. intros. simpl in TR. - exploit transl_cond_branch_correct; eauto. intros (rs' & jmp & A & B & C & D). - econstructor; split. - eapply exec_straight_opt_right. eexact A. apply exec_straight_one. eexact B. auto. - split. apply agree_exten with rs0; auto. intros. Simpl. - split. - simpl; congruence. - Simpl. rewrite D. - exact LEAF. - -- (* Mjumptable *) - assert (f0 = f) by congruence. subst f0. - inv AT. monadInv H6. - exploit functions_transl; eauto. intro FN. - generalize (transf_function_no_overflow _ _ H5); intro NOOV. - exploit find_label_goto_label. eauto. eauto. - instantiate (2 := rs0#X16 <- Vundef #X17 <- Vundef). - Simpl. eauto. - eauto. - intros [tc' [rs' [A [B C]]]]. - exploit ireg_val; eauto. rewrite H. intros LD; inv LD. - left; econstructor; split. - apply plus_one. econstructor; eauto. - eapply find_instr_tail; eauto. - simpl. Simpl. rewrite <- H9. unfold Mach.label in H0; unfold label; rewrite H0. eexact A. - econstructor; eauto. - eapply agree_undef_regs; eauto. - simpl. intros. rewrite C; auto with asmgen. Simpl. - congruence. - - rewrite C by congruence. - repeat rewrite Pregmap.gso by congruence. - assumption. - -- (* Mreturn *) - assert (f0 = f) by congruence. subst f0. - inversion AT; subst. simpl in H6; monadInv H6. - assert (NOOV: list_length_z tf.(fn_code) <= Ptrofs.max_unsigned). - eapply transf_function_no_overflow; eauto. - exploit make_epilogue_correct; eauto. intros (rs1 & m1 & U & V & W & X & Y & Z). - exploit exec_straight_steps_2; eauto using functions_transl. - intros (ofs' & P & Q). - left; econstructor; split. - (* execution *) - eapply plus_right'. eapply exec_straight_exec; eauto. - econstructor. eexact P. eapply functions_transl; eauto. eapply find_instr_tail. eexact Q. - simpl. reflexivity. - traceEq. - (* match states *) - econstructor; eauto. - apply agree_set_other; auto with asmgen. - -- (* internal function *) - - exploit functions_translated; eauto. intros [tf [A B]]. monadInv B. - generalize EQ; intros EQ'. monadInv EQ'. - destruct (zlt Ptrofs.max_unsigned (list_length_z x0.(fn_code))); inversion EQ1. clear EQ1. subst x0. - unfold store_stack in *. - exploit Mem.alloc_extends. eauto. eauto. apply Z.le_refl. apply Z.le_refl. - intros [m1' [C D]]. - exploit Mem.storev_extends. eexact D. eexact H1. eauto. eauto. - intros [m2' [F G]]. - simpl chunk_of_type in F. - exploit Mem.storev_extends. eexact G. eexact H2. eauto. eauto. - intros [m3' [P Q]]. - change (chunk_of_type Tptr) with Mint64 in *. - (* Execution of function prologue *) - monadInv EQ0. rewrite transl_code'_transl_code in EQ1. - set (tfbody := Pallocframe (fn_stacksize f) (fn_link_ofs f) :: - storeptr RA XSP (fn_retaddr_ofs f) x0) in *. - set (tf := {| fn_sig := Mach.fn_sig f; fn_code := tfbody |}) in *. - set (rs2 := nextinstr (rs0#X29 <- (parent_sp s) #SP <- sp #X16 <- Vundef)). - exploit (storeptr_correct tge tf XSP (fn_retaddr_ofs f) RA x0 m2' m3' rs2). - simpl preg_of_iregsp. change (rs2 X30) with (rs0 X30). rewrite ATLR. - change (rs2 X2) with sp. eexact P. - simpl; congruence. congruence. - intros (rs3 & U & V & W). - assert (EXEC_PROLOGUE: - exec_straight tge tf - tf.(fn_code) rs0 m' - x0 rs3 m3'). - { change (fn_code tf) with tfbody; unfold tfbody. - apply exec_straight_step with rs2 m2'. - unfold exec_instr. rewrite C. fold sp. - rewrite <- (sp_val _ _ _ AG). rewrite F. reflexivity. - reflexivity. - eexact U. } - exploit exec_straight_steps_2; eauto using functions_transl. omega. constructor. - intros (ofs' & X & Y). - left; exists (State rs3 m3'); split. - eapply exec_straight_steps_1; eauto. omega. constructor. - econstructor; eauto. - rewrite X; econstructor; eauto. - apply agree_exten with rs2; eauto with asmgen. - unfold rs2. - apply agree_nextinstr. apply agree_set_other; auto with asmgen. - apply agree_change_sp with (parent_sp s). - apply agree_undef_regs with rs0. auto. -Local Transparent destroyed_at_function_entry. simpl. - simpl; intros; Simpl. - unfold sp; congruence. - intros. rewrite V by auto with asmgen. reflexivity. - - rewrite W. - unfold rs2. - Simpl. - -- (* external function *) - exploit functions_translated; eauto. - intros [tf [A B]]. simpl in B. inv B. - exploit extcall_arguments_match; eauto. - intros [args' [C D]]. - exploit external_call_mem_extends; eauto. - intros [res' [m2' [P [Q [R S]]]]]. - left; econstructor; split. - apply plus_one. eapply exec_step_external; eauto. - eapply external_call_symbols_preserved; eauto. apply senv_preserved. - econstructor; eauto. - unfold loc_external_result. apply agree_set_other; auto. apply agree_set_pair; auto. - apply agree_undef_caller_save_regs; auto. - -- (* return *) - inv STACKS. simpl in *. - right. split. omega. split. auto. - rewrite <- ATPC in H5. - econstructor; eauto. congruence. - inv WF. - inv STACK. - inv H1. - congruence. + remember (list_nth_z (header bb) (size bb - 1)) as label_opt; destruct label_opt; auto; + exploit list_nth_z_range; eauto; omega. Qed. -Lemma transf_initial_states: - forall st1, Mach.initial_state prog st1 -> - exists st2, Asm.initial_state tprog st2 /\ match_states st1 st2. +Lemma pc_ptr_exec_step: forall ofs bb b rs m _rs _m + (ATPC : rs PC = Vptr b ofs) + (MATCHI : match_internal (size bb - 1) + {| _rs := rs; _m := m |} + {| _rs := _rs; _m := _m |}), + _rs PC = Vptr b (Ptrofs.add ofs (Ptrofs.repr (size bb - 1))). Proof. - intros. inversion H. unfold ge0 in *. - econstructor; split. - econstructor. - eapply (Genv.init_mem_transf_partial TRANSF); eauto. - replace (Genv.symbol_address (Genv.globalenv tprog) (prog_main tprog) Ptrofs.zero) - with (Vptr fb Ptrofs.zero). - econstructor; eauto. - constructor. - apply Mem.extends_refl. - split. auto. simpl. unfold Vnullptr; destruct Archi.ptr64; congruence. - intros. rewrite Regmap.gi. auto. - unfold Genv.symbol_address. - rewrite (match_program_main TRANSF). - rewrite symbols_preserved. - unfold ge; rewrite H1. auto. + intros; inv MATCHI. rewrite <- AGPC; rewrite ATPC; unfold Val.offset_ptr; eauto. Qed. -Lemma transf_final_states: - forall st1 st2 r, - match_states st1 st2 -> Mach.final_state st1 r -> Asm.final_state st2 r. +Lemma find_instr_ofs_somei: forall ofs bb f tc asmi rs m _rs _m + (BOUNDOFS : Ptrofs.unsigned ofs + size bb <= Ptrofs.max_unsigned) + (FIND_INSTR : Asm.find_instr (Ptrofs.unsigned ofs + (size bb - 1)) tc = + Some (asmi)) + (MATCHI : match_internal (size bb - 1) + {| _rs := rs; _m := m |} + {| _rs := _rs; _m := _m |}), + Asm.find_instr (Ptrofs.unsigned (Ptrofs.add ofs (Ptrofs.repr (size bb - 1)))) + (Asm.fn_code {| Asm.fn_sig := fn_sig f; Asm.fn_code := tc |}) = + Some (asmi). Proof. - intros. inv H0. inv H. constructor. assumption. - compute in H1. inv H1. - generalize (preg_val _ _ _ R0 AG). rewrite H2. intros LD; inv LD. auto. + intros; simpl. + replace (Ptrofs.unsigned (Ptrofs.add ofs (Ptrofs.repr (size bb - 1)))) + with (Ptrofs.unsigned ofs + (size bb - 1)); try assumption. + generalize (bblock_size_pos bb); generalize (Ptrofs.unsigned_range_2 ofs); intros. + unfold Ptrofs.add. + rewrite Ptrofs.unsigned_repr. rewrite Ptrofs.unsigned_repr; try omega. + rewrite Ptrofs.unsigned_repr; omega. Qed. -Theorem transf_program_correct: - forward_simulation (Mach.semantics return_address_offset prog) (Asm.semantics tprog). +Lemma eval_builtin_arg_match: forall rs _m _rs a1 b1 + (AG : forall r : preg, r <> PC -> rs r = _rs r) + (EVAL : eval_builtin_arg tge (fun r : dreg => rs r) (rs SP) _m a1 b1), + eval_builtin_arg tge _rs (_rs SP) _m (map_builtin_arg DR a1) b1. +Proof. + intros; induction EVAL; simpl in *; try rewrite AG; try rewrite AG in EVAL; try discriminate; try congruence; eauto with barg. + econstructor. rewrite <- AG; try discriminate; auto. +Qed. + +Lemma eval_builtin_args_match: forall bb rs m _rs _m args vargs + (MATCHI : match_internal (size bb - 1) + {| _rs := rs; _m := m |} + {| _rs := _rs; _m := _m |}) + (EVAL : eval_builtin_args tge (fun r : dreg => rs r) (rs SP) m args vargs), + eval_builtin_args tge _rs (_rs SP) _m (map (map_builtin_arg DR) args) vargs. +Proof. + intros; inv MATCHI. + induction EVAL; subst. + - econstructor. + - econstructor. + + eapply eval_builtin_arg_match; eauto. + + eauto. +Qed. + +Lemma pc_both_sides: forall (rs _rs: regset) v + (AG : forall r : preg, r <> PC -> rs r = _rs r), + rs # PC <- v = _rs # PC <- v. +Proof. + intros; unfold Pregmap.set; apply functional_extensionality; intros y. + destruct (PregEq.eq y PC); try rewrite AG; eauto. +Qed. + +Lemma set_buitin_res_sym res: forall vres rs _rs r + (NPC: r <> PC) + (AG : forall r : preg, r <> PC -> rs r = _rs r), + set_res res vres rs r = set_res res vres _rs r. +Proof. + induction res; simpl; intros; unfold Pregmap.set; try rewrite AG; eauto. +Qed. + +Lemma set_builtin_res_dont_move_pc_gen res: forall vres rs _rs v1 v2 + (HV: v1 = v2) + (AG : forall r : preg, r <> PC -> rs r = _rs r), + (set_res res vres rs) # PC <- v1 = + (set_res res vres _rs) # PC <- v2. +Proof. + intros. rewrite HV. generalize res vres rs _rs AG v2. + clear res vres rs _rs AG v1 v2 HV. + induction res. + - simpl; intros. apply pc_both_sides; intros. + unfold Pregmap.set; try rewrite AG; eauto. + - simpl; intros; apply pc_both_sides; eauto. + - simpl; intros. + erewrite IHres2; eauto; intros. + eapply set_buitin_res_sym; eauto. +Qed. + +Lemma set_builtin_map_not_pc (res: builtin_res dreg): forall vres rs, + set_res (map_builtin_res DR res) vres rs PC = rs PC. +Proof. + induction res. + - intros; simpl. unfold Pregmap.set. destruct (PregEq.eq PC x); try congruence. + - intros; simpl; congruence. + - intros; simpl in *. rewrite IHres2. rewrite IHres1. reflexivity. +Qed. + +Lemma undef_reg_preserved (rl: list mreg): forall rs _rs r + (NPC: r <> PC) + (AG : forall r : preg, r <> PC -> rs r = _rs r), + undef_regs (map preg_of rl) rs r = undef_regs (map preg_of rl) _rs r. +Proof. + induction rl. + - simpl; auto. + - simpl; intros. erewrite IHrl; eauto. + intros. unfold Pregmap.set. destruct (PregEq.eq r0 (preg_of a)); try rewrite AG; eauto. +Qed. + +Lemma undef_regs_other: + forall r rl rs, + (forall r', In r' rl -> r <> r') -> + undef_regs rl rs r = rs r. Proof. - eapply forward_simulation_star with (measure := measure) - (match_states := fun S1 S2 => match_states S1 S2 /\ wf_state ge S1). + induction rl; simpl; intros. auto. + rewrite IHrl by auto. rewrite Pregmap.gso; auto. +Qed. + +Fixpoint preg_notin (r: preg) (rl: list mreg) : Prop := + match rl with + | nil => True + | r1 :: nil => r <> preg_of r1 + | r1 :: rl => r <> preg_of r1 /\ preg_notin r rl + end. + +Remark preg_notin_charact: + forall r rl, + preg_notin r rl <-> (forall mr, In mr rl -> r <> preg_of mr). +Proof. + induction rl; simpl; intros. + tauto. + destruct rl. + simpl. split. intros. intuition congruence. auto. + rewrite IHrl. split. + intros [A B]. intros. destruct H. congruence. auto. + auto. +Qed. + +Lemma undef_regs_other_2: + forall r rl rs, + preg_notin r rl -> + undef_regs (map preg_of rl) rs r = rs r. +Proof. + intros. apply undef_regs_other. intros. + exploit list_in_map_inv; eauto. intros [mr [A B]]. subst. + rewrite preg_notin_charact in H. auto. +Qed. + +Lemma exec_exit_simulation_plus b ofs f bb s2 t rs m rs' m': forall + (FINDF: Genv.find_funct_ptr ge b = Some (Internal f)) + (FINDBB: find_bblock (Ptrofs.unsigned ofs) (fn_blocks f) = Some bb) + (NEMPTY_EXIT: exit bb <> None) + (MATCHI: match_internal (size bb - Z.of_nat (length_opt (exit bb))) (State rs m) s2) + (EXIT: exec_exit ge f (Ptrofs.repr (size bb)) rs m (exit bb) t rs' m') + (ATPC: rs PC = Vptr b ofs), + plus Asm.step tge s2 t (State rs' m'). +Proof. + intros. + exploit internal_functions_unfold; eauto. + intros (tc & FINDtf & TRANStf & _). + + exploit (find_instr_bblock (size bb - 1)); eauto. + { generalize (bblock_size_pos bb). omega. } + intros (i' & NTH & FIND_INSTR). + + inv NTH. + + rewrite last_instruction_cannot_be_label in *. discriminate. + + destruct (exit bb) as [ctrl |] eqn:NEMPTY_EXIT'. 2: { contradiction. } + rewrite bblock_size_aux in *. rewrite NEMPTY_EXIT' in *. simpl in *. + (* XXX: Is there a better way to simplify this expression i.e. automatically? *) + replace (list_length_z (header bb) + list_length_z (body bb) + 1 - 1 - + list_length_z (header bb)) with (list_length_z (body bb)) in H by omega. + rewrite list_nth_z_range_exceeded in H; try omega. discriminate. + + assert (Ptrofs.unsigned ofs + size bb <= Ptrofs.max_unsigned). { + eapply size_of_blocks_bounds; eauto. + } + assert (size bb <= Ptrofs.max_unsigned). { generalize (Ptrofs.unsigned_range_2 ofs); omega. } + destruct cfi. + * (* control flow instruction *) + destruct s2. + rewrite H in EXIT. (* exit bb is a cfi *) + inv EXIT. + rewrite H in MATCHI. simpl in MATCHI. + exploit internal_functions_translated; eauto. + rewrite FINDtf. + intros (tf & FINDtf' & TRANSf). inversion FINDtf'; subst; clear FINDtf'. + exploit exec_cfi_simulation; eauto. + (* extract exec_cfi_simulation's conclusion as separate hypotheses *) + intros (rs2' & m2' & EXECI & MATCHS); rewrite MATCHS. + apply plus_one. + eapply Asm.exec_step_internal; eauto. + - eapply pc_ptr_exec_step; eauto. + - eapply find_instr_ofs_somei; eauto. + * (* builtin *) + destruct s2. + rewrite H in EXIT. + rewrite H in MATCHI. simpl in MATCHI. + simpl in FIND_INSTR. + inversion EXIT. + apply plus_one. + eapply external_call_symbols_preserved in H10; try (apply senv_preserved). + eapply eval_builtin_args_preserved in H6; try (apply symbols_preserved). + eapply Asm.exec_step_builtin; eauto. + - eapply pc_ptr_exec_step; eauto. + - eapply find_instr_ofs_somei; eauto. + - eapply eval_builtin_args_match; eauto. + - inv MATCHI; eauto. + - inv MATCHI. + unfold Asm.nextinstr, incrPC. + assert (HPC: Val.offset_ptr (rs PC) (Ptrofs.repr (size bb)) + = Val.offset_ptr (_rs PC) Ptrofs.one). + { rewrite <- AGPC. rewrite ATPC. unfold Val.offset_ptr. + rewrite Ptrofs.add_assoc. unfold Ptrofs.add. + assert (BBPOS: size bb >= 1) by eapply bblock_size_pos. + rewrite (Ptrofs.unsigned_repr (size bb - 1)); try omega. + rewrite Ptrofs.unsigned_one. + replace (size bb - 1 + 1) with (size bb) by omega. + reflexivity. } + apply set_builtin_res_dont_move_pc_gen. + -- erewrite !set_builtin_map_not_pc. + erewrite !undef_regs_other_2. + rewrite HPC; auto. all: rewrite preg_notin_charact; intros; try discriminate. + -- intros. eapply undef_reg_preserved; eauto. +Qed. + +Lemma exec_exit_simulation_star b ofs f bb s2 t rs m rs' m': forall + (FINDF: Genv.find_funct_ptr ge b = Some (Internal f)) + (FINDBB: find_bblock (Ptrofs.unsigned ofs) (fn_blocks f) = Some bb) + (MATCHI: match_internal (size bb - Z.of_nat (length_opt (exit bb))) (State rs m) s2) + (EXIT: exec_exit ge f (Ptrofs.repr (size bb)) rs m (exit bb) t rs' m') + (ATPC: rs PC = Vptr b ofs), + star Asm.step tge s2 t (State rs' m'). +Proof. + intros. + destruct (exit bb) eqn: Hex. + - eapply plus_star. + eapply exec_exit_simulation_plus; try rewrite Hex; congruence || eauto. + - inv MATCHI. + inv EXIT. + assert (X: rs2 = incrPC (Ptrofs.repr (size bb)) rs). { + unfold incrPC. unfold Pregmap.set. + apply functional_extensionality. intros x. + destruct (PregEq.eq x PC) as [X|]. + - rewrite X. rewrite <- AGPC. simpl. + replace (size bb - 0) with (size bb) by omega. reflexivity. + - rewrite AG; try assumption. reflexivity. + } + destruct X. + subst; eapply star_refl; eauto. +Qed. + +Lemma exec_bblock_simulation b ofs f bb t rs m rs' m': forall + (ATPC: rs PC = Vptr b ofs) + (FINDF: Genv.find_funct_ptr ge b = Some (Internal f)) + (FINDBB: find_bblock (Ptrofs.unsigned ofs) (fn_blocks f) = Some bb) + (EXECBB: exec_bblock lk ge f bb rs m t rs' m'), + plus Asm.step tge (State rs m) t (State rs' m'). +Proof. + intros; destruct EXECBB as (rs1 & m1 & BODY & CTL). + exploit exec_header_simulation; eauto. + intros (s0 & STAR & MATCH0). + eapply star_plus_trans; traceEq || eauto. + destruct (bblock_non_empty bb). + - (* body bb <> nil *) + exploit exec_body_simulation_plus; eauto. + intros (s1 & PLUS & MATCH1). + eapply plus_star_trans; traceEq || eauto. + eapply exec_exit_simulation_star; eauto. + erewrite <- exec_body_dont_move_PC; eauto. + - (* exit bb <> None *) + exploit exec_body_simulation_star; eauto. + intros (s1 & STAR1 & MATCH1). + eapply star_plus_trans; traceEq || eauto. + eapply exec_exit_simulation_plus; eauto. + erewrite <- exec_body_dont_move_PC; eauto. +Qed. + +Lemma step_simulation s t s': + Asmblock.step lk ge s t s' -> plus Asm.step tge s t s'. +Proof. + intros STEP. + inv STEP; simpl; exploit functions_translated; eauto; + intros (tf0 & FINDtf & TRANSf); + monadInv TRANSf. + - (* internal step *) eapply exec_bblock_simulation; eauto. + - (* external step *) + apply plus_one. + exploit external_call_symbols_preserved; eauto. apply senv_preserved. + intros ?. + eapply Asm.exec_step_external; eauto. +Qed. + +Lemma transf_program_correct: + forward_simulation (Asmblock.semantics lk prog) (Asm.semantics tprog). +Proof. + eapply forward_simulation_plus. - apply senv_preserved. - - simpl; intros. exploit transf_initial_states; eauto. - intros (s2 & A & B). - exists s2; intuition auto. apply wf_initial; auto. - - simpl; intros. destruct H as [MS WF]. eapply transf_final_states; eauto. - - simpl; intros. destruct H0 as [MS WF]. - exploit step_simulation; eauto. intros [ (s2' & A & B) | (A & B & C) ]. - + left; exists s2'; intuition auto. eapply wf_step; eauto. - + right; intuition auto. eapply wf_step; eauto. + - eexact transf_initial_states. + - eexact transf_final_states. + - (* TODO step_simulation *) + unfold match_states. + simpl; intros; subst; eexists; split; eauto. + eapply step_simulation; eauto. Qed. End PRESERVATION. + +End Asmblock_PRESERVATION. + + +Local Open Scope linking_scope. + +Definition block_passes := + mkpass Machblockgenproof.match_prog + ::: mkpass PseudoAsmblockproof.match_prog + ::: mkpass Asmblockgenproof.match_prog + ::: mkpass PostpassSchedulingproof.match_prog + ::: mkpass Asmblock_PRESERVATION.match_prog + ::: pass_nil _. + +Definition match_prog := pass_match (compose_passes block_passes). + +Lemma transf_program_match: + forall p tp, Asmgen.transf_program p = OK tp -> match_prog p tp. +Proof. + intros p tp H. + unfold Asmgen.transf_program in H. apply bind_inversion in H. destruct H. + inversion_clear H. apply bind_inversion in H1. destruct H1. + inversion_clear H. apply bind_inversion in H2. destruct H2. inversion_clear H. + unfold Compopts.time in *. remember (Machblockgen.transf_program p) as mbp. + unfold match_prog; simpl. + exists mbp; split. apply Machblockgenproof.transf_program_match; auto. + exists x; split. apply PseudoAsmblockproof.transf_program_match; auto. + exists x0; split. apply Asmblockgenproof.transf_program_match; auto. + exists x1; split. apply PostpassSchedulingproof.transf_program_match; auto. + exists tp; split. apply Asmblock_PRESERVATION.transf_program_match; auto. auto. +Qed. + +(** Return Address Offset *) + +Definition return_address_offset: Mach.function -> Mach.code -> ptrofs -> Prop := + Machblockgenproof.Mach_return_address_offset (PseudoAsmblockproof.rao Asmblockgenproof.next). + +Lemma return_address_exists: + forall f sg ros c, is_tail (Mach.Mcall sg ros :: c) f.(Mach.fn_code) -> + exists ra, return_address_offset f c ra. +Proof. + intros; eapply Machblockgenproof.Mach_return_address_exists; eauto. +Admitted. + +Section PRESERVATION. + +Variable prog: Mach.program. +Variable tprog: Asm.program. +Hypothesis TRANSF: match_prog prog tprog. +Let ge := Genv.globalenv prog. +Let tge := Genv.globalenv tprog. + +Theorem transf_program_correct: + forward_simulation (Mach.semantics return_address_offset prog) (Asm.semantics tprog). +Proof. +Admitted. +(* TODO + unfold match_prog in TRANSF. simpl in TRANSF. + inv TRANSF. inv H. inv H1. inv H. inv H2. inv H. inv H3. inv H. inv H4. inv H. + eapply compose_forward_simulations. + { exploit Machblockgenproof.transf_program_correct; eauto. } + eapply compose_forward_simulations. + + apply PseudoAsmblockproof.transf_program_correct; eauto. + - intros; apply Asmblockgenproof.next_progress. + - intros. eapply .functions_bound_max_pos; eauto. + { intros. eapply Asmblock_PRESERVATION.symbol_high_low. eauto. } + + eapply compose_forward_simulations. apply Asmblockgenproof.transf_program_correct; eauto. + { intros; eapply Asmblock_PRESERVATION.symbol_high_low; eauto. } + apply Asmblock_PRESERVATION.transf_program_correct. eauto. +Qed.*) + +End PRESERVATION. + +Instance TransfAsm: TransfLink match_prog := pass_match_link (compose_passes block_passes). + +(*******************************************) +(* Stub actually needed by driver/Compiler *) + +Module Asmgenproof0. + +Definition return_address_offset := return_address_offset. + +End Asmgenproof0. diff --git a/aarch64/Asmgenproof_orig_single_label_in_header.v.stash b/aarch64/Asmgenproof_orig_single_label_in_header.v.stash new file mode 100644 index 00000000..bff18716 --- /dev/null +++ b/aarch64/Asmgenproof_orig_single_label_in_header.v.stash @@ -0,0 +1,2245 @@ +(* *************************************************************) +(* *) +(* The Compcert verified compiler *) +(* *) +(* Sylvain Boulmé Grenoble-INP, VERIMAG *) +(* Léo Gourdin UGA, VERIMAG *) +(* Justus Fasse UGA, VERIMAG *) +(* Xavier Leroy INRIA Paris-Rocquencourt *) +(* David Monniaux CNRS, VERIMAG *) +(* Cyril Six Kalray *) +(* *) +(* Copyright Kalray. Copyright VERIMAG. All rights reserved. *) +(* This file is distributed under the terms of the INRIA *) +(* Non-Commercial License Agreement. *) +(* *) +(* *************************************************************) + +Require Import Coqlib Errors. +Require Import Integers Floats AST Linking. +Require Import Values Memory Events Globalenvs Smallstep. +Require Import Op Locations Machblock Conventions PseudoAsmblock Asm Asmblock. +Require Machblockgenproof Asmblockgenproof PostpassSchedulingproof. +Require Import Asmgen. +Require Import Axioms. +Require Import IterList. +Require Import Ring. + +Module Asmblock_PRESERVATION. + +Import Asmblock_TRANSF. + +Definition match_prog (p: Asmblock.program) (tp: Asm.program) := + match_program (fun _ f tf => transf_fundef f = OK tf) eq p tp. + +Lemma transf_program_match: + forall p tp, transf_program p = OK tp -> match_prog p tp. +Proof. + intros. eapply match_transform_partial_program; eauto. +Qed. + +Section PRESERVATION. + +Variable prog: Asmblock.program. +Variable tprog: Asm.program. +Hypothesis TRANSF: match_prog prog tprog. +Let ge := Genv.globalenv prog. +Let tge := Genv.globalenv tprog. + +Definition lk :aarch64_linker := {| Asmblock.symbol_low:=Asm.symbol_low tge; Asmblock.symbol_high:=Asm.symbol_high tge|}. + +Lemma symbols_preserved: + forall (s: ident), Genv.find_symbol tge s = Genv.find_symbol ge s. +Proof (Genv.find_symbol_match TRANSF). + +Lemma symbol_addresses_preserved: + forall (s: ident) (ofs: ptrofs), + Genv.symbol_address tge s ofs = Genv.symbol_address ge s ofs. +Proof. + intros; unfold Genv.symbol_address; rewrite symbols_preserved; reflexivity. +Qed. + +Lemma senv_preserved: + Senv.equiv ge tge. +Proof (Genv.senv_match TRANSF). + +Lemma symbol_high_low: forall (id: ident) (ofs: ptrofs), + Val.addl (Asmblock.symbol_high lk id ofs) (Asmblock.symbol_low lk id ofs) = Genv.symbol_address ge id ofs. +Proof. + unfold lk; simpl. intros; rewrite Asm.symbol_high_low; unfold Genv.symbol_address; + rewrite symbols_preserved; reflexivity. +Qed. + +Lemma functions_translated: + forall b f, + Genv.find_funct_ptr ge b = Some f -> + exists tf, + Genv.find_funct_ptr tge b = Some tf /\ transf_fundef f = OK tf. +Proof (Genv.find_funct_ptr_transf_partial TRANSF). + +Lemma internal_functions_translated: + forall b f, + Genv.find_funct_ptr ge b = Some (Internal f) -> + exists tf, + Genv.find_funct_ptr tge b = Some (Internal tf) /\ transf_function f = OK tf. +Proof. + intros; exploit functions_translated; eauto. + intros (x & FIND & TRANSf). + apply bind_inversion in TRANSf. + destruct TRANSf as (tf & TRANSf & X). + inv X. + eauto. +Qed. + +Lemma internal_functions_unfold: + forall b f, + Genv.find_funct_ptr ge b = Some (Internal f) -> + exists tc, + Genv.find_funct_ptr tge b = Some (Internal (Asm.mkfunction (fn_sig f) tc)) + /\ unfold (fn_blocks f) = OK tc + /\ list_length_z tc <= Ptrofs.max_unsigned. +Proof. + intros. + exploit internal_functions_translated; eauto. + intros (tf & FINDtf & TRANStf). + unfold transf_function in TRANStf. + monadInv TRANStf. + destruct (zlt _ _); try congruence. + inv EQ. inv EQ0. + eexists; intuition eauto. + omega. +Qed. + + +Inductive is_nth_inst (bb: bblock) (n:Z) (i:Asm.instruction): Prop := + | is_nth_label l: + list_nth_z (header bb) n = Some l -> + i = Asm.Plabel l -> + is_nth_inst bb n i + | is_nth_basic bi: + list_nth_z (body bb) (n - list_length_z (header bb)) = Some bi -> + basic_to_instruction bi = OK i -> + is_nth_inst bb n i + | is_nth_ctlflow cfi: + (exit bb) = Some cfi -> + n = size bb - 1 -> + i = control_to_instruction cfi -> + is_nth_inst bb n i. + +(* Asmblock and Asm share the same definition of state *) +Definition match_states (s1 s2 : state) := s1 = s2. + +Inductive match_internal: forall n, state -> state -> Prop := + | match_internal_intro n rs1 m1 rs2 m2 + (MEM: m1 = m2) + (AG: forall r, r <> PC -> rs1 r = rs2 r) + (AGPC: Val.offset_ptr (rs1 PC) (Ptrofs.repr n) = rs2 PC) + : match_internal n (State rs1 m1) (State rs2 m2). + +Lemma match_internal_set_parallel: + forall n rs1 m1 rs2 m2 r val, + match_internal n (State rs1 m1) (State rs2 m2) -> + r <> PC -> + match_internal n (State (rs1#r <- val) m1) (State (rs2#r <- val ) m2). +Proof. + intros n rs1 m1 rs2 m2 r v MI. + inversion MI; constructor; auto. + - intros r' NOTPC. + unfold Pregmap.set; rewrite AG. reflexivity. assumption. + - unfold Pregmap.set; destruct (PregEq.eq PC r); congruence. +Qed. + +Lemma agree_match_states: + forall rs1 m1 rs2 m2, + match_states (State rs1 m1) (State rs2 m2) -> + forall r : preg, rs1#r = rs2#r. +Proof. + intros. + unfold match_states in *. + assert (rs1 = rs2) as EQ. { congruence. } + rewrite EQ. reflexivity. +Qed. + +Lemma match_states_set_parallel: + forall rs1 m1 rs2 m2 r v, + match_states (State rs1 m1) (State rs2 m2) -> + match_states (State (rs1#r <- v) m1) (State (rs2#r <- v) m2). +Proof. + intros; unfold match_states in *. + assert (rs1 = rs2) as RSEQ. { congruence. } + assert (m1 = m2) as MEQ. { congruence. } + rewrite RSEQ in *; rewrite MEQ in *; unfold Pregmap.set; reflexivity. +Qed. + +(* match_internal from match_states *) +Lemma mi_from_ms: + forall rs1 m1 rs2 m2 b ofs, + match_states (State rs1 m1) (State rs2 m2) -> + rs1#PC = Vptr b ofs -> + match_internal 0 (State rs1 m1) (State rs2 m2). +Proof. + intros rs1 m1 rs2 m2 b ofs MS PCVAL. + inv MS; constructor; auto; unfold Val.offset_ptr; + rewrite PCVAL; rewrite Ptrofs.add_zero; reflexivity. +Qed. + +Lemma transf_initial_states: + forall s1, Asmblock.initial_state prog s1 -> + exists s2, Asm.initial_state tprog s2 /\ match_states s1 s2. +Proof. + intros ? INIT_s1. + inversion INIT_s1 as (m, ?, ge0, rs). unfold ge0 in *. + econstructor; split. + - econstructor. + eapply (Genv.init_mem_transf_partial TRANSF); eauto. + - rewrite (match_program_main TRANSF); rewrite symbol_addresses_preserved. + unfold rs; reflexivity. +Qed. + +Lemma transf_final_states: + forall s1 s2 r, + match_states s1 s2 -> Asmblock.final_state s1 r -> Asm.final_state s2 r. +Proof. + intros s1 s2 r MATCH FINAL_s1. + inv FINAL_s1; inv MATCH; constructor; assumption. +Qed. + +Definition max_pos (f : Asm.function) := list_length_z f.(Asm.fn_code). + +Lemma functions_bound_max_pos: forall fb f tf, + Genv.find_funct_ptr ge fb = Some (Internal f) -> + transf_function f = OK tf -> + max_pos tf <= Ptrofs.max_unsigned. +Proof. + intros fb f tf FINDf TRANSf. + unfold transf_function in TRANSf. + apply bind_inversion in TRANSf. + destruct TRANSf as (c & TRANSf). + destruct TRANSf as (_ & TRANSf). + destruct (zlt _ _). + - inversion TRANSf. + - unfold max_pos. + assert (Asm.fn_code tf = c) as H. { inversion TRANSf as (H'); auto. } + rewrite H; omega. +Qed. + +Lemma one_le_max_unsigned: + 1 <= Ptrofs.max_unsigned. +Proof. + unfold Ptrofs.max_unsigned; simpl; unfold Ptrofs.wordsize; + unfold Wordsize_Ptrofs.wordsize; destruct Archi.ptr64; simpl; omega. +Qed. + +(* NB: does not seem useful anymore, with the [exec_header_simulation] proof below +Lemma match_internal_exec_label: + forall n rs1 m1 rs2 m2 l fb f tf, + Genv.find_funct_ptr ge fb = Some (Internal f) -> + transf_function f = OK tf -> + match_internal n (State rs1 m1) (State rs2 m2) -> + n >= 0 -> + (* There is no step if n is already max_pos *) + n < (max_pos tf) -> + exists rs2' m2', Asm.exec_instr tge tf (Asm.Plabel l) rs2 m2 = Next rs2' m2' + /\ match_internal (n+1) (State rs1 m1) (State rs2' m2'). +Proof. + intros. (* XXX auto generated names *) + unfold Asm.exec_instr. + eexists; eexists; split; eauto. + inversion H1; constructor; auto. + - intros; unfold Asm.nextinstr; unfold Pregmap.set; + destruct (PregEq.eq r PC); auto; contradiction. + - unfold Asm.nextinstr; rewrite Pregmap.gss; unfold Ptrofs.one. + rewrite <- AGPC; rewrite Val.offset_ptr_assoc; unfold Ptrofs.add; + rewrite Ptrofs.unsigned_repr. rewrite Ptrofs.unsigned_repr; trivial. + + split. + * apply Z.le_0_1. + * apply one_le_max_unsigned. + + split. + * apply Z.ge_le; assumption. + * rewrite <- functions_bound_max_pos; eauto; omega. +Qed. +*) + +Lemma incrPC_agree_but_pc: + forall rs r ofs, + r <> PC -> + (incrPC ofs rs)#r = rs#r. +Proof. + intros rs r ofs NOTPC. + unfold incrPC; unfold Pregmap.set; destruct (PregEq.eq r PC). + - contradiction. + - reflexivity. +Qed. + +Lemma bblock_non_empty bb: body bb <> nil \/ exit bb <> None. +Proof. + destruct bb. simpl. + unfold non_empty_bblockb in correct. + unfold non_empty_body, non_empty_exit, Is_true in correct. + destruct body, exit. + - right. discriminate. + - contradiction. + - right. discriminate. + - left. discriminate. +Qed. + +Lemma list_length_z_aux_increase A (l: list A): forall acc, + list_length_z_aux l acc >= acc. +Proof. + induction l; simpl; intros. + - omega. + - generalize (IHl (Z.succ acc)). omega. +Qed. + +Lemma bblock_size_aux_pos bb: list_length_z (body bb) + Z.of_nat (length_opt (exit bb)) >= 1. +Proof. + destruct (bblock_non_empty bb), (body bb) as [|hd tl], (exit bb); simpl; + try (congruence || omega); + unfold list_length_z; simpl; + generalize (list_length_z_aux_increase _ tl 1); omega. +Qed. + + +Lemma list_length_add_acc A (l : list A) acc: + list_length_z_aux l acc = (list_length_z l) + acc. +Proof. + unfold list_length_z, list_length_z_aux. simpl. + fold list_length_z_aux. + rewrite (list_length_z_aux_shift l acc 0). + omega. +Qed. + +Lemma list_length_z_cons A hd (tl : list A): + list_length_z (hd :: tl) = list_length_z tl + 1. +Proof. + unfold list_length_z; simpl; rewrite list_length_add_acc; reflexivity. +Qed. + +(*Lemma length_agree A (l : list A):*) + (*list_length_z l = Z.of_nat (length l).*) +(*Proof.*) + (*induction l as [| ? l IH]; intros.*) + (*- unfold list_length_z; reflexivity.*) + (*- simpl; rewrite list_length_z_cons, Zpos_P_of_succ_nat; omega.*) +(*Qed.*) + +Lemma bblock_size_aux bb: size bb = list_length_z (header bb) + list_length_z (body bb) + Z.of_nat (length_opt (exit bb)). +Proof. + unfold size. + repeat (rewrite list_length_z_nat). repeat (rewrite Nat2Z.inj_add). reflexivity. +Qed. + +Lemma header_size_lt_block_size bb: + list_length_z (header bb) < size bb. +Proof. + rewrite bblock_size_aux. + generalize (bblock_non_empty bb); intros NEMPTY; destruct NEMPTY as [HDR|EXIT]. + - destruct (body bb); try contradiction; rewrite list_length_z_cons; + repeat rewrite list_length_z_nat; omega. + - destruct (exit bb); try contradiction; simpl; repeat rewrite list_length_z_nat; omega. +Qed. + +Lemma body_size_le_block_size bb: + list_length_z (body bb) <= size bb. +Proof. + rewrite bblock_size_aux; repeat rewrite list_length_z_nat; omega. +Qed. + + +Lemma bblock_size_pos bb: size bb >= 1. +Proof. + rewrite (bblock_size_aux bb). + generalize (bblock_size_aux_pos bb). + generalize (list_length_z_pos (header bb)). + omega. +Qed. + +Lemma unfold_car_cdr bb bbs tc: + unfold (bb :: bbs) = OK tc -> + exists tbb tc', unfold_bblock bb = OK tbb + /\ unfold bbs = OK tc' + /\ unfold (bb :: bbs) = OK (tbb ++ tc'). +Proof. + intros UNFOLD. + assert (UF := UNFOLD). + unfold unfold in UNFOLD. + apply bind_inversion in UNFOLD. destruct UNFOLD as (? & UBB). destruct UBB as (UBB & REST). + apply bind_inversion in REST. destruct REST as (? & UNFOLD'). + fold unfold in UNFOLD'. destruct UNFOLD' as (UNFOLD' & UNFOLD). + rewrite <- UNFOLD in UF. + eauto. +Qed. + +Lemma unfold_cdr bb bbs tc: + unfold (bb :: bbs) = OK tc -> + exists tc', unfold bbs = OK tc'. +Proof. + intros; exploit unfold_car_cdr; eauto. intros (_ & ? & _ & ? & _). + eexists; eauto. +Qed. + +Lemma unfold_car bb bbs tc: + unfold (bb :: bbs) = OK tc -> + exists tbb, unfold_bblock bb = OK tbb. +Proof. + intros; exploit unfold_car_cdr; eauto. intros (? & _ & ? & _ & _). + eexists; eauto. +Qed. + +Lemma all_blocks_translated: + forall bbs tc, + unfold bbs = OK tc -> + forall bb, In bb bbs -> + exists c, unfold_bblock bb = OK c. +Proof. + induction bbs as [| bb bbs IHbbs]. + - contradiction. + - intros ? UNFOLD ? IN. + (* unfold proceeds by unfolding the basic block at the head of the list and + * then recurring *) + exploit unfold_car_cdr; eauto. intros (? & ? & ? & ? & _). + (* basic block is either in head or tail *) + inversion IN as [EQ | NEQ]. + + rewrite <- EQ; eexists; eauto. + + eapply IHbbs; eauto. +Qed. + +Lemma entire_body_translated: + forall lbi tc, + unfold_body lbi = OK tc -> + forall bi, In bi lbi -> + exists bi', basic_to_instruction bi = OK bi'. +Proof. + induction lbi as [| a lbi IHlbi]. + - intros. contradiction. + - intros tc UNFOLD_BODY bi IN. + unfold unfold_body in UNFOLD_BODY. apply bind_inversion in UNFOLD_BODY. + destruct UNFOLD_BODY as (? & TRANSbi & REST). + apply bind_inversion in REST. destruct REST as (? & UNFOLD_BODY' & ?). + fold unfold_body in UNFOLD_BODY'. + + inversion IN as [EQ | NEQ]. + + rewrite <- EQ; eauto. + + eapply IHlbi; eauto. +Qed. + +Lemma bblock_in_bblocks bbs bb: forall + tc pos + (UNFOLD: unfold bbs = OK tc) + (FINDBB: find_bblock pos bbs = Some bb), + In bb bbs. +Proof. + induction bbs as [| b bbs IH]. + - intros. inversion FINDBB. + - destruct pos. + + intros. inversion FINDBB as (EQ). rewrite <- EQ. apply in_eq. + + intros. + exploit unfold_cdr; eauto. intros (tc' & UNFOLD'). + unfold find_bblock in FINDBB. simpl in FINDBB. + fold find_bblock in FINDBB. + apply in_cons. eapply IH; eauto. + + intros. inversion FINDBB. +Qed. + +Lemma blocks_translated tc pos bbs bb: forall + (UNFOLD: unfold bbs = OK tc) + (FINDBB: find_bblock pos bbs = Some bb), + exists tbb, unfold_bblock bb = OK tbb. +Proof. + intros; exploit bblock_in_bblocks; eauto; intros; + eapply all_blocks_translated; eauto. +Qed. + +Lemma size_header b pos f bb: forall + (FINDF: Genv.find_funct_ptr ge b = Some (Internal f)) + (FINDBB: find_bblock pos (fn_blocks f) = Some bb), + list_length_z (header bb) <= 1. +Proof. + intros. + exploit internal_functions_unfold; eauto. + intros (tc & FINDtf & TRANStf & ?). + exploit blocks_translated; eauto. intros TBB. + + unfold unfold_bblock in TBB. + destruct (zle (list_length_z (header bb)) 1). + - assumption. + - destruct TBB as (? & TBB). discriminate TBB. +Qed. + +Lemma list_nth_z_neg A (l: list A): forall n, + n < 0 -> list_nth_z l n = None. +Proof. + induction l; simpl; auto. + intros n H; destruct (zeq _ _); (try eapply IHl); omega. +Qed. + +Lemma find_bblock_neg bbs: forall pos, + pos < 0 -> find_bblock pos bbs = None. +Proof. + induction bbs; simpl; auto. + intros. destruct (zlt pos 0). { reflexivity. } + destruct (zeq pos 0); contradiction. +Qed. + +Lemma equal_header_size bb: + length (header bb) = length (unfold_label (header bb)). +Proof. + induction (header bb); auto. + simpl. rewrite IHl. auto. +Qed. + +Lemma equal_body_size: + forall bb tb, + unfold_body (body bb) = OK tb -> + length (body bb) = length tb. +Proof. + intros bb. induction (body bb). + - simpl. intros ? H. inversion H. auto. + - intros tb H. simpl in H. apply bind_inversion in H. destruct H as (? & BI & TAIL). + apply bind_inversion in TAIL. destruct TAIL as (tb' & BODY' & CONS). inv CONS. + simpl. specialize (IHl tb' BODY'). rewrite IHl. reflexivity. +Qed. + +Lemma equal_exit_size bb: + length_opt (exit bb) = length (unfold_exit (exit bb)). +Proof. + destruct (exit bb); trivial. +Qed. + +Lemma bblock_size_preserved bb tb: + unfold_bblock bb = OK tb -> + size bb = list_length_z tb. +Proof. + unfold unfold_bblock. intros UNFOLD_BBLOCK. + destruct (zle (list_length_z (header bb)) 1). 2: { inversion UNFOLD_BBLOCK. } + apply bind_inversion in UNFOLD_BBLOCK. destruct UNFOLD_BBLOCK as (? & UNFOLD_BODY & CONS). + inversion CONS. + unfold size. + rewrite equal_header_size, equal_exit_size. + erewrite equal_body_size; eauto. + rewrite list_length_z_nat. + repeat (rewrite app_length). + rewrite plus_assoc. auto. +Qed. + +Lemma size_of_blocks_max_pos_aux: + forall bbs tbbs pos bb, + find_bblock pos bbs = Some bb -> + unfold bbs = OK tbbs -> + pos + size bb <= list_length_z tbbs. +Proof. + induction bbs as [| bb ? IHbbs]. + - intros tbbs ? ? FINDBB; inversion FINDBB. + - simpl; intros tbbs pos bb' FINDBB UNFOLD. + apply bind_inversion in UNFOLD; destruct UNFOLD as (tbb & UNFOLD_BBLOCK & H). + apply bind_inversion in H; destruct H as (tbbs' & UNFOLD & CONS). + inv CONS. + destruct (zlt pos 0). { discriminate FINDBB. } + destruct (zeq pos 0). + + inv FINDBB. + exploit bblock_size_preserved; eauto; intros SIZE; rewrite SIZE. + repeat (rewrite list_length_z_nat). rewrite app_length, Nat2Z.inj_add. + omega. + + generalize (IHbbs tbbs' (pos - size bb) bb' FINDBB UNFOLD). intros IH. + exploit bblock_size_preserved; eauto; intros SIZE. + repeat (rewrite list_length_z_nat); rewrite app_length. + rewrite Nat2Z.inj_add; repeat (rewrite <- list_length_z_nat). + omega. +Qed. + +Lemma size_of_blocks_max_pos pos f tf bi: + find_bblock pos (fn_blocks f) = Some bi -> + transf_function f = OK tf -> + pos + size bi <= max_pos tf. +Proof. + unfold transf_function, max_pos. + intros FINDBB UNFOLD. + apply bind_inversion in UNFOLD. destruct UNFOLD as (? & UNFOLD & H). + destruct (zlt Ptrofs.max_unsigned (list_length_z x)). { discriminate H. } + inv H. simpl. + eapply size_of_blocks_max_pos_aux; eauto. +Qed. + +Lemma unfold_bblock_not_nil bb: + unfold_bblock bb = OK nil -> False. +Proof. + intros. + exploit bblock_size_preserved; eauto. unfold list_length_z; simpl. intros SIZE. + generalize (bblock_size_pos bb). intros SIZE'. omega. +Qed. + +(* same proof as list_nth_z_range (Coqlib) *) +Lemma find_instr_range: + forall c n i, + Asm.find_instr n c = Some i -> 0 <= n < list_length_z c. +Proof. + induction c; simpl; intros. + discriminate. + rewrite list_length_z_cons. destruct (zeq n 0). + generalize (list_length_z_pos c); omega. + exploit IHc; eauto. omega. +Qed. + +Lemma find_instr_tail: + forall tbb pos c i, + Asm.find_instr pos c = Some i -> + Asm.find_instr (pos + list_length_z tbb) (tbb ++ c) = Some i. +Proof. + induction tbb as [| ? ? IHtbb]. + - intros. unfold list_length_z; simpl. rewrite Z.add_0_r. assumption. + - intros. rewrite list_length_z_cons. simpl. + destruct (zeq (pos + (list_length_z tbb + 1)) 0). + + exploit find_instr_range; eauto. intros POS_RANGE. + generalize (list_length_z_pos tbb). omega. + + replace (pos + (list_length_z tbb + 1) - 1) with (pos + list_length_z tbb) by omega. + eapply IHtbb; eauto. +Qed. + +Lemma size_of_blocks_bounds fb pos f bi: + Genv.find_funct_ptr ge fb = Some (Internal f) -> + find_bblock pos (fn_blocks f) = Some bi -> + pos + size bi <= Ptrofs.max_unsigned. +Proof. + intros; exploit internal_functions_translated; eauto. + intros (tf & _ & TRANSf). + assert (pos + size bi <= max_pos tf). { eapply size_of_blocks_max_pos; eauto. } + assert (max_pos tf <= Ptrofs.max_unsigned). { eapply functions_bound_max_pos; eauto. } + omega. +Qed. + +Lemma find_instr_bblock_tail: + forall tbb bb pos c i, + Asm.find_instr pos c = Some i -> + unfold_bblock bb = OK tbb -> + Asm.find_instr (pos + size bb ) (tbb ++ c) = Some i. +Proof. + induction tbb. + - intros. exploit unfold_bblock_not_nil; eauto. intros. contradiction. + - intros. simpl. + destruct (zeq (pos + size bb) 0). + + (* absurd *) + exploit find_instr_range; eauto. intros POS_RANGE. + generalize (bblock_size_pos bb). intros SIZE. omega. + + erewrite bblock_size_preserved; eauto. + rewrite list_length_z_cons. + replace (pos + (list_length_z tbb + 1) - 1) with (pos + list_length_z tbb) by omega. + apply find_instr_tail; auto. +Qed. + +Lemma list_nth_z_find_label: + forall (ll : list label) il n l, + list_nth_z ll n = Some l -> + Asm.find_instr n ((unfold_label ll) ++ il) = Some (Asm.Plabel l). +Proof. + induction ll. + - intros. inversion H. + - intros. simpl. + destruct (zeq n 0) as [Z | NZ]. + + inversion H as (H'). rewrite Z in H'. simpl in H'. inv H'. reflexivity. + + simpl in H. destruct (zeq n 0). { contradiction. } + apply IHll; auto. +Qed. + +Lemma list_nth_z_find_bi: + forall lbi bi tlbi n bi' exit, + list_nth_z lbi n = Some bi -> + unfold_body lbi = OK tlbi -> + basic_to_instruction bi = OK bi' -> + Asm.find_instr n (tlbi ++ exit) = Some bi'. +Proof. + induction lbi. + - intros. inversion H. + - simpl. intros. + apply bind_inversion in H0. destruct H0 as (? & ? & ?). + apply bind_inversion in H2. destruct H2 as (? & ? & ?). + destruct (zeq n 0) as [Z | NZ]. + + destruct n. + * inversion H as (BI). rewrite BI in *. + inversion H3. simpl. congruence. + * (* absurd *) congruence. + * (* absurd *) congruence. + + inv H3. simpl. destruct (zeq n 0). { contradiction. } + eapply IHlbi; eauto. +Qed. + +Lemma list_nth_z_find_bi_with_header: + forall ll lbi bi tlbi n bi' (rest : list Asm.instruction), + list_nth_z lbi (n - list_length_z ll) = Some bi -> + unfold_body lbi = OK tlbi -> + basic_to_instruction bi = OK bi' -> + Asm.find_instr n ((unfold_label ll) ++ (tlbi) ++ (rest)) = Some bi'. +Proof. + induction ll. + - unfold list_length_z. simpl. intros. + replace (n - 0) with n in H by omega. eapply list_nth_z_find_bi; eauto. + - intros. simpl. destruct (zeq n 0). + + rewrite list_length_z_cons in H. rewrite e in H. + replace (0 - (list_length_z ll + 1)) with (-1 - (list_length_z ll)) in H by omega. + generalize (list_length_z_pos ll). intros. + rewrite list_nth_z_neg in H; try omega. inversion H. + + rewrite list_length_z_cons in H. + replace (n - (list_length_z ll + 1)) with (n -1 - (list_length_z ll)) in H by omega. + eapply IHll; eauto. +Qed. + +(* XXX unused *) +Lemma range_list_nth_z: + forall (A: Type) (l: list A) n, + 0 <= n < list_length_z l -> + exists x, list_nth_z l n = Some x. +Proof. + induction l. + - intros. unfold list_length_z in H. simpl in H. omega. + - intros n. destruct (zeq n 0). + + intros. simpl. destruct (zeq n 0). { eauto. } contradiction. + + intros H. rewrite list_length_z_cons in H. + simpl. destruct (zeq n 0). { contradiction. } + replace (Z.pred n) with (n - 1) by omega. + eapply IHl; omega. +Qed. + +Lemma list_nth_z_n_too_big: + forall (A: Type) (l: list A) n, + 0 <= n -> + list_nth_z l n = None -> + n >= list_length_z l. +Proof. + induction l. + - intros. unfold list_length_z. simpl. omega. + - intros. rewrite list_length_z_cons. + simpl in H0. + destruct (zeq n 0) as [N | N]. + + inversion H0. + + (* XXX there must be a more elegant way to prove this simple fact *) + assert (n > 0). { omega. } + assert (0 <= n - 1). { omega. } + generalize (IHl (n - 1)). intros IH. + assert (n - 1 >= list_length_z l). { auto. } + assert (n > list_length_z l); omega. +Qed. + +Lemma find_instr_past_header: + forall labels n rest, + list_nth_z labels n = None -> + Asm.find_instr n (unfold_label labels ++ rest) = + Asm.find_instr (n - list_length_z labels) rest. +Proof. + induction labels as [| label labels' IH]. + - unfold list_length_z; simpl; intros; rewrite Z.sub_0_r; reflexivity. + - intros. simpl. destruct (zeq n 0) as [N | N]. + + rewrite N in H. inversion H. + + rewrite list_length_z_cons. + replace (n - (list_length_z labels' + 1)) with (n - 1 - list_length_z labels') by omega. + simpl in H. destruct (zeq n 0). { contradiction. } + replace (Z.pred n) with (n - 1) in H by omega. + apply IH; auto. +Qed. + +(* very similar to find_instr_past_header *) +Lemma find_instr_past_body: + forall lbi n tlbi rest, + list_nth_z lbi n = None -> + unfold_body lbi = OK tlbi -> + Asm.find_instr n (tlbi ++ rest) = + Asm.find_instr (n - list_length_z lbi) rest. +Proof. + induction lbi. + - unfold list_length_z; simpl; intros ? ? ? ? H. inv H; rewrite Z.sub_0_r; reflexivity. + - intros n tlib ? NTH UNFOLD_BODY. + unfold unfold_body in UNFOLD_BODY. apply bind_inversion in UNFOLD_BODY. + destruct UNFOLD_BODY as (? & BI & H). + apply bind_inversion in H. destruct H as (? & UNFOLD_BODY' & CONS). + fold unfold_body in UNFOLD_BODY'. inv CONS. + simpl; destruct (zeq n 0) as [N|N]. + + rewrite N in NTH; inversion NTH. + + rewrite list_length_z_cons. + replace (n - (list_length_z lbi + 1)) with (n - 1 - list_length_z lbi) by omega. + simpl in NTH. destruct (zeq n 0). { contradiction. } + replace (Z.pred n) with (n - 1) in NTH by omega. + apply IHlbi; auto. +Qed. + +Lemma n_beyond_body: + forall bb n, + 0 <= n < size bb -> + list_nth_z (header bb) n = None -> + list_nth_z (body bb) (n - list_length_z (header bb)) = None -> + n >= Z.of_nat (length (header bb) + length (body bb)). +Proof. + intros. + assert (0 <= n). { omega. } + generalize (list_nth_z_n_too_big label (header bb) n H2 H0). intros. + generalize (list_nth_z_n_too_big _ (body bb) (n - list_length_z (header bb))). intros. + unfold size in H. + + assert (0 <= n - list_length_z (header bb)). { omega. } + assert (n - list_length_z (header bb) >= list_length_z (body bb)). { apply H4; auto. } + + assert (n >= list_length_z (header bb) + list_length_z (body bb)). { omega. } + rewrite Nat2Z.inj_add. + repeat (rewrite <- list_length_z_nat). assumption. +Qed. + +Lemma exec_arith_instr_dont_move_PC ai rs rs': forall + (BASIC: exec_arith_instr lk ai rs = rs'), + rs PC = rs' PC. +Proof. + destruct ai; simpl; intros; + try (rewrite <- BASIC; rewrite Pregmap.gso; auto; discriminate). + - destruct i; simpl in BASIC. + + unfold compare_long in BASIC; rewrite <- BASIC. + repeat rewrite Pregmap.gso; try discriminate. reflexivity. + + unfold compare_long in BASIC; rewrite <- BASIC. + repeat rewrite Pregmap.gso; try discriminate. reflexivity. + + destruct sz; + try (unfold compare_single in BASIC || unfold compare_float in BASIC); + destruct (rs r1), (rs r2); + try (rewrite <- BASIC; repeat rewrite Pregmap.gso; try (discriminate || reflexivity)). + - destruct i; simpl in BASIC; destruct is; + try (unfold compare_int in BASIC || unfold compare_long in BASIC); + try (rewrite <- BASIC; repeat rewrite Pregmap.gso; try (discriminate || reflexivity)). + - destruct i; simpl in BASIC; destruct sz; + try (unfold compare_single in BASIC || unfold compare_float in BASIC); + destruct (rs r1); + try (rewrite <- BASIC; repeat rewrite Pregmap.gso; try (discriminate || reflexivity)). + - destruct fsz; rewrite <- BASIC; rewrite Pregmap.gso; try (discriminate || reflexivity). + - destruct fsz; rewrite <- BASIC; rewrite Pregmap.gso; try (discriminate || reflexivity). +Qed. + +Lemma exec_basic_dont_move_PC bi rs m rs' m': forall + (BASIC: exec_basic lk ge bi rs m = Next rs' m'), + rs PC = rs' PC. +Proof. + destruct bi; simpl; intros. + - inv BASIC. exploit exec_arith_instr_dont_move_PC; eauto. + - unfold exec_load in BASIC. + destruct Mem.loadv. 2: { discriminate BASIC. } + inv BASIC. rewrite Pregmap.gso; try discriminate; auto. + - unfold exec_store in BASIC. + destruct Mem.storev. 2: { discriminate BASIC. } + inv BASIC; reflexivity. + - destruct Mem.alloc, Mem.store. 2: { discriminate BASIC. } + inv BASIC. repeat (rewrite Pregmap.gso; try discriminate). reflexivity. + - destruct Mem.loadv. 2: { discriminate BASIC. } + destruct rs, Mem.free; try discriminate BASIC. + inv BASIC; rewrite Pregmap.gso; try discriminate; auto. + - inv BASIC; rewrite Pregmap.gso; try discriminate; auto. + - inv BASIC; rewrite Pregmap.gso; try discriminate; auto. + - inv BASIC; rewrite Pregmap.gso; try discriminate; auto. + - inv BASIC; rewrite Pregmap.gso; try discriminate; auto. +Qed. + +Lemma exec_body_dont_move_PC_aux: + forall bis rs m rs' m' + (BODY: exec_body lk ge bis rs m = Next rs' m'), + rs PC = rs' PC. +Proof. + induction bis. + - intros; inv BODY; reflexivity. + - simpl; intros. + remember (exec_basic lk ge a rs m) as bi eqn:BI; destruct bi. 2: { discriminate BODY. } + symmetry in BI; destruct s in BODY, BI; simpl in BODY, BI. + exploit exec_basic_dont_move_PC; eauto; intros AGPC; rewrite AGPC. + eapply IHbis; eauto. +Qed. + +Lemma exec_body_dont_move_PC bb rs m rs' m': forall + (BODY: exec_body lk ge (body bb) rs m = Next rs' m'), + rs PC = rs' PC. +Proof. apply exec_body_dont_move_PC_aux. Qed. + +Lemma find_instr_bblock: + forall n lb pos bb tlb + (FINDBB: find_bblock pos lb = Some bb) + (UNFOLD: unfold lb = OK tlb) + (SIZE: 0 <= n < size bb), + exists i, is_nth_inst bb n i /\ Asm.find_instr (pos+n) tlb = Some i. +Proof. + induction lb as [| b lb IHlb]. + - intros. inversion FINDBB. + - intros pos bb tlb FINDBB UNFOLD SIZE. + destruct pos. + + inv FINDBB. simpl. + exploit unfold_car_cdr; eauto. intros (tbb & tlb' & UNFOLD_BBLOCK & UNFOLD' & UNFOLD_cons). + rewrite UNFOLD in UNFOLD_cons. inversion UNFOLD_cons. + unfold unfold_bblock in UNFOLD_BBLOCK. + destruct (zle (list_length_z (header bb)) 1). 2: { inversion UNFOLD_BBLOCK. } + apply bind_inversion in UNFOLD_BBLOCK. + destruct UNFOLD_BBLOCK as (? & UNFOLD_BODY & H). + inversion H as (UNFOLD_BBLOCK). + remember (list_nth_z (header bb) n) as label_opt eqn:LBL. destruct label_opt. + * (* nth instruction is a label *) + eexists; split. { eapply is_nth_label; eauto. } + inversion UNFOLD_cons. + symmetry in LBL. + rewrite <- app_assoc. + apply list_nth_z_find_label; auto. + * remember (list_nth_z (body bb) (n - list_length_z (header bb))) as bi_opt eqn:BI. + destruct bi_opt. + -- (* nth instruction is a basic instruction *) + exploit list_nth_z_in; eauto. intros INBB. + exploit entire_body_translated; eauto. intros BI'. + destruct BI'. + eexists; split. + ++ eapply is_nth_basic; eauto. + ++ repeat (rewrite <- app_assoc). eapply list_nth_z_find_bi_with_header; eauto. + -- (* nth instruction is the exit instruction *) + generalize n_beyond_body. intros TEMP. + assert (n >= Z.of_nat (Datatypes.length (header bb) + + Datatypes.length (body bb))) as NGE. { auto. } clear TEMP. + remember (exit bb) as exit_opt eqn:EXIT. destruct exit_opt. + ++ rewrite <- app_assoc. rewrite find_instr_past_header; auto. + rewrite <- app_assoc. erewrite find_instr_past_body; eauto. + assert (SIZE' := SIZE). + unfold size in SIZE. rewrite <- EXIT in SIZE. simpl in SIZE. + destruct SIZE as (LOWER & UPPER). + repeat (rewrite Nat2Z.inj_add in UPPER). + repeat (rewrite <- list_length_z_nat in UPPER). repeat (rewrite Nat2Z.inj_add in NGE). + repeat (rewrite <- list_length_z_nat in NGE). simpl in UPPER. + assert (n = list_length_z (header bb) + list_length_z (body bb)). { omega. } + assert (n = size bb - 1). { + unfold size. rewrite <- EXIT. simpl. + repeat (rewrite Nat2Z.inj_add). repeat (rewrite <- list_length_z_nat). simpl. omega. + } + symmetry in EXIT. + eexists; split. + ** eapply is_nth_ctlflow; eauto. + ** simpl. + destruct (zeq (n - list_length_z (header bb) - list_length_z (body bb)) 0). { reflexivity. } + (* absurd *) omega. + ++ (* absurd *) + unfold size in SIZE. rewrite <- EXIT in SIZE. simpl in SIZE. + destruct SIZE as (? & SIZE'). rewrite Nat.add_0_r in SIZE'. omega. + + unfold find_bblock in FINDBB; simpl in FINDBB; fold find_bblock in FINDBB. + inversion UNFOLD as (UNFOLD'). + apply bind_inversion in UNFOLD'. destruct UNFOLD' as (? & (UNFOLD_BBLOCK' & UNFOLD')). + apply bind_inversion in UNFOLD'. destruct UNFOLD' as (? & (UNFOLD' & TLB)). + inversion TLB. + generalize (IHlb _ _ _ FINDBB UNFOLD'). intros IH. + destruct IH as (? & (IH_is_nth & IH_find_instr)); eauto. + eexists; split. + * apply IH_is_nth. + * replace (Z.pos p + n) with (Z.pos p + n - size b + size b) by omega. + eapply find_instr_bblock_tail; try assumption. + replace (Z.pos p + n - size b) with (Z.pos p - size b + n) by omega. + apply IH_find_instr. + + (* absurd *) + generalize (Pos2Z.neg_is_neg p). intros. exploit (find_bblock_neg (b :: lb)); eauto. + rewrite FINDBB. intros CONTRA. inversion CONTRA. +Qed. + +Lemma exec_header_simulation b ofs f bb rs m: forall + (ATPC: rs PC = Vptr b ofs) + (FINDF: Genv.find_funct_ptr ge b = Some (Internal f)) + (FINDBB: find_bblock (Ptrofs.unsigned ofs) (fn_blocks f) = Some bb), + exists s', star Asm.step tge (State rs m) E0 s' + /\ match_internal (list_length_z (header bb)) (State rs m) s'. +Proof. + intros. + exploit internal_functions_unfold; eauto. + intros (tc & FINDtf & TRANStf & _). + assert (BNDhead: list_length_z (header bb) <= 1). { eapply size_header; eauto. } + destruct (header bb) as [|l[|]] eqn: EQhead. + + (* header nil *) + eexists; split. + - eapply star_refl. + - split; eauto. + unfold list_length_z; rewrite !ATPC; simpl. + rewrite Ptrofs.add_zero; auto. + + (* header one *) + assert (Lhead: list_length_z (header bb) = 1). { rewrite EQhead; unfold list_length_z; simpl. auto. } + exploit (find_instr_bblock 0); eauto. + { generalize (bblock_size_pos bb). omega. } + intros (i & NTH & FIND_INSTR). + inv NTH. + * rewrite EQhead in H; simpl in H. inv H. + cutrewrite (Ptrofs.unsigned ofs + 0 = Ptrofs.unsigned ofs) in FIND_INSTR; try omega. + eexists. split. + - eapply star_one. + eapply Asm.exec_step_internal; eauto. + simpl; eauto. + - unfold list_length_z; simpl. split; eauto. + intros r; destruct r; simpl; congruence || auto. + * (* absurd case *) + erewrite list_nth_z_neg in * |-; [ congruence | rewrite Lhead; omega]. + * (* absurd case *) + rewrite bblock_size_aux, Lhead in *. generalize (bblock_size_aux_pos bb). omega. + + (* absurd case *) + unfold list_length_z in BNDhead. simpl in *. + generalize (list_length_z_aux_increase _ l1 2); omega. +Qed. + +Lemma eval_addressing_preserved a rs1 rs2: + (forall r : preg, r <> PC -> rs1 r = rs2 r) -> + eval_addressing lk a rs1 = Asm.eval_addressing tge a rs2. +Proof. + intros EQ. + destruct a; simpl; try (rewrite !EQ; congruence). auto. +Qed. + +Ltac next_stuck_cong := try (unfold Next, Stuck in *; congruence). + +Ltac inv_ok_eq := + repeat match goal with + | [EQ: OK ?x = OK ?y |- _ ] + => inversion EQ; clear EQ; subst + end. + +Ltac reg_rwrt := + match goal with + | [e: DR _ = DR _ |- _ ] + => rewrite e in * + end. + +Ltac destruct_reg_inv := + repeat match goal with + | [ H : match ?reg with _ => _ end = _ |- _ ] + => simpl in *; destruct reg; try congruence; try inv_ok_eq; try reg_rwrt + end. + +Ltac destruct_ireg_inv := + repeat match goal with + | [ H : match ?reg with _ => _ end = _ |- _ ] + => destruct reg as [[r|]|]; try congruence; try inv_ok_eq; subst + end. + +Ltac destruct_reg_size := + simpl in *; + match goal with + | [ |- context [ match ?reg with _ => _ end ] ] + => destruct reg; try congruence + end. + +Ltac find_rwrt_ag := + simpl in *; + match goal with + | [ AG: forall r, r <> ?PC -> _ r = _ r |- _ ] + => repeat rewrite <- AG; try congruence + end. + +Ltac inv_matchi := + match goal with + | [ MATCHI : match_internal _ _ _ |- _ ] + => inversion MATCHI; subst; find_rwrt_ag + end. + +Ltac destruct_ir0_reg := + match goal with + | [ |- context [ ir0 _ _ ?r ] ] + => unfold ir0 in *; destruct r; find_rwrt_ag; eauto + end. + +Ltac pc_not_sp := + match goal with + | [ |- ?PC <> ?SP ] + => destruct (PregEq.eq SP PC); repeat congruence; discriminate + end. + +Ltac update_x_access_x := + subst; rewrite !Pregmap.gss; auto. + +Ltac update_x_access_r := + rewrite !Pregmap.gso; auto. + +Lemma nextinstr_agree_but_pc rs1 rs2: forall + (AG: forall r, r <> PC -> rs1 r = rs2 r), + forall r, r <> PC -> rs1 r = Asm.nextinstr rs2 r. +Proof. + intros; unfold Asm.nextinstr in *; rewrite Pregmap.gso in *; eauto. +Qed. + +Lemma ptrofs_nextinstr_agree rs1 rs2 n: forall + (BOUNDED : 0 <= n <= Ptrofs.max_unsigned) + (AGPC : Val.offset_ptr (rs1 PC) (Ptrofs.repr n) = rs2 PC), + Val.offset_ptr (rs1 PC) (Ptrofs.repr (n + 1)) = Asm.nextinstr rs2 PC. +Proof. + intros; unfold Asm.nextinstr; rewrite Pregmap.gss. + rewrite <- Ptrofs.unsigned_one; rewrite <- (Ptrofs.unsigned_repr n); eauto; + rewrite <- Ptrofs.add_unsigned; rewrite <- Val.offset_ptr_assoc; rewrite AGPC; eauto. +Qed. + +Lemma load_preserved n rs1 m1 rs1' m1' rs2 m2 rd chk f a: forall + (BOUNDED: 0 <= n <= Ptrofs.max_unsigned) + (MATCHI: match_internal n (State rs1 m1) (State rs2 m2)) + (HLOAD: exec_load lk chk f a rd rs1 m1 = Next rs1' m1'), + exists (rs2' : regset) (m2' : mem), Asm.exec_load tge chk f a rd rs2 m2 = Next rs2' m2' + /\ match_internal (n + 1) (State rs1' m1') (State rs2' m2'). +Proof. + intros. + unfold exec_load, Asm.exec_load in *. + inversion MATCHI as [n0 r1 mx1 r2 mx2 EQM EQR EQPC]; subst. + rewrite <- (eval_addressing_preserved a rs1 rs2); auto. + destruct (Mem.loadv _ _ _). + + inversion HLOAD; auto. repeat (econstructor; eauto). + * eapply nextinstr_agree_but_pc; intros. + destruct (PregEq.eq r rd); try update_x_access_x; try update_x_access_r. + * eapply ptrofs_nextinstr_agree; eauto. + + next_stuck_cong. +Qed. + +Lemma store_preserved n rs1 m1 rs1' m1' rs2 m2 rd chk a: forall + (BOUNDED: 0 <= n <= Ptrofs.max_unsigned) + (MATCHI: match_internal n (State rs1 m1) (State rs2 m2)) + (HSTORE: exec_store lk chk a rd rs1 m1 = Next rs1' m1'), + exists (rs2' : regset) (m2' : mem), Asm.exec_store tge chk a rd rs2 m2 = Next rs2' m2' + /\ match_internal (n + 1) (State rs1' m1') (State rs2' m2'). +Proof. + intros. + unfold exec_store, Asm.exec_store in *. + inversion MATCHI as [n0 r1 mx1 r2 mx2 EQM EQR EQPC]; subst. + rewrite <- (eval_addressing_preserved a rs1 rs2); auto. + destruct (Mem.storev _ _ _ _). + + inversion HSTORE; auto. repeat (econstructor; eauto). + * eapply nextinstr_agree_but_pc; intros. + subst. apply EQR. auto. + * eapply ptrofs_nextinstr_agree; subst; eauto. + + next_stuck_cong. +Qed. + +Lemma next_inst_preserved n rs1 m1 rs1' m1' rs2 m2 (x: dreg) v: forall + (BOUNDED: 0 <= n <= Ptrofs.max_unsigned) + (MATCHI: match_internal n (State rs1 m1) (State rs2 m2)) + (NEXTI: Next rs1 # x <- v m1 = Next rs1' m1'), + exists (rs2' : regset) (m2' : mem), + Next (Asm.nextinstr rs2 # x <- v) m2 = Next rs2' m2' + /\ match_internal (n + 1) (State rs1' m1') (State rs2' m2'). +Proof. + intros. + inversion MATCHI as [n0 r1 mx1 r2 mx2 EQM EQR EQPC]; subst. + inversion NEXTI. repeat (econstructor; eauto). + * eapply nextinstr_agree_but_pc; intros. + destruct (PregEq.eq r x); try update_x_access_x; try update_x_access_r. + * eapply ptrofs_nextinstr_agree; eauto. +Qed. + +Lemma match_internal_nextinstr_switch: + forall n s rs2 m2 r v, + r <> PC -> + match_internal n s (State ((Asm.nextinstr rs2)#r <- v) m2) -> + match_internal n s (State (Asm.nextinstr (rs2#r <- v)) m2). +Proof. + unfold Asm.nextinstr; intros n s rs2 m2 r v NOTPC1 MI. + inversion MI; subst; constructor; auto. + - eapply nextinstr_agree_but_pc; intros. + rewrite AG; try congruence. + destruct (PregEq.eq r r0); try update_x_access_x; try update_x_access_r. + - rewrite !Pregmap.gss, !Pregmap.gso; try congruence. + rewrite AGPC. + rewrite Pregmap.gso, Pregmap.gss; try congruence. +Qed. + +Lemma match_internal_nextinstr_set_parallel: + forall n rs1 m1 rs2 m2 r v1 v2, + r <> PC -> + match_internal n (State rs1 m1) (State (Asm.nextinstr rs2) m2) -> + v1 = v2 -> + match_internal n (State (rs1#r <- v1) m1) (State (Asm.nextinstr (rs2#r <- v2)) m2). +Proof. + intros; subst; eapply match_internal_nextinstr_switch; eauto. + intros; eapply match_internal_set_parallel; eauto. +Qed. + +Lemma exec_basic_simulation: + forall tf n rs1 m1 rs1' m1' rs2 m2 bi tbi + (BOUNDED: 0 <= n <= Ptrofs.max_unsigned) + (BASIC: exec_basic lk ge bi rs1 m1 = Next rs1' m1') + (MATCHI: match_internal n (State rs1 m1) (State rs2 m2)) + (TRANSBI: basic_to_instruction bi = OK tbi), + exists rs2' m2', Asm.exec_instr tge tf tbi + rs2 m2 = Next rs2' m2' + /\ match_internal (n + 1) (State rs1' m1') (State rs2' m2'). +Proof. + intros. + destruct bi. + { (* PArith *) + simpl in *; destruct i. + 1,2,3,4,5,6: (* PArithP, PArithPP, PArithPPP, PArithRR0R, PArithRR0, PArithARRRR0 *) + destruct i; + try (destruct sumbool_rec; try congruence); + try (monadInv TRANSBI); + try (destruct_reg_inv); + try (inv_matchi); + try (exploit next_inst_preserved; eauto); + try (repeat destruct_reg_size); + try (destruct_ir0_reg). + { (* PArithComparisonPP *) + destruct i; + try (monadInv TRANSBI); + try (inv_matchi); + try (destruct_reg_inv); + simpl in *. + 1,2: (* compare_long *) + inversion BASIC; clear BASIC; subst; + eexists; eexists; split; eauto; + unfold compare_long; + repeat (eapply match_internal_nextinstr_set_parallel; [ congruence | idtac | try (rewrite !AG; congruence)]); + try (econstructor; eauto); + try (eapply nextinstr_agree_but_pc; eauto); + try (eapply ptrofs_nextinstr_agree; eauto). + + destruct sz. + - (* compare_single *) + unfold compare_single in BASIC. + destruct (rs1 x), (rs1 x0); + inversion BASIC; + eexists; eexists; split; eauto; + repeat (eapply match_internal_nextinstr_set_parallel; [ congruence | idtac | try (rewrite !AG; congruence)]); + try (econstructor; eauto); + try (eapply nextinstr_agree_but_pc; eauto); + try (eapply ptrofs_nextinstr_agree; eauto). + - (* compare_float *) + unfold compare_float in BASIC. + destruct (rs1 x), (rs1 x0); + inversion BASIC; + eexists; eexists; split; eauto; + repeat (eapply match_internal_nextinstr_set_parallel; [ congruence | idtac | try (rewrite !AG; congruence)]); + try (econstructor; eauto); + try (eapply nextinstr_agree_but_pc; eauto); + try (eapply ptrofs_nextinstr_agree; eauto). } + 1,2: (* PArithComparisonR0R, PArithComparisonP *) + destruct i; + try (monadInv TRANSBI); + try (inv_matchi); + try (destruct_reg_inv); + try (destruct_reg_size); + simpl in *; + inversion BASIC; clear BASIC; subst; + eexists; eexists; split; eauto; + unfold compare_long, compare_int, compare_float, compare_single; + try (destruct_reg_size); + repeat (eapply match_internal_nextinstr_set_parallel; [ congruence | idtac | try (rewrite !AG; congruence)]); + try (econstructor; eauto); + try (destruct_ir0_reg); + try (eapply nextinstr_agree_but_pc; eauto); + try (eapply ptrofs_nextinstr_agree; eauto). + { (* Pcset *) + try (monadInv TRANSBI); + try (inv_matchi). + try (exploit next_inst_preserved; eauto); + try (simpl in *; intros; + unfold if_opt_bool_val in *; unfold eval_testcond in *; + rewrite <- !AG; try congruence; eauto). } + { (* Pfmovi *) + try (monadInv TRANSBI); + try (inv_matchi); + try (destruct_reg_size); + try (destruct_ir0_reg); + try (exploit next_inst_preserved; eauto). } + { (* Pcsel *) + try (destruct_reg_inv); + try (monadInv TRANSBI); + try (destruct_reg_inv); + try (inv_matchi); + try (exploit next_inst_preserved; eauto); + simpl in *; intros; + unfold if_opt_bool_val in *; unfold eval_testcond in *; + rewrite <- !AG; try congruence; eauto. } + { (* Pfnmul *) + try (monadInv TRANSBI); + try (inv_matchi); + try (destruct_reg_size); + try (exploit next_inst_preserved; eauto); + try (find_rwrt_ag). } } + { (* PLoad *) + destruct ld; monadInv TRANSBI; try destruct_ireg_inv; exploit load_preserved; eauto; + intros; simpl in *; destruct sz; eauto. } + { (* PStore *) + destruct st; monadInv TRANSBI; try destruct_ireg_inv; exploit store_preserved; eauto; + simpl in *; inv_matchi; find_rwrt_ag. } + { (* Pallocframe *) + monadInv TRANSBI; + inv_matchi; try pc_not_sp; + destruct sz eqn:EQSZ; + destruct Mem.alloc eqn:EQALLOC; + destruct Mem.store eqn:EQSTORE; inversion BASIC; try pc_not_sp; + eexists; eexists; split; eauto; + repeat (eapply match_internal_nextinstr_set_parallel; [ try (pc_not_sp; congruence) | idtac | try (reflexivity)]); + try (econstructor; eauto); + try (eapply nextinstr_agree_but_pc; eauto); + try (eapply ptrofs_nextinstr_agree; eauto). } + { (* Pfreeframe *) + monadInv TRANSBI; + inv_matchi; try pc_not_sp; + destruct sz eqn:EQSZ; + destruct Mem.loadv eqn:EQLOAD; + destruct (rs1 SP) eqn:EQRS1SP; + try (destruct Mem.free eqn:EQFREE); + inversion BASIC; try pc_not_sp; + eexists; eexists; split; eauto; + repeat (eapply match_internal_nextinstr_set_parallel; [ try (pc_not_sp; congruence) | idtac | try (reflexivity)]); + try (econstructor; eauto); + try (eapply nextinstr_agree_but_pc; eauto); + try (eapply ptrofs_nextinstr_agree; eauto). } + 1,2,3,4: (* Ploadsymbol, Pcvtsw2x, Pcvtuw2x, Pcvtx2w *) + try (monadInv TRANSBI); + try (inv_matchi); + try (exploit next_inst_preserved; eauto); + rewrite symbol_addresses_preserved; eauto; + try (find_rwrt_ag). +Qed. + +Lemma find_basic_instructions b ofs f bb tc: forall + (FINDF: Genv.find_funct_ptr ge b = Some (Internal f)) + (FINDBB: find_bblock (Ptrofs.unsigned ofs) (fn_blocks f) = Some bb) + (UNFOLD: unfold (fn_blocks f) = OK tc), + forall n, + (n < length (body bb))%nat -> + exists (i : Asm.instruction) (bi : basic), + list_nth_z (body bb) (Z.of_nat n) = Some bi + /\ basic_to_instruction bi = OK i + /\ Asm.find_instr (Ptrofs.unsigned ofs + + (list_length_z (header bb)) + + Z.of_nat n) tc + = Some i. +Proof. + intros until n; intros NLT. + exploit internal_functions_unfold; eauto. + intros (tc' & FINDtf & TRANStf & _). + assert (tc' = tc) by congruence; subst. + exploit (find_instr_bblock (list_length_z (header bb) + Z.of_nat n)); eauto. + { unfold size; split. + - rewrite list_length_z_nat; omega. + - repeat (rewrite list_length_z_nat). repeat (rewrite Nat2Z.inj_add). omega. } + intros (i & NTH & FIND_INSTR). + exists i; intros. + inv NTH. + - (* absurd *) apply list_nth_z_range in H; omega. + - exists bi; + rewrite Z.add_simpl_l in H; + rewrite Z.add_assoc in FIND_INSTR; + intuition. + - (* absurd *) rewrite bblock_size_aux in H0; + rewrite H in H0; simpl in H0; repeat rewrite list_length_z_nat in H0; omega. +Qed. + +(** "is_tail" auxiliary lemma about is_tail to move in IterList ou Coqlib (déplacer aussi Machblockgenproof.is_tail_app_inv) ? *) + +Lemma is_tail_app_right A (l2 l1: list A): is_tail l1 (l2++l1). +Proof. + intros; eapply Machblockgenproof.is_tail_app_inv; econstructor. +Qed. + +Lemma is_tail_app_def A (l1 l2: list A): + is_tail l1 l2 -> exists l3, l2 = l3 ++ l1. +Proof. + induction 1 as [|x l1 l2]; simpl. + - exists nil; simpl; auto. + - destruct IHis_tail as (l3 & EQ); rewrite EQ. + exists (x::l3); simpl; auto. +Qed. + +Lemma is_tail_bound A (l1 l2: list A): + is_tail l1 l2 -> (length l1 <= length l2)%nat. +Proof. + intros H; destruct (is_tail_app_def _ _ _ H) as (l3 & EQ). + subst; rewrite app_length. + omega. +Qed. + +Lemma is_tail_list_nth_z A (l1 l2: list A): + is_tail l1 l2 -> list_nth_z l2 ((list_length_z l2) - (list_length_z l1)) = list_nth_z l1 0. +Proof. + induction 1; simpl. + - replace (list_length_z c - list_length_z c) with 0; omega || auto. + - assert (X: list_length_z (i :: c2) > list_length_z c1). + { rewrite !list_length_z_nat, <- Nat2Z.inj_gt. + exploit is_tail_bound; simpl; eauto. + omega. } + destruct (zeq (list_length_z (i :: c2) - list_length_z c1) 0) as [Y|Y]; try omega. + replace (Z.pred (list_length_z (i :: c2) - list_length_z c1)) with (list_length_z c2 - list_length_z c1); auto. + rewrite list_length_z_cons. + omega. +Qed. + +(* TODO: remplacer find_basic_instructions directement par ce lemme ? *) +Lemma find_basic_instructions_alt b ofs f bb tc n: forall + (FINDF: Genv.find_funct_ptr ge b = Some (Internal f)) + (FINDBB: find_bblock (Ptrofs.unsigned ofs) (fn_blocks f) = Some bb) + (UNFOLD: unfold (fn_blocks f) = OK tc) + (BOUND: 0 <= n < list_length_z (body bb)), + exists (i : Asm.instruction) (bi : basic), + list_nth_z (body bb) n = Some bi + /\ basic_to_instruction bi = OK i + /\ Asm.find_instr (Ptrofs.unsigned ofs + + (list_length_z (header bb)) + + n) tc + = Some i. +Proof. + intros; assert ((Z.to_nat n) < length (body bb))%nat. + { rewrite Nat2Z.inj_lt, <- list_length_z_nat, Z2Nat.id; try omega. } + exploit find_basic_instructions; eauto. + rewrite Z2Nat.id; try omega. intros (i & bi & X). + eexists; eexists; intuition eauto. +Qed. + +Lemma header_body_tail_bound: forall (a: basic) (li: list basic) bb ofs + (BOUNDBB : Ptrofs.unsigned ofs + size bb <= Ptrofs.max_unsigned) + (BDYLENPOS : 0 <= list_length_z (body bb) - list_length_z (a :: li) < + list_length_z (body bb)), +0 <= list_length_z (header bb) + list_length_z (body bb) - list_length_z (a :: li) <= +Ptrofs.max_unsigned. +Proof. + intros. + assert (HBBPOS: list_length_z (header bb) >= 0) by eapply list_length_z_pos. + assert (HBBSIZE: list_length_z (header bb) < size bb) by eapply header_size_lt_block_size. + assert (OFSBOUND: 0 <= Ptrofs.unsigned ofs <= Ptrofs.max_unsigned) by eapply Ptrofs.unsigned_range_2. + assert (BBSIZE: size bb <= Ptrofs.max_unsigned) by omega. + unfold size in BBSIZE. + rewrite !Nat2Z.inj_add in BBSIZE. + rewrite <- !list_length_z_nat in BBSIZE. + omega. +Qed. + +(* A more general version of the exec_body_simulation_plus lemma below. + This generalization is necessary for the induction proof inside the body. +*) +Lemma exec_body_simulation_plus_gen li: forall b ofs f bb rs m s2 rs' m' + (BLI: is_tail li (body bb)) + (ATPC: rs PC = Vptr b ofs) + (FINDF: Genv.find_funct_ptr ge b = Some (Internal f)) + (FINDBB: find_bblock (Ptrofs.unsigned ofs) (fn_blocks f) = Some bb) + (NEMPTY_BODY: li <> nil) + (MATCHI: match_internal ((list_length_z (header bb)) + (list_length_z (body bb)) - (list_length_z li)) (State rs m) s2) + (BODY: exec_body lk ge li rs m = Next rs' m'), + exists s2', plus Asm.step tge s2 E0 s2' + /\ match_internal (size bb - (Z.of_nat (length_opt (exit bb)))) (State rs' m') s2'. +Proof. + induction li as [|a li]; simpl; try congruence. + intros. + assert (BDYLENPOS: 0 <= (list_length_z (body bb) - list_length_z (a::li)) < list_length_z (body bb)). { + assert (Z.of_nat O < list_length_z (a::li) <= list_length_z (body bb)); try omega. + rewrite !list_length_z_nat; split. + - rewrite <- Nat2Z.inj_lt. simpl. omega. + - rewrite <- Nat2Z.inj_le; eapply is_tail_bound; eauto. + } + exploit internal_functions_unfold; eauto. + intros (tc & FINDtf & TRANStf & _). + exploit find_basic_instructions_alt; eauto. + intros (tbi & (bi & (NTHBI & TRANSBI & FIND_INSTR))). + exploit is_tail_list_nth_z; eauto. + rewrite NTHBI; simpl. + intros X; inversion X; subst; clear X NTHBI. + destruct (exec_basic _ _ _ _ _) eqn:EXEC_BASIC; next_stuck_cong. + destruct s as (rs1 & m1); simpl in *. + destruct s2 as (rs2 & m2); simpl in *. + assert (BOUNDBBMAX: Ptrofs.unsigned ofs + size bb <= Ptrofs.max_unsigned) + by (eapply size_of_blocks_bounds; eauto). + exploit header_body_tail_bound; eauto. intros BDYTAIL. + exploit exec_basic_simulation; eauto. + intros (rs_next' & m_next' & EXEC_INSTR & MI_NEXT). + exploit exec_basic_dont_move_PC; eauto. intros AGPC. + inversion MI_NEXT as [A B C D E M_NEXT_AGREE RS_NEXT_AGREE ATPC_NEXT PC_OFS_NEXT RS RS']. + subst A. subst B. subst C. subst D. subst E. + rewrite ATPC in AGPC. symmetry in AGPC, ATPC_NEXT. + + inv MATCHI. symmetry in AGPC0. + rewrite ATPC in AGPC0. + unfold Val.offset_ptr in AGPC0. + + simpl in FIND_INSTR. + (* Execute internal step. *) + exploit (Asm.exec_step_internal tge b); eauto. + { + rewrite Ptrofs.add_unsigned. + repeat (rewrite Ptrofs.unsigned_repr); try omega. + 2: { + assert (BOUNDOFS: 0 <= Ptrofs.unsigned ofs <= Ptrofs.max_unsigned) by eapply Ptrofs.unsigned_range_2. + assert (list_length_z (body bb) <= size bb) by eapply body_size_le_block_size. + assert (list_length_z (header bb) <= 1). { eapply size_header; eauto. } + omega. } + try rewrite list_length_z_nat; try split; + simpl; rewrite <- !list_length_z_nat; + replace (Ptrofs.unsigned ofs + (list_length_z (header bb) + list_length_z (body bb) - + list_length_z (a :: li))) with (Ptrofs.unsigned ofs + list_length_z (header bb) + + (list_length_z (body bb) - list_length_z (a :: li))) by omega; + try assumption; try omega. } + + (* This is our STEP hypothesis. *) + intros STEP_NEXT. + destruct li as [|a' li]; simpl in *. + - (* case of a single instruction in li: this our base case in the induction *) + inversion BODY; subst. + eexists; split. + + apply plus_one. eauto. + + constructor; auto. + rewrite ATPC_NEXT. + apply f_equal. + apply f_equal. + rewrite bblock_size_aux, list_length_z_cons; simpl. + omega. + - exploit (IHli b ofs f bb rs1 m_next' (State rs_next' m_next')); congruence || eauto. + + exploit is_tail_app_def; eauto. + intros (l3 & EQ); rewrite EQ. + exploit (is_tail_app_right _ (l3 ++ a::nil)). + rewrite <- app_assoc; simpl; eauto. + + constructor; auto. + rewrite ATPC_NEXT. + apply f_equal. + apply f_equal. + rewrite! list_length_z_cons; simpl. + omega. + + intros (s2' & LAST_STEPS & LAST_MATCHS). + eexists. split; eauto. + eapply plus_left'; eauto. +Qed. + +Lemma exec_body_simulation_plus b ofs f bb rs m s2 rs' m': forall + (ATPC: rs PC = Vptr b ofs) + (FINDF: Genv.find_funct_ptr ge b = Some (Internal f)) + (FINDBB: find_bblock (Ptrofs.unsigned ofs) (fn_blocks f) = Some bb) + (NEMPTY_BODY: body bb <> nil) + (MATCHI: match_internal (list_length_z (header bb)) (State rs m) s2) + (BODY: exec_body lk ge (body bb) rs m = Next rs' m'), + exists s2', plus Asm.step tge s2 E0 s2' + /\ match_internal (size bb - (Z.of_nat (length_opt (exit bb)))) (State rs' m') s2'. +Proof. + intros. + exploit exec_body_simulation_plus_gen; eauto. + - constructor. + - replace (list_length_z (header bb) + list_length_z (body bb) - list_length_z (body bb)) with (list_length_z (header bb)); auto. + omega. +Qed. + +Lemma exec_body_simulation_star b ofs f bb rs m s2 rs' m': forall + (ATPC: rs PC = Vptr b ofs) + (FINDF: Genv.find_funct_ptr ge b = Some (Internal f)) + (FINDBB: find_bblock (Ptrofs.unsigned ofs) (fn_blocks f) = Some bb) + (MATCHI: match_internal (list_length_z (header bb)) (State rs m) s2) + (BODY: exec_body lk ge (body bb) rs m = Next rs' m'), + exists s2', star Asm.step tge s2 E0 s2' + /\ match_internal (size bb - (Z.of_nat (length_opt (exit bb)))) (State rs' m') s2'. +Proof. + intros. + destruct (body bb) eqn: Hbb. + - simpl in BODY. inv BODY. + eexists. split. + eapply star_refl; eauto. + assert (EQ: (size bb - Z.of_nat (length_opt (exit bb))) = list_length_z (header bb)). + { rewrite bblock_size_aux. rewrite Hbb; unfold list_length_z; simpl. omega. } + rewrite EQ; eauto. + - exploit exec_body_simulation_plus; congruence || eauto. + { rewrite Hbb; eauto. } + intros (s2' & PLUS & MATCHI'). + eexists; split; eauto. + eapply plus_star; eauto. +Qed. + +Lemma list_nth_z_range_exceeded A (l : list A) n: + n >= list_length_z l -> + list_nth_z l n = None. +Proof. + intros N. + remember (list_nth_z l n) as opt eqn:H. symmetry in H. + destruct opt; auto. + exploit list_nth_z_range; eauto. omega. +Qed. + +Lemma label_in_header_list lbl a: + is_label lbl a = true -> list_length_z (header a) <= 1 -> header a = lbl :: nil. +Proof. + intros. + eapply is_label_correct_true in H. + destruct (header a). + - eapply in_nil in H. contradiction. + - rewrite list_length_z_cons in H0. + assert (list_length_z l0 >= 0) by eapply list_length_z_pos. + assert (list_length_z l0 = 0) by omega. + rewrite list_length_z_nat in H2. + assert (Datatypes.length l0 = 0%nat) by omega. + eapply length_zero_iff_nil in H3. subst. + unfold In in H. destruct H. + + subst; eauto. + + destruct H. +Qed. + +Lemma no_label_in_basic_inst: forall a lbl x, + basic_to_instruction a = OK x -> Asm.is_label lbl x = false. +Proof. + intros. + destruct a; simpl in *; + repeat destruct i; simpl in *; + try (try destruct_reg_inv; monadInv H; simpl in *; reflexivity). +Qed. + +Lemma label_pos_body bdy: forall c1 c2 z ex lbl + (HUNF : unfold_body bdy = OK c2), + Asm.label_pos lbl (z + Z.of_nat ((Datatypes.length bdy) + length_opt ex)) c1 = Asm.label_pos lbl (z) ((c2 ++ unfold_exit ex) ++ c1). +Proof. + induction bdy. + - intros. inversion HUNF. simpl in *. + destruct ex eqn:EQEX. + + simpl in *. unfold Asm.is_label. destruct c; simpl; try congruence. + destruct i; simpl; try congruence. + + simpl in *. ring_simplify (z + 0). auto. + - intros. inversion HUNF; clear HUNF. monadInv H0. simpl in *. + erewrite no_label_in_basic_inst; eauto. rewrite <- IHbdy; eauto. + erewrite Zpos_P_of_succ_nat. + apply f_equal2; auto. omega. +Qed. + +Lemma asm_label_pos_header: forall z a x0 x1 lbl + (HUNF: unfold_body (body a) = OK x1), + Asm.label_pos lbl (z + size a) x0 = + Asm.label_pos lbl (z + list_length_z (header a)) ((x1 ++ unfold_exit (exit a)) ++ x0). +Proof. + intros. + unfold size. + rewrite <- plus_assoc. rewrite Nat2Z.inj_add. + rewrite list_length_z_nat. + replace (z + (Z.of_nat (Datatypes.length (header a)) + Z.of_nat (Datatypes.length (body a) + length_opt (exit a)))) with (z + Z.of_nat (Datatypes.length (header a)) + Z.of_nat (Datatypes.length (body a) + length_opt (exit a))) by omega. + eapply (label_pos_body (body a) x0 x1 (z + Z.of_nat (Datatypes.length (header a))) (exit a) lbl). auto. +Qed. + +Lemma header_size_cons_nil: forall (l0: label) (l1: list label) + (HSIZE: list_length_z (l0 :: l1) <= 1), + l1 = nil. +Proof. + intros. + destruct l1; try congruence. rewrite !list_length_z_cons in HSIZE. + assert (list_length_z l1 >= 0) by eapply list_length_z_pos. + assert (list_length_z l1 + 1 + 1 >= 2) by omega. + assert (2 <= 1) by omega. contradiction H1. omega. +Qed. + +Lemma label_pos_preserved_gen bbs: forall lbl c z + (HUNF: unfold bbs = OK c), + label_pos lbl z bbs = Asm.label_pos lbl z c. +Proof. + induction bbs. + - intros. simpl in *. inversion HUNF. simpl. reflexivity. + - intros. simpl in *. monadInv HUNF. unfold unfold_bblock in EQ. + destruct (zle _ _); try congruence. monadInv EQ. + destruct (is_label _ _) eqn:EQLBL. + + erewrite label_in_header_list; eauto. + simpl in *. destruct (peq lbl lbl); try congruence. + + erewrite IHbbs; eauto. + rewrite (asm_label_pos_header z a x0 x1 lbl); auto. + unfold is_label in *. + destruct (header a). + * replace (z + list_length_z (@nil label)) with (z); eauto. + unfold list_length_z. simpl. omega. + * eapply header_size_cons_nil in l as HL1. + subst. simpl in *. destruct (in_dec _ _); try congruence. + simpl in *. + destruct (peq _ _); try intuition congruence. +Qed. + +Lemma label_pos_preserved f lbl z tf: forall + (FINDF: transf_function f = OK tf), + label_pos lbl z (fn_blocks f) = Asm.label_pos lbl z (Asm.fn_code tf). +Proof. + intros. + eapply label_pos_preserved_gen. + unfold transf_function in FINDF. monadInv FINDF. + destruct zlt; try congruence. inversion EQ0. eauto. +Qed. + +Lemma goto_label_preserved bb rs1 m1 rs1' m1' rs2 m2 lbl f tf v: forall + (FINDF: transf_function f = OK tf) + (BOUNDED: size bb <= Ptrofs.max_unsigned) + (MATCHI: match_internal (size bb - 1) (State rs1 m1) (State rs2 m2)) + (HGOTO: goto_label f lbl (incrPC v rs1) m1 = Next rs1' m1'), + exists (rs2' : regset) (m2' : mem), Asm.goto_label tf lbl rs2 m2 = Next rs2' m2' + /\ match_states (State rs1' m1') (State rs2' m2'). +Proof. + intros. + unfold goto_label, Asm.goto_label in *. + rewrite <- (label_pos_preserved f); auto. + inversion MATCHI as [n0 r1 mx1 r2 mx2 EQM EQR EQPC]; subst. + destruct label_pos; next_stuck_cong. + destruct (incrPC v rs1 PC) eqn:INCRPC; next_stuck_cong. + inversion HGOTO; auto. repeat (econstructor; eauto). + rewrite <- EQPC. + unfold incrPC in *. + rewrite !Pregmap.gss in *. + destruct (rs1 PC) eqn:EQRS1; simpl in *; try congruence. + replace (rs2 # PC <- (Vptr b0 (Ptrofs.repr z))) with ((rs1 # PC <- (Vptr b0 (Ptrofs.add i0 v))) # PC <- (Vptr b (Ptrofs.repr z))); auto. + eapply functional_extensionality. intros. + destruct (PregEq.eq x PC); subst. + rewrite !Pregmap.gss. congruence. + rewrite !Pregmap.gso; auto. +Qed. + +Lemma next_inst_incr_pc_preserved bb rs1 m1 rs1' m1' rs2 m2 f tf: forall + (FINDF: transf_function f = OK tf) + (BOUNDED: size bb <= Ptrofs.max_unsigned) + (MATCHI: match_internal (size bb - 1) (State rs1 m1) (State rs2 m2)) + (NEXT: Next (incrPC (Ptrofs.repr (size bb)) rs1) m2 = Next rs1' m1'), + exists (rs2' : regset) (m2' : mem), + Next (Asm.nextinstr rs2) m2 = Next rs2' m2' + /\ match_states (State rs1' m1') (State rs2' m2'). +Proof. + intros; simpl in *; unfold incrPC in NEXT; + inv_matchi; + assert (size bb >= 1) by eapply bblock_size_pos; + assert (0 <= size bb - 1 <= Ptrofs.max_unsigned) by omega; + inversion NEXT; subst; + eexists; eexists; split; eauto. + assert (rs1 # PC <- (Val.offset_ptr (rs1 PC) (Ptrofs.repr (size bb))) = Asm.nextinstr rs2). { + unfold Pregmap.set. apply functional_extensionality. + intros x. destruct (PregEq.eq x PC). + -- unfold Asm.nextinstr. rewrite <- AGPC. + rewrite Val.offset_ptr_assoc. rewrite Ptrofs.add_unsigned. + rewrite (Ptrofs.unsigned_repr (size bb - 1)); try omega. + rewrite Ptrofs.unsigned_one. + replace (size bb - 1 + 1) with (size bb) by omega. + rewrite e. rewrite Pregmap.gss. + reflexivity. + -- eapply nextinstr_agree_but_pc; eauto. } + rewrite H1. econstructor. +Qed. + +Lemma pc_reg_overwrite: forall (r: ireg) rs1 m1 rs2 m2 bb + (MATCHI: match_internal (size bb - 1) (State rs1 m1) (State rs2 m2)), + rs2 # PC <- (rs2 r) = + (rs1 # PC <- (Val.offset_ptr (rs1 PC) (Ptrofs.repr (size bb)))) # PC <- + (rs1 r). +Proof. + intros. + unfold Pregmap.set; apply functional_extensionality. + intros x; destruct (PregEq.eq x PC) as [X | X]; try discriminate; inv_matchi. +Qed. + +Lemma exec_cfi_simulation: + forall bb f tf rs1 m1 rs1' m1' rs2 m2 cfi + (SIZE: size bb <= Ptrofs.max_unsigned) + (FINDF: transf_function f = OK tf) + (* Warning: Asmblock's PC is assumed to be already pointing on the next instruction ! *) + (CFI: exec_cfi ge f cfi (incrPC (Ptrofs.repr (size bb)) rs1) m1 = Next rs1' m1') + (MATCHI: match_internal (size bb - 1) (State rs1 m1) (State rs2 m2)), + exists rs2' m2', Asm.exec_instr tge tf (cf_instruction_to_instruction cfi) + rs2 m2 = Next rs2' m2' + /\ match_states (State rs1' m1') (State rs2' m2'). +Proof. + intros. + assert (BBPOS: size bb >= 1) by eapply bblock_size_pos. + destruct cfi; inv CFI; simpl. + - (* Pb *) + exploit goto_label_preserved; eauto. + - (* Pbc *) + inv_matchi. + unfold eval_testcond in *. destruct c; + erewrite !incrPC_agree_but_pc in H0; try rewrite <- !AG; try congruence. + all: + destruct_reg_size; + try destruct b eqn:EQB. + 1,4,7,10,13,16,19,22,25,28,31,34: + exploit goto_label_preserved; eauto. + 1,3,5,7,9,11,13,15,17,19,21,23: + exploit next_inst_incr_pc_preserved; eauto. + all: repeat (econstructor; eauto). + - (* Pbl *) + eexists; eexists; split; eauto. + assert ( ((incrPC (Ptrofs.repr (size bb)) rs1) # X30 <- (incrPC (Ptrofs.repr (size bb)) rs1 PC)) + # PC <- (Genv.symbol_address ge id Ptrofs.zero) + = (rs2 # X30 <- (Val.offset_ptr (rs2 PC) Ptrofs.one)) + # PC <- (Genv.symbol_address tge id Ptrofs.zero) + ) as EQRS. { + unfold incrPC. unfold Pregmap.set. simpl. apply functional_extensionality. + intros x. destruct (PregEq.eq x PC). + * rewrite symbol_addresses_preserved. reflexivity. + * destruct (PregEq.eq x X30). + -- inv MATCHI. rewrite <- AGPC. rewrite Val.offset_ptr_assoc. + unfold Ptrofs.add, Ptrofs.one. repeat (rewrite Ptrofs.unsigned_repr); try omega. + replace (size bb - 1 + 1) with (size bb) by omega. reflexivity. + -- inv MATCHI; rewrite AG; try assumption; reflexivity. + } rewrite EQRS; inv MATCHI; reflexivity. + - (* Pbs *) + eexists; eexists; split; eauto. + assert ( (incrPC (Ptrofs.repr (size bb)) rs1) # PC <- + (Genv.symbol_address ge id Ptrofs.zero) + = rs2 # PC <- (Genv.symbol_address tge id Ptrofs.zero) + ) as EQRS. { + unfold incrPC, Pregmap.set. rewrite symbol_addresses_preserved. inv MATCHI. + apply functional_extensionality. intros x. destruct (PregEq.eq x PC); auto. + } rewrite EQRS; inv MATCHI; reflexivity. + - (* Pblr *) + eexists; eexists; split; eauto. + unfold incrPC. rewrite Pregmap.gss. rewrite Pregmap.gso; try discriminate. + assert ( (rs2 # X30 <- (Val.offset_ptr (rs2 PC) Ptrofs.one)) # PC <- (rs2 r) + = ((rs1 # PC <- (Val.offset_ptr (rs1 PC) (Ptrofs.repr (size bb)))) + # X30 <- (Val.offset_ptr (rs1 PC) (Ptrofs.repr (size bb)))) + # PC <- (rs1 r) + ) as EQRS. { + unfold Pregmap.set. apply functional_extensionality. + intros x; destruct (PregEq.eq x PC) as [X | X]. + - inv_matchi; rewrite AG; auto. + - destruct (PregEq.eq x X30) as [X' | X']. + + inversion MATCHI; subst. rewrite <- AGPC. + rewrite Val.offset_ptr_assoc. unfold Ptrofs.one. + rewrite Ptrofs.add_unsigned. rewrite Ptrofs.unsigned_repr; try omega. rewrite Ptrofs.unsigned_repr; try omega. + rewrite Z.sub_add; reflexivity. + + inv_matchi. + } rewrite EQRS. inv_matchi. + - (* Pbr *) + eexists; eexists; split; eauto. + unfold incrPC. rewrite Pregmap.gso; try discriminate. + rewrite (pc_reg_overwrite r rs1 m1' rs2 m2 bb); auto. + inv_matchi. + - (* Pret *) + eexists; eexists; split; eauto. + unfold incrPC. rewrite Pregmap.gso; try discriminate. + rewrite (pc_reg_overwrite r rs1 m1' rs2 m2 bb); auto. + inv_matchi. + - (* Pcbnz *) + inv_matchi. + unfold eval_neg_branch in *. + erewrite incrPC_agree_but_pc in H0; try congruence. + destruct eval_testzero; next_stuck_cong. + destruct b. + * exploit next_inst_incr_pc_preserved; eauto. + * exploit goto_label_preserved; eauto. + - (* Pcbz *) + inv_matchi. + unfold eval_branch in *. + erewrite incrPC_agree_but_pc in H0; try congruence. + destruct eval_testzero; next_stuck_cong. + destruct b. + * exploit goto_label_preserved; eauto. + * exploit next_inst_incr_pc_preserved; eauto. + - (* Ptbnbz *) + inv_matchi. + unfold eval_branch in *. + erewrite incrPC_agree_but_pc in H0; try congruence. + destruct eval_testbit; next_stuck_cong. + destruct b. + * exploit goto_label_preserved; eauto. + * exploit next_inst_incr_pc_preserved; eauto. + - (* Ptbz *) + inv_matchi. + unfold eval_neg_branch in *. + erewrite incrPC_agree_but_pc in H0; try congruence. + destruct eval_testbit; next_stuck_cong. + destruct b. + * exploit next_inst_incr_pc_preserved; eauto. + * exploit goto_label_preserved; eauto. + - (* Pbtbl *) + assert (rs2 # X16 <- Vundef r1 = (incrPC (Ptrofs.repr (size bb)) rs1) # X16 <- Vundef r1) + as EQUNDEFX16. { + unfold incrPC, Pregmap.set. + destruct (PregEq.eq r1 X16) as [X16 | X16]; auto. + destruct (PregEq.eq r1 PC) as [PC' | PC']; try discriminate. + inv MATCHI; rewrite AG; auto. + } rewrite <- EQUNDEFX16 in H0. + destruct_reg_inv; next_stuck_cong. + unfold goto_label, Asm.goto_label in *. + rewrite <- (label_pos_preserved f); auto. + inversion MATCHI; subst. + destruct label_pos; next_stuck_cong. + destruct (((incrPC (Ptrofs.repr (size bb)) rs1) # X16 <- Vundef) # X17 <- Vundef PC) eqn:INCRPC; next_stuck_cong. + inversion H0; auto. repeat (econstructor; eauto). + rewrite !Pregmap.gso; try congruence. + rewrite <- AGPC. + unfold incrPC in *. + destruct (rs1 PC) eqn:EQRS1; simpl in *; try discriminate. + replace (((rs2 # X16 <- Vundef) # X17 <- Vundef) # PC <- (Vptr b0 (Ptrofs.repr z))) with + ((((rs1 # PC <- (Vptr b0 (Ptrofs.add i1 (Ptrofs.repr (size bb))))) # X16 <- + Vundef) # X17 <- Vundef) # PC <- (Vptr b (Ptrofs.repr z))); auto. + eapply functional_extensionality; intros x. + destruct (PregEq.eq x PC); subst. + + rewrite Pregmap.gso in INCRPC; try congruence. + rewrite Pregmap.gso in INCRPC; try congruence. + rewrite Pregmap.gss in INCRPC. + rewrite !Pregmap.gss in *; congruence. + + rewrite Pregmap.gso; auto. + rewrite (Pregmap.gso (i := x) (j := PC)); auto. + destruct (PregEq.eq x X17); subst. + * rewrite !Pregmap.gss; auto. + * rewrite !(Pregmap.gso (i := x) (j:= X17)); auto. destruct (PregEq.eq x X16); subst. + -- rewrite !Pregmap.gss; auto. + -- rewrite !Pregmap.gso; auto. +Qed. + +Lemma last_instruction_cannot_be_label bb: + list_nth_z (header bb) (size bb - 1) = None. +Proof. + assert (list_length_z (header bb) <= size bb - 1). { + rewrite bblock_size_aux. generalize (bblock_size_aux_pos bb). omega. + } + remember (list_nth_z (header bb) (size bb - 1)) as label_opt; destruct label_opt; auto; + exploit list_nth_z_range; eauto; omega. +Qed. + +Lemma pc_ptr_exec_step: forall ofs bb b rs m _rs _m + (ATPC : rs PC = Vptr b ofs) + (MATCHI : match_internal (size bb - 1) + {| _rs := rs; _m := m |} + {| _rs := _rs; _m := _m |}), + _rs PC = Vptr b (Ptrofs.add ofs (Ptrofs.repr (size bb - 1))). +Proof. + intros; inv MATCHI. rewrite <- AGPC; rewrite ATPC; unfold Val.offset_ptr; eauto. +Qed. + +Lemma find_instr_ofs_somei: forall ofs bb f tc asmi rs m _rs _m + (BOUNDOFS : Ptrofs.unsigned ofs + size bb <= Ptrofs.max_unsigned) + (FIND_INSTR : Asm.find_instr (Ptrofs.unsigned ofs + (size bb - 1)) tc = + Some (asmi)) + (MATCHI : match_internal (size bb - 1) + {| _rs := rs; _m := m |} + {| _rs := _rs; _m := _m |}), + Asm.find_instr (Ptrofs.unsigned (Ptrofs.add ofs (Ptrofs.repr (size bb - 1)))) + (Asm.fn_code {| Asm.fn_sig := fn_sig f; Asm.fn_code := tc |}) = + Some (asmi). +Proof. + intros; simpl. + replace (Ptrofs.unsigned (Ptrofs.add ofs (Ptrofs.repr (size bb - 1)))) + with (Ptrofs.unsigned ofs + (size bb - 1)); try assumption. + generalize (bblock_size_pos bb); generalize (Ptrofs.unsigned_range_2 ofs); intros. + unfold Ptrofs.add. + rewrite Ptrofs.unsigned_repr. rewrite Ptrofs.unsigned_repr; try omega. + rewrite Ptrofs.unsigned_repr; omega. +Qed. + +Lemma eval_builtin_arg_match: forall rs _m _rs a1 b1 + (AG : forall r : preg, r <> PC -> rs r = _rs r) + (EVAL : eval_builtin_arg tge (fun r : dreg => rs r) (rs SP) _m a1 b1), + eval_builtin_arg tge _rs (_rs SP) _m (map_builtin_arg DR a1) b1. +Proof. + intros; induction EVAL; simpl in *; try rewrite AG; try rewrite AG in EVAL; try discriminate; try congruence; eauto with barg. + econstructor. rewrite <- AG; try discriminate; auto. +Qed. + +Lemma eval_builtin_args_match: forall bb rs m _rs _m args vargs + (MATCHI : match_internal (size bb - 1) + {| _rs := rs; _m := m |} + {| _rs := _rs; _m := _m |}) + (EVAL : eval_builtin_args tge (fun r : dreg => rs r) (rs SP) m args vargs), + eval_builtin_args tge _rs (_rs SP) _m (map (map_builtin_arg DR) args) vargs. +Proof. + intros; inv MATCHI. + induction EVAL; subst. + - econstructor. + - econstructor. + + eapply eval_builtin_arg_match; eauto. + + eauto. +Qed. + +Lemma pc_both_sides: forall (rs _rs: regset) v + (AG : forall r : preg, r <> PC -> rs r = _rs r), + rs # PC <- v = _rs # PC <- v. +Proof. + intros; unfold Pregmap.set; apply functional_extensionality; intros y. + destruct (PregEq.eq y PC); try rewrite AG; eauto. +Qed. + +Lemma set_buitin_res_sym res: forall vres rs _rs r + (NPC: r <> PC) + (AG : forall r : preg, r <> PC -> rs r = _rs r), + set_res res vres rs r = set_res res vres _rs r. +Proof. + induction res; simpl; intros; unfold Pregmap.set; try rewrite AG; eauto. +Qed. + +Lemma set_builtin_res_dont_move_pc_gen res: forall vres rs _rs v1 v2 + (HV: v1 = v2) + (AG : forall r : preg, r <> PC -> rs r = _rs r), + (set_res res vres rs) # PC <- v1 = + (set_res res vres _rs) # PC <- v2. +Proof. + intros. rewrite HV. generalize res vres rs _rs AG v2. + clear res vres rs _rs AG v1 v2 HV. + induction res. + - simpl; intros. apply pc_both_sides; intros. + unfold Pregmap.set; try rewrite AG; eauto. + - simpl; intros; apply pc_both_sides; eauto. + - simpl; intros. + erewrite IHres2; eauto; intros. + eapply set_buitin_res_sym; eauto. +Qed. + +Lemma set_builtin_map_not_pc (res: builtin_res dreg): forall vres rs, + set_res (map_builtin_res DR res) vres rs PC = rs PC. +Proof. + induction res. + - intros; simpl. unfold Pregmap.set. destruct (PregEq.eq PC x); try congruence. + - intros; simpl; congruence. + - intros; simpl in *. rewrite IHres2. rewrite IHres1. reflexivity. +Qed. + +Lemma undef_reg_preserved (rl: list mreg): forall rs _rs r + (NPC: r <> PC) + (AG : forall r : preg, r <> PC -> rs r = _rs r), + undef_regs (map preg_of rl) rs r = undef_regs (map preg_of rl) _rs r. +Proof. + induction rl. + - simpl; auto. + - simpl; intros. erewrite IHrl; eauto. + intros. unfold Pregmap.set. destruct (PregEq.eq r0 (preg_of a)); try rewrite AG; eauto. +Qed. + +Lemma undef_regs_other: + forall r rl rs, + (forall r', In r' rl -> r <> r') -> + undef_regs rl rs r = rs r. +Proof. + induction rl; simpl; intros. auto. + rewrite IHrl by auto. rewrite Pregmap.gso; auto. +Qed. + +Fixpoint preg_notin (r: preg) (rl: list mreg) : Prop := + match rl with + | nil => True + | r1 :: nil => r <> preg_of r1 + | r1 :: rl => r <> preg_of r1 /\ preg_notin r rl + end. + +Remark preg_notin_charact: + forall r rl, + preg_notin r rl <-> (forall mr, In mr rl -> r <> preg_of mr). +Proof. + induction rl; simpl; intros. + tauto. + destruct rl. + simpl. split. intros. intuition congruence. auto. + rewrite IHrl. split. + intros [A B]. intros. destruct H. congruence. auto. + auto. +Qed. + +Lemma undef_regs_other_2: + forall r rl rs, + preg_notin r rl -> + undef_regs (map preg_of rl) rs r = rs r. +Proof. + intros. apply undef_regs_other. intros. + exploit list_in_map_inv; eauto. intros [mr [A B]]. subst. + rewrite preg_notin_charact in H. auto. +Qed. + +Lemma exec_exit_simulation_plus b ofs f bb s2 t rs m rs' m': forall + (FINDF: Genv.find_funct_ptr ge b = Some (Internal f)) + (FINDBB: find_bblock (Ptrofs.unsigned ofs) (fn_blocks f) = Some bb) + (NEMPTY_EXIT: exit bb <> None) + (MATCHI: match_internal (size bb - Z.of_nat (length_opt (exit bb))) (State rs m) s2) + (EXIT: exec_exit ge f (Ptrofs.repr (size bb)) rs m (exit bb) t rs' m') + (ATPC: rs PC = Vptr b ofs), + plus Asm.step tge s2 t (State rs' m'). +Proof. + intros. + exploit internal_functions_unfold; eauto. + intros (tc & FINDtf & TRANStf & _). + + exploit (find_instr_bblock (size bb - 1)); eauto. + { generalize (bblock_size_pos bb). omega. } + intros (i' & NTH & FIND_INSTR). + + inv NTH. + + rewrite last_instruction_cannot_be_label in *. discriminate. + + destruct (exit bb) as [ctrl |] eqn:NEMPTY_EXIT'. 2: { contradiction. } + rewrite bblock_size_aux in *. rewrite NEMPTY_EXIT' in *. simpl in *. + (* XXX: Is there a better way to simplify this expression i.e. automatically? *) + replace (list_length_z (header bb) + list_length_z (body bb) + 1 - 1 - + list_length_z (header bb)) with (list_length_z (body bb)) in H by omega. + rewrite list_nth_z_range_exceeded in H; try omega. discriminate. + + assert (Ptrofs.unsigned ofs + size bb <= Ptrofs.max_unsigned). { + eapply size_of_blocks_bounds; eauto. + } + assert (size bb <= Ptrofs.max_unsigned). { generalize (Ptrofs.unsigned_range_2 ofs); omega. } + destruct cfi. + * (* control flow instruction *) + destruct s2. + rewrite H in EXIT. (* exit bb is a cfi *) + inv EXIT. + rewrite H in MATCHI. simpl in MATCHI. + exploit internal_functions_translated; eauto. + rewrite FINDtf. + intros (tf & FINDtf' & TRANSf). inversion FINDtf'; subst; clear FINDtf'. + exploit exec_cfi_simulation; eauto. + (* extract exec_cfi_simulation's conclusion as separate hypotheses *) + intros (rs2' & m2' & EXECI & MATCHS); rewrite MATCHS. + apply plus_one. + eapply Asm.exec_step_internal; eauto. + - eapply pc_ptr_exec_step; eauto. + - eapply find_instr_ofs_somei; eauto. + * (* builtin *) + destruct s2. + rewrite H in EXIT. + rewrite H in MATCHI. simpl in MATCHI. + simpl in FIND_INSTR. + inversion EXIT. + apply plus_one. + eapply external_call_symbols_preserved in H10; try (apply senv_preserved). + eapply eval_builtin_args_preserved in H6; try (apply symbols_preserved). + eapply Asm.exec_step_builtin; eauto. + - eapply pc_ptr_exec_step; eauto. + - eapply find_instr_ofs_somei; eauto. + - eapply eval_builtin_args_match; eauto. + - inv MATCHI; eauto. + - inv MATCHI. + unfold Asm.nextinstr, incrPC. + assert (HPC: Val.offset_ptr (rs PC) (Ptrofs.repr (size bb)) + = Val.offset_ptr (_rs PC) Ptrofs.one). + { rewrite <- AGPC. rewrite ATPC. unfold Val.offset_ptr. + rewrite Ptrofs.add_assoc. unfold Ptrofs.add. + assert (BBPOS: size bb >= 1) by eapply bblock_size_pos. + rewrite (Ptrofs.unsigned_repr (size bb - 1)); try omega. + rewrite Ptrofs.unsigned_one. + replace (size bb - 1 + 1) with (size bb) by omega. + reflexivity. } + apply set_builtin_res_dont_move_pc_gen. + -- erewrite !set_builtin_map_not_pc. + erewrite !undef_regs_other_2. + rewrite HPC; auto. all: rewrite preg_notin_charact; intros; try discriminate. + -- intros. eapply undef_reg_preserved; eauto. +Qed. + +Lemma exec_exit_simulation_star b ofs f bb s2 t rs m rs' m': forall + (FINDF: Genv.find_funct_ptr ge b = Some (Internal f)) + (FINDBB: find_bblock (Ptrofs.unsigned ofs) (fn_blocks f) = Some bb) + (MATCHI: match_internal (size bb - Z.of_nat (length_opt (exit bb))) (State rs m) s2) + (EXIT: exec_exit ge f (Ptrofs.repr (size bb)) rs m (exit bb) t rs' m') + (ATPC: rs PC = Vptr b ofs), + star Asm.step tge s2 t (State rs' m'). +Proof. + intros. + destruct (exit bb) eqn: Hex. + - eapply plus_star. + eapply exec_exit_simulation_plus; try rewrite Hex; congruence || eauto. + - inv MATCHI. + inv EXIT. + assert (X: rs2 = incrPC (Ptrofs.repr (size bb)) rs). { + unfold incrPC. unfold Pregmap.set. + apply functional_extensionality. intros x. + destruct (PregEq.eq x PC) as [X|]. + - rewrite X. rewrite <- AGPC. simpl. + replace (size bb - 0) with (size bb) by omega. reflexivity. + - rewrite AG; try assumption. reflexivity. + } + destruct X. + subst; eapply star_refl; eauto. +Qed. + +Lemma exec_bblock_simulation b ofs f bb t rs m rs' m': forall + (ATPC: rs PC = Vptr b ofs) + (FINDF: Genv.find_funct_ptr ge b = Some (Internal f)) + (FINDBB: find_bblock (Ptrofs.unsigned ofs) (fn_blocks f) = Some bb) + (EXECBB: exec_bblock lk ge f bb rs m t rs' m'), + plus Asm.step tge (State rs m) t (State rs' m'). +Proof. + intros; destruct EXECBB as (rs1 & m1 & BODY & CTL). + exploit exec_header_simulation; eauto. + intros (s0 & STAR & MATCH0). + eapply star_plus_trans; traceEq || eauto. + destruct (bblock_non_empty bb). + - (* body bb <> nil *) + exploit exec_body_simulation_plus; eauto. + intros (s1 & PLUS & MATCH1). + eapply plus_star_trans; traceEq || eauto. + eapply exec_exit_simulation_star; eauto. + erewrite <- exec_body_dont_move_PC; eauto. + - (* exit bb <> None *) + exploit exec_body_simulation_star; eauto. + intros (s1 & STAR1 & MATCH1). + eapply star_plus_trans; traceEq || eauto. + eapply exec_exit_simulation_plus; eauto. + erewrite <- exec_body_dont_move_PC; eauto. +Qed. + +Lemma step_simulation s t s': + Asmblock.step lk ge s t s' -> plus Asm.step tge s t s'. +Proof. + intros STEP. + inv STEP; simpl; exploit functions_translated; eauto; + intros (tf0 & FINDtf & TRANSf); + monadInv TRANSf. + - (* internal step *) eapply exec_bblock_simulation; eauto. + - (* external step *) + apply plus_one. + exploit external_call_symbols_preserved; eauto. apply senv_preserved. + intros ?. + eapply Asm.exec_step_external; eauto. +Qed. + +Lemma transf_program_correct: + forward_simulation (Asmblock.semantics lk prog) (Asm.semantics tprog). +Proof. + eapply forward_simulation_plus. + - apply senv_preserved. + - eexact transf_initial_states. + - eexact transf_final_states. + - (* TODO step_simulation *) + unfold match_states. + simpl; intros; subst; eexists; split; eauto. + eapply step_simulation; eauto. +Qed. + +End PRESERVATION. + +End Asmblock_PRESERVATION. + + +Local Open Scope linking_scope. + +Definition block_passes := + mkpass Machblockgenproof.match_prog + ::: mkpass PseudoAsmblockproof.match_prog + ::: mkpass Asmblockgenproof.match_prog + (*::: mkpass PostpassSchedulingproof.match_prog*) + ::: mkpass Asmblock_PRESERVATION.match_prog + ::: pass_nil _. + +Definition match_prog := pass_match (compose_passes block_passes). + +Lemma transf_program_match: + forall p tp, Asmgen.transf_program p = OK tp -> match_prog p tp. +Proof. + intros p tp H. + unfold Asmgen.transf_program in H. apply bind_inversion in H. destruct H. + inversion_clear H. apply bind_inversion in H1. destruct H1. + inversion_clear H. inversion H2. remember (Machblockgen.transf_program p) as mbp. + unfold match_prog; simpl. + exists mbp; split. apply Machblockgenproof.transf_program_match; auto. + exists x; split. apply PseudoAsmblockproof.transf_program_match; auto. + exists x0; split. apply Asmblockgenproof.transf_program_match; auto. + exists tp; split. apply Asmblock_PRESERVATION.transf_program_match; auto. auto. +Qed. + +(** Return Address Offset *) + +Definition return_address_offset: Mach.function -> Mach.code -> ptrofs -> Prop := + Machblockgenproof.Mach_return_address_offset (PseudoAsmblockproof.rao Asmblockgenproof.next). + +Lemma return_address_exists: + forall f sg ros c, is_tail (Mach.Mcall sg ros :: c) f.(Mach.fn_code) -> + exists ra, return_address_offset f c ra. +Proof. + intros; eapply Machblockgenproof.Mach_return_address_exists; eauto. +Admitted. + +Section PRESERVATION. + +Variable prog: Mach.program. +Variable tprog: Asm.program. +Hypothesis TRANSF: match_prog prog tprog. +Let ge := Genv.globalenv prog. +Let tge := Genv.globalenv tprog. + +Theorem transf_program_correct: + forward_simulation (Mach.semantics return_address_offset prog) (Asm.semantics tprog). +Proof. + unfold match_prog in TRANSF. simpl in TRANSF. + inv TRANSF. inv H. inv H1. inv H. inv H2. inv H. inv H3. inv H. + eapply compose_forward_simulations. + { exploit Machblockgenproof.transf_program_correct; eauto. } + eapply compose_forward_simulations. + + apply PseudoAsmblockproof.transf_program_correct; eauto. + - intros; apply Asmblockgenproof.next_progress. + - intros; eapply Asmblockgenproof.functions_bound_max_pos; eauto. + { intros; eapply Asmblock_PRESERVATION.symbol_high_low; eauto. } + + eapply compose_forward_simulations. apply Asmblockgenproof.transf_program_correct; eauto. + { intros; eapply Asmblock_PRESERVATION.symbol_high_low; eauto. } + apply Asmblock_PRESERVATION.transf_program_correct. eauto. +Qed. + +End PRESERVATION. + +Instance TransfAsm: TransfLink match_prog := pass_match_link (compose_passes block_passes). + +(*******************************************) +(* Stub actually needed by driver/Compiler *) + +Module Asmgenproof0. + +Definition return_address_offset := return_address_offset. + +End Asmgenproof0. diff --git a/aarch64/InstructionScheduler.ml b/aarch64/InstructionScheduler.ml new file mode 100644 index 00000000..eab0b21a --- /dev/null +++ b/aarch64/InstructionScheduler.ml @@ -0,0 +1,1263 @@ +(* *************************************************************) +(* *) +(* The Compcert verified compiler *) +(* *) +(* Sylvain Boulmé Grenoble-INP, VERIMAG *) +(* David Monniaux CNRS, VERIMAG *) +(* Cyril Six Kalray *) +(* *) +(* Copyright Kalray. Copyright VERIMAG. All rights reserved. *) +(* This file is distributed under the terms of the INRIA *) +(* Non-Commercial License Agreement. *) +(* *) +(* *************************************************************) + +let with_destructor dtor stuff f = + try let ret = f stuff in + dtor stuff; + ret + with exn -> dtor stuff; + raise exn;; + +let with_out_channel chan f = with_destructor close_out chan f;; +let with_in_channel chan f = with_destructor close_in chan f;; + +(** Schedule instructions on a synchronized pipeline +@author David Monniaux, CNRS, VERIMAG *) + +type latency_constraint = { + instr_from : int; + instr_to : int; + latency : int };; + +type problem = { + max_latency : int; + resource_bounds : int array; + instruction_usages : int array array; + latency_constraints : latency_constraint list; + };; + +let print_problem channel problem = + (if problem.max_latency >= 0 + then Printf.fprintf channel "max makespan: %d\n" problem.max_latency); + output_string channel "resource bounds:"; + (Array.iter (fun b -> Printf.fprintf channel " %d" b) problem.resource_bounds); + output_string channel ";\n"; + (Array.iteri (fun i v -> + Printf.fprintf channel "instr%d:" i; + (Array.iter (fun b -> Printf.fprintf channel " %d" b) v); + output_string channel ";\n") problem.instruction_usages); + List.iter (fun instr -> + Printf.printf "t%d - t%d >= %d;\n" + instr.instr_to instr.instr_from instr.latency) + problem.latency_constraints;; + +let get_nr_instructions problem = Array.length problem.instruction_usages;; +let get_nr_resources problem = Array.length problem.resource_bounds;; + +type solution = int array +type scheduler = problem -> solution option + +(* DISABLED +(** Schedule the problem optimally by constraint solving using the Gecode solver. *) +external gecode_scheduler : problem -> solution option = + "caml_gecode_schedule_instr";; + *) + +let maximum_slot_used times = + let maxi = ref (-1) in + for i=0 to (Array.length times)-2 + do + maxi := max !maxi times.(i) + done; + !maxi;; + +let check_schedule (problem : problem) (times : solution) = + let nr_instructions = get_nr_instructions problem in + (if Array.length times <> nr_instructions+1 + then failwith + (Printf.sprintf "check_schedule: %d times expected, got %d" + (nr_instructions+1) (Array.length times))); + (if problem.max_latency >= 0 && times.(nr_instructions)> problem.max_latency + then failwith "check_schedule: max_latency exceeded"); + (Array.iteri (fun i time -> + (if time < 0 + then failwith (Printf.sprintf "time[%d] < 0" i))) times); + let slot_resources = Array.init ((maximum_slot_used times)+1) + (fun _ -> Array.copy problem.resource_bounds) in + for i=0 to nr_instructions -1 + do + let remaining_resources = slot_resources.(times.(i)) + and used_resources = problem.instruction_usages.(i) in + for resource=0 to (Array.length used_resources)-1 + do + let after = remaining_resources.(resource) - used_resources.(resource) in + (if after < 0 + then failwith (Printf.sprintf "check_schedule: instruction %d exceeds resource %d at slot %d" i resource times.(i))); + remaining_resources.(resource) <- after + done + done; + List.iter (fun ctr -> + if times.(ctr.instr_to) - times.(ctr.instr_from) < ctr.latency + then failwith (Printf.sprintf "check_schedule: time[%d]=%d - time[%d]=%d < %d" + ctr.instr_to times.(ctr.instr_to) + ctr.instr_from times.(ctr.instr_from) + ctr.latency) + ) problem.latency_constraints;; + +let bound_max_time problem = + let total = ref(Array.length problem.instruction_usages) in + List.iter (fun ctr -> total := !total + ctr.latency) problem.latency_constraints; + !total;; + +let vector_less_equal a b = + try + Array.iter2 (fun x y -> + if x>y + then raise Exit) a b; + true + with Exit -> false;; + +let vector_subtract a b = + assert ((Array.length a) = (Array.length b)); + for i=0 to (Array.length a)-1 + do + b.(i) <- b.(i) - a.(i) + done;; + +(* The version with critical path ordering is much better! *) +type list_scheduler_order = + | INSTRUCTION_ORDER + | CRITICAL_PATH_ORDER;; + +let int_max (x : int) (y : int) = + if x > y then x else y;; + +let int_min (x : int) (y : int) = + if x < y then x else y;; + +let get_predecessors problem = + let nr_instructions = get_nr_instructions problem in + let predecessors = Array.make (nr_instructions+1) [] in + List.iter (fun ctr -> + predecessors.(ctr.instr_to) <- + (ctr.instr_from, ctr.latency)::predecessors.(ctr.instr_to)) + problem.latency_constraints; + predecessors;; + +let get_successors problem = + let nr_instructions = get_nr_instructions problem in + let successors = Array.make nr_instructions [] in + List.iter (fun ctr -> + successors.(ctr.instr_from) <- + (ctr.instr_to, ctr.latency)::successors.(ctr.instr_from)) + problem.latency_constraints; + successors;; + +let critical_paths successors = + let nr_instructions = Array.length successors in + let path_lengths = Array.make nr_instructions (-1) in + let rec compute i = + if i=nr_instructions then 0 else + match path_lengths.(i) with + | -2 -> failwith "InstructionScheduler: the dependency graph has cycles" + | -1 -> path_lengths.(i) <- -2; + let x = List.fold_left + (fun cur (j, latency)-> int_max cur (latency+(compute j))) + 1 successors.(i) + in path_lengths.(i) <- x; x + | x -> x + in for i = nr_instructions-1 downto 0 + do + ignore (compute i) + done; + path_lengths;; + +let maximum_critical_path problem = + let paths = critical_paths (get_successors problem) in + Array.fold_left int_max 0 paths;; + +let get_earliest_dates predecessors = + let nr_instructions = (Array.length predecessors)-1 in + let path_lengths = Array.make (nr_instructions+1) (-1) in + let rec compute i = + match path_lengths.(i) with + | -2 -> failwith "InstructionScheduler: the dependency graph has cycles" + | -1 -> path_lengths.(i) <- -2; + let x = List.fold_left + (fun cur (j, latency)-> int_max cur (latency+(compute j))) + 0 predecessors.(i) + in path_lengths.(i) <- x; x + | x -> x + in for i = 0 to nr_instructions + do + ignore (compute i) + done; + for i = 0 to nr_instructions - 1 + do + path_lengths.(nr_instructions) <- int_max + path_lengths.(nr_instructions) (1 + path_lengths.(i)) + done; + path_lengths;; + +exception Unschedulable + +let get_latest_dates deadline successors = + let nr_instructions = Array.length successors + and path_lengths = critical_paths successors in + Array.init (nr_instructions + 1) + (fun i -> + if i < nr_instructions then + let path_length = path_lengths.(i) in + assert (path_length >= 1); + (if path_length > deadline + then raise Unschedulable); + deadline - path_length + else deadline);; + +let priority_list_scheduler (order : list_scheduler_order) + (problem : problem) : + solution option = + let nr_instructions = get_nr_instructions problem in + let successors = get_successors problem + and predecessors = get_predecessors problem + and times = Array.make (nr_instructions+1) (-1) in + + let priorities = match order with + | INSTRUCTION_ORDER -> None + | CRITICAL_PATH_ORDER -> Some (critical_paths successors) in + + let module InstrSet = + Set.Make (struct type t=int + let compare = match priorities with + | None -> (fun x y -> x - y) + | Some p -> (fun x y -> + (match p.(y)-p.(x) with + | 0 -> x - y + | z -> z)) + end) in + + let max_time = bound_max_time problem in + let ready = Array.make max_time InstrSet.empty in + Array.iteri (fun i preds -> + if i<nr_instructions && preds=[] + then ready.(0) <- InstrSet.add i ready.(0)) predecessors; + + let current_time = ref 0 + and current_resources = Array.copy problem.resource_bounds + and earliest_time i = + try + let time = ref (-1) in + List.iter (fun (j, latency) -> + if times.(j) < 0 + then raise Exit + else let t = times.(j) + latency in + if t > !time + then time := t) predecessors.(i); + assert(!time >= 0); + !time + with Exit -> -1 + + in + let advance_time() = + begin + (if !current_time < max_time-1 + then + begin + Array.blit problem.resource_bounds 0 current_resources 0 + (Array.length current_resources); + ready.(!current_time + 1) <- + InstrSet.union (ready.(!current_time)) (ready.(!current_time + 1)); + ready.(!current_time) <- InstrSet.empty; + end); + incr current_time + end in + + let attempt_scheduling ready usages = + let result = ref (-1) in + try + InstrSet.iter (fun i -> + (* Printf.printf "trying scheduling %d\n" i; + pr int_vector usages.(i); + print _vector current_resources; *) + if vector_less_equal usages.(i) current_resources + then + begin + vector_subtract usages.(i) current_resources; + result := i; + raise Exit + end) ready; + -1 + with Exit -> !result in + + while !current_time < max_time + do + if (InstrSet.is_empty ready.(!current_time)) + then advance_time() + else + match attempt_scheduling ready.(!current_time) + problem.instruction_usages with + | -1 -> advance_time() + | i -> + begin + assert(times.(i) < 0); + times.(i) <- !current_time; + ready.(!current_time) <- InstrSet.remove i (ready.(!current_time)); + List.iter (fun (instr_to, latency) -> + if instr_to < nr_instructions then + match earliest_time instr_to with + | -1 -> () + | to_time -> + ready.(to_time) <- InstrSet.add instr_to ready.(to_time)) + successors.(i); + successors.(i) <- [] + end + done; + try + let final_time = ref (-1) in + for i=0 to nr_instructions-1 + do + (if times.(i) < 0 then raise Exit); + (if !final_time < times.(i)+1 then final_time := times.(i)+1) + done; + List.iter (fun (i, latency) -> + let target_time = latency + times.(i) in + if target_time > !final_time + then final_time := target_time + ) predecessors.(nr_instructions); + times.(nr_instructions) <- !final_time; + Some times + with Exit -> None;; + +let list_scheduler = priority_list_scheduler CRITICAL_PATH_ORDER;; + +(* dummy code for placating ocaml's warnings *) +let _ = fun x -> priority_list_scheduler INSTRUCTION_ORDER x;; + +type bundle = int list;; + +let rec extract_deps_to index = function + | [] -> [] + | dep :: deps -> let extracts = extract_deps_to index deps in + if (dep.instr_to == index) then + dep :: extracts + else + extracts + +exception InvalidBundle;; + +let dependency_check problem bundle index = + let index_deps = extract_deps_to index problem.latency_constraints in + List.iter (fun i -> + List.iter (fun dep -> + if (dep.instr_from == i) then raise InvalidBundle + ) index_deps + ) bundle;; + +let rec make_bundle problem resources bundle index = + let resources_copy = Array.copy resources in + let nr_instructions = get_nr_instructions problem in + if (index >= nr_instructions) then (bundle, index+1) else + let inst_usage = problem.instruction_usages.(index) in + try match vector_less_equal inst_usage resources with + | false -> raise InvalidBundle + | true -> ( + dependency_check problem bundle index; + vector_subtract problem.instruction_usages.(index) resources_copy; + make_bundle problem resources_copy (index::bundle) (index+1) + ) + with InvalidBundle -> (bundle, index);; + +let rec make_bundles problem index : bundle list = + if index >= get_nr_instructions problem then + [] + else + let (bundle, new_index) = make_bundle problem problem.resource_bounds [] index in + bundle :: (make_bundles problem new_index);; + +let bundles_to_schedule problem bundles : solution = + let nr_instructions = get_nr_instructions problem in + let schedule = Array.make (nr_instructions+1) (nr_instructions+4) in + let time = ref 0 in + List.iter (fun bundle -> + begin + List.iter (fun i -> + schedule.(i) <- !time + ) bundle; + time := !time + 1 + end + ) bundles; schedule;; + +let greedy_scheduler (problem : problem) : solution option = + let bundles = make_bundles problem 0 in + Some (bundles_to_schedule problem bundles);; + +(* alternate implementation +let swap_array_elements a i j = + let x = a.(i) in + a.(i) <- a.(j); + a.(j) <- x;; + +let array_reverse_slice a first last = + let i = ref first and j = ref last in + while i < j + do + swap_array_elements a !i !j; + incr i; + decr j + done;; + +let array_reverse a = + let a' = Array.copy a in + array_reverse_slice a' 0 ((Array.length a)-1); + a';; + *) + +(* unneeded +let array_reverse a = + let n=Array.length a in + Array.init n (fun i -> a.(n-1-i));; + *) + +let reverse_constraint nr_instructions ctr = + { instr_to = nr_instructions -ctr.instr_from; + instr_from = nr_instructions - ctr.instr_to; + latency = ctr.latency };; + +(* unneeded +let rec list_map_filter f = function + | [] -> [] + | h::t -> + (match f h with + | None -> list_map_filter f t + | Some x -> x :: (list_map_filter f t));; + *) + +let reverse_problem problem = + let nr_instructions = get_nr_instructions problem in + { + max_latency = problem.max_latency; + resource_bounds = problem.resource_bounds; + instruction_usages = Array.init (nr_instructions + 1) + (fun i -> + if i=0 + then Array.map (fun _ -> 0) problem.resource_bounds else problem.instruction_usages.(nr_instructions - i)); + latency_constraints = List.map (reverse_constraint nr_instructions) + problem.latency_constraints + };; + +let max_scheduled_time solution = + let time = ref (-1) in + for i = 0 to ((Array.length solution) - 2) + do + time := max !time solution.(i) + done; + !time;; + +(* +let recompute_makespan problem solution = + let n = (Array.length solution) - 1 and ms = ref 0 in + List.iter (fun cstr -> + if cstr.instr_to = n + then ms := max !ms (solution.(cstr.instr_from) + cstr.latency) + ) problem.latency_constraints; + !ms;; + *) + +let schedule_reversed (scheduler : problem -> solution option) + (problem : problem) = + match scheduler (reverse_problem problem) with + | None -> None + | Some solution -> + let nr_instructions = get_nr_instructions problem in + let makespan = max_scheduled_time solution in + let ret = Array.init (nr_instructions + 1) + (fun i -> makespan-solution.(nr_instructions-i)) in + ret.(nr_instructions) <- max ((max_scheduled_time ret) + 1) + (ret.(nr_instructions)); + Some ret;; + +(** Schedule the problem using a greedy list scheduling algorithm, from the end. *) +let reverse_list_scheduler = schedule_reversed list_scheduler;; + +let check_problem problem = + (if (Array.length problem.instruction_usages) < 1 + then failwith "length(problem.instruction_usages) < 1");; + +let validated_scheduler (scheduler : problem -> solution option) + (problem : problem) = + check_problem problem; + match scheduler problem with + | None -> None + | (Some solution) as ret -> check_schedule problem solution; ret;; + +let get_max_latency solution = + solution.((Array.length solution)-1);; + +let show_date_ranges problem = + let deadline = problem.max_latency in + assert(deadline >= 0); + let successors = get_successors problem + and predecessors = get_predecessors problem in + let earliest_dates : int array = get_earliest_dates predecessors + and latest_dates : int array = get_latest_dates deadline successors in + assert ((Array.length earliest_dates) = + (Array.length latest_dates)); + Array.iteri (fun i early -> + let late = latest_dates.(i) in + Printf.printf "t[%d] in %d..%d\n" i early late) + earliest_dates;; + +type pseudo_boolean_problem_type = + | SATISFIABILITY + | OPTIMIZATION;; + +type pseudo_boolean_mapper = { + mapper_pb_type : pseudo_boolean_problem_type; + mapper_nr_instructions : int; + mapper_nr_pb_variables : int; + mapper_earliest_dates : int array; + mapper_latest_dates : int array; + mapper_var_offsets : int array; + mapper_final_predecessors : (int * int) list +};; + +(* Latency constraints are: + presence of instr-to at each t <= sum of presences of instr-from at compatible times + + if reverse_encoding + presence of instr-from at each t <= sum of presences of instr-to at compatible times *) + +(* Experiments show reverse_encoding=true multiplies time by 2 in sat4j + without making hard instances easier *) +let direct_encoding = false +and reverse_encoding = false +and delta_encoding = true + +let pseudo_boolean_print_problem channel problem pb_type = + let deadline = problem.max_latency in + assert (deadline > 0); + let nr_instructions = get_nr_instructions problem + and nr_resources = get_nr_resources problem + and successors = get_successors problem + and predecessors = get_predecessors problem in + let earliest_dates = get_earliest_dates predecessors + and latest_dates = get_latest_dates deadline successors in + let var_offsets = Array.make + (match pb_type with + | OPTIMIZATION -> nr_instructions+1 + | SATISFIABILITY -> nr_instructions) 0 in + let nr_pb_variables = + (let nr = ref 0 in + for i=0 to (match pb_type with + | OPTIMIZATION -> nr_instructions + | SATISFIABILITY -> nr_instructions-1) + do + var_offsets.(i) <- !nr; + nr := !nr + latest_dates.(i) - earliest_dates.(i) + 1 + done; + !nr) + and nr_pb_constraints = + (match pb_type with + | OPTIMIZATION -> nr_instructions+1 + | SATISFIABILITY -> nr_instructions) + + + (let count = ref 0 in + for t=0 to deadline-1 + do + for j=0 to nr_resources-1 + do + try + for i=0 to nr_instructions-1 + do + let usage = problem.instruction_usages.(i).(j) in + if t >= earliest_dates.(i) && t <= latest_dates.(i) + && usage > 0 then raise Exit + done + with Exit -> incr count + done + done; + !count) + + + (let count=ref 0 in + List.iter + (fun ctr -> + if ctr.instr_to < nr_instructions + then count := !count + 1 + latest_dates.(ctr.instr_to) + - earliest_dates.(ctr.instr_to) + + (if reverse_encoding + then 1 + latest_dates.(ctr.instr_from) + - earliest_dates.(ctr.instr_from) + else 0) + ) + problem.latency_constraints; + !count) + + + (match pb_type with + | OPTIMIZATION -> (1 + deadline - earliest_dates.(nr_instructions)) * nr_instructions + | SATISFIABILITY -> 0) + and measured_nr_constraints = ref 0 in + + let pb_var i t = + assert(t >= earliest_dates.(i)); + assert(t <= latest_dates.(i)); + let v = 1+var_offsets.(i)+t-earliest_dates.(i) in + assert(v <= nr_pb_variables); + Printf.sprintf "x%d" v in + + let end_constraint () = + begin + output_string channel ";\n"; + incr measured_nr_constraints + end in + + let gen_latency_constraint i_to i_from latency t_to = + Printf.fprintf channel "* t[%d] - t[%d] >= %d when t[%d]=%d\n" + i_to i_from latency i_to t_to; + for t_from=earliest_dates.(i_from) to + int_min latest_dates.(i_from) (t_to - latency) + do + Printf.fprintf channel "+1 %s " (pb_var i_from t_from) + done; + Printf.fprintf channel "-1 %s " (pb_var i_to t_to); + Printf.fprintf channel ">= 0"; + end_constraint() + + and gen_dual_latency_constraint i_to i_from latency t_from = + Printf.fprintf channel "* t[%d] - t[%d] >= %d when t[%d]=%d\n" + i_to i_from latency i_to t_from; + for t_to=int_max earliest_dates.(i_to) (t_from + latency) + to latest_dates.(i_to) + do + Printf.fprintf channel "+1 %s " (pb_var i_to t_to) + done; + Printf.fprintf channel "-1 %s " (pb_var i_from t_from); + Printf.fprintf channel ">= 0"; + end_constraint() + in + + Printf.fprintf channel "* #variable= %d #constraint= %d\n" nr_pb_variables nr_pb_constraints; + Printf.fprintf channel "* nr_instructions=%d deadline=%d\n" nr_instructions deadline; + begin + match pb_type with + | SATISFIABILITY -> () + | OPTIMIZATION -> + output_string channel "min:"; + for t=earliest_dates.(nr_instructions) to deadline + do + Printf.fprintf channel " %+d %s" t (pb_var nr_instructions t) + done; + output_string channel ";\n"; + end; + for i=0 to (match pb_type with + | OPTIMIZATION -> nr_instructions + | SATISFIABILITY -> nr_instructions-1) + do + let early = earliest_dates.(i) and late= latest_dates.(i) in + Printf.fprintf channel "* t[%d] in %d..%d\n" i early late; + for t=early to late + do + Printf.fprintf channel "+1 %s " (pb_var i t) + done; + Printf.fprintf channel "= 1"; + end_constraint() + done; + + for t=0 to deadline-1 + do + for j=0 to nr_resources-1 + do + let bound = problem.resource_bounds.(j) + and coeffs = ref [] in + for i=0 to nr_instructions-1 + do + let usage = problem.instruction_usages.(i).(j) in + if t >= earliest_dates.(i) && t <= latest_dates.(i) + && usage > 0 + then coeffs := (i, usage) :: !coeffs + done; + if !coeffs <> [] then + begin + Printf.fprintf channel "* resource #%d at t=%d <= %d\n" j t bound; + List.iter (fun (i, usage) -> + Printf.fprintf channel "%+d %s " (-usage) (pb_var i t)) !coeffs; + Printf.fprintf channel ">= %d" (-bound); + end_constraint(); + end + done + done; + + List.iter + (fun ctr -> + if ctr.instr_to < nr_instructions then + begin + for t_to=earliest_dates.(ctr.instr_to) to latest_dates.(ctr.instr_to) + do + gen_latency_constraint ctr.instr_to ctr.instr_from ctr.latency t_to + done; + if reverse_encoding + then + for t_from=earliest_dates.(ctr.instr_from) to latest_dates.(ctr.instr_from) + do + gen_dual_latency_constraint ctr.instr_to ctr.instr_from ctr.latency t_from + done + end + ) problem.latency_constraints; + + begin + match pb_type with + | SATISFIABILITY -> () + | OPTIMIZATION -> + let final_latencies = Array.make nr_instructions 1 in + List.iter (fun (i, latency) -> + final_latencies.(i) <- int_max final_latencies.(i) latency) + predecessors.(nr_instructions); + for t_to=earliest_dates.(nr_instructions) to deadline + do + for i_from = 0 to nr_instructions -1 + do + gen_latency_constraint nr_instructions i_from final_latencies.(i_from) t_to + done + done + end; + assert (!measured_nr_constraints = nr_pb_constraints); + { + mapper_pb_type = pb_type; + mapper_nr_instructions = nr_instructions; + mapper_nr_pb_variables = nr_pb_variables; + mapper_earliest_dates = earliest_dates; + mapper_latest_dates = latest_dates; + mapper_var_offsets = var_offsets; + mapper_final_predecessors = predecessors.(nr_instructions) + };; + +type pb_answer = + | Positive + | Negative + | Unknown + +let line_to_pb_solution sol line nr_pb_variables = + let assign s v = + begin + let i = int_of_string s in + sol.(i-1) <- v + end in + List.iter + begin + function "" -> () + | item -> + (match String.get item 0 with + | '+' -> + assert ((String.length item) >= 3); + assert ((String.get item 1) = 'x'); + assign (String.sub item 2 ((String.length item)-2)) Positive + | '-' -> + assert ((String.length item) >= 3); + assert ((String.get item 1) = 'x'); + assign (String.sub item 2 ((String.length item)-2)) Negative + | 'x' -> + assert ((String.length item) >= 2); + assign (String.sub item 1 ((String.length item)-1)) Positive + | _ -> failwith "syntax error in pseudo Boolean solution: epected + - or x" + ) + end + (String.split_on_char ' ' (String.sub line 2 ((String.length line)-2)));; + +let pb_solution_to_schedule mapper pb_solution = + Array.mapi (fun i offset -> + let first = mapper.mapper_earliest_dates.(i) + and last = mapper.mapper_latest_dates.(i) + and time = ref (-1) in + for t=first to last + do + match pb_solution.(t - first + offset) with + | Positive -> + (if !time = -1 + then time:=t + else failwith "duplicate time in pseudo boolean solution") + | Negative -> () + | Unknown -> failwith "unknown value in pseudo boolean solution" + done; + (if !time = -1 + then failwith "no time in pseudo boolean solution"); + !time + ) mapper.mapper_var_offsets;; + +let pseudo_boolean_read_solution mapper channel = + let optimum = ref (-1) + and optimum_found = ref false + and solution = Array.make mapper.mapper_nr_pb_variables Unknown in + try + while true do + match input_line channel with + | "" -> () + | line -> + begin + match String.get line 0 with + | 'c' -> () + | 'o' -> + assert ((String.length line) >= 2); + assert ((String.get line 1) = ' '); + optimum := int_of_string (String.sub line 2 ((String.length line)-2)) + | 's' -> (match line with + | "s OPTIMUM FOUND" -> optimum_found := true + | "s SATISFIABLE" -> () + | "s UNSATISFIABLE" -> close_in channel; + raise Unschedulable + | _ -> failwith line) + | 'v' -> line_to_pb_solution solution line mapper.mapper_nr_pb_variables + | x -> Printf.printf "unknown: %s\n" line + end + done; + assert false + with End_of_file -> + close_in channel; + begin + let sol = pb_solution_to_schedule mapper solution in + sol + end;; + +let recompute_max_latency mapper solution = + let maxi = ref (-1) in + for i=0 to (mapper.mapper_nr_instructions-1) + do + maxi := int_max !maxi (1+solution.(i)) + done; + List.iter (fun (i, latency) -> + maxi := int_max !maxi (solution.(i) + latency)) mapper.mapper_final_predecessors; + !maxi;; + +let adjust_check_solution mapper solution = + match mapper.mapper_pb_type with + | OPTIMIZATION -> + let max_latency = recompute_max_latency mapper solution in + assert (max_latency = solution.(mapper.mapper_nr_instructions)); + solution + | SATISFIABILITY -> + let max_latency = recompute_max_latency mapper solution in + Array.init (mapper.mapper_nr_instructions+1) + (fun i -> if i < mapper.mapper_nr_instructions + then solution.(i) + else max_latency);; + +(* let pseudo_boolean_solver = ref "/local/monniaux/progs/naps/naps" *) +(* let pseudo_boolean_solver = ref "/local/monniaux/packages/sat4j/org.sat4j.pb.jar CuttingPlanes" *) + +(* let pseudo_boolean_solver = ref "java -jar /usr/share/java/org.sat4j.pb.jar CuttingPlanes" *) +(* let pseudo_boolean_solver = ref "java -jar /usr/share/java/org.sat4j.pb.jar" *) +(* let pseudo_boolean_solver = ref "clasp" *) +(* let pseudo_boolean_solver = ref "/home/monniaux/progs/CP/open-wbo/open-wbo_static -formula=1" *) +(* let pseudo_boolean_solver = ref "/home/monniaux/progs/CP/naps/naps" *) +(* let pseudo_boolean_solver = ref "/home/monniaux/progs/CP/minisatp/build/release/bin/minisatp" *) +(* let pseudo_boolean_solver = ref "java -jar sat4j-pb.jar CuttingPlanesStar" *) +let pseudo_boolean_solver = ref "pb_solver" + +let pseudo_boolean_scheduler pb_type problem = + try + let filename_in = "problem.opb" in + (* needed only if not using stdout and filename_out = "problem.sol" *) + let mapper = + with_out_channel (open_out filename_in) + (fun opb_problem -> + pseudo_boolean_print_problem opb_problem problem pb_type) in + Some (with_in_channel + (Unix.open_process_in (!pseudo_boolean_solver ^ " " ^ filename_in)) + (fun opb_solution -> adjust_check_solution mapper (pseudo_boolean_read_solution mapper opb_solution))) + with + | Unschedulable -> None;; + +let rec reoptimizing_scheduler (scheduler : scheduler) (previous_solution : solution) (problem : problem) = + if (get_max_latency previous_solution)>1 then + begin + Printf.printf "reoptimizing < %d\n" (get_max_latency previous_solution); + flush stdout; + match scheduler + { problem with max_latency = (get_max_latency previous_solution)-1 } + with + | None -> previous_solution + | Some solution -> reoptimizing_scheduler scheduler solution problem + end + else previous_solution;; + +let smt_var i = Printf.sprintf "t%d" i + +let is_resource_used problem j = + try + Array.iter (fun usages -> + if usages.(j) > 0 + then raise Exit) problem.instruction_usages; + false + with Exit -> true;; + +let smt_use_quantifiers = false + +let smt_print_problem channel problem = + let nr_instructions = get_nr_instructions problem in + let gen_smt_resource_constraint time j = + output_string channel "(<= (+"; + Array.iteri + (fun i usages -> + let usage=usages.(j) in + if usage > 0 + then Printf.fprintf channel " (ite (= %s %s) %d 0)" + time (smt_var i) usage) + problem.instruction_usages; + Printf.fprintf channel ") %d)" problem.resource_bounds.(j) + in + output_string channel "(set-option :produce-models true)\n"; + for i=0 to nr_instructions + do + Printf.fprintf channel "(declare-const %s Int)\n" (smt_var i); + Printf.fprintf channel "(assert (>= %s 0))\n" (smt_var i) + done; + for i=0 to nr_instructions-1 + do + Printf.fprintf channel "(assert (< %s %s))\n" + (smt_var i) (smt_var nr_instructions) + done; + (if problem.max_latency > 0 + then Printf.fprintf channel "(assert (<= %s %d))\n" + (smt_var nr_instructions) problem.max_latency); + List.iter (fun ctr -> + Printf.fprintf channel "(assert (>= (- %s %s) %d))\n" + (smt_var ctr.instr_to) + (smt_var ctr.instr_from) + ctr.latency) problem.latency_constraints; + for j=0 to (Array.length problem.resource_bounds)-1 + do + if is_resource_used problem j + then + begin + if smt_use_quantifiers + then + begin + Printf.fprintf channel + "; resource #%d <= %d\n(assert (forall ((t Int)) " + j problem.resource_bounds.(j); + gen_smt_resource_constraint "t" j; + output_string channel "))\n" + end + else + begin + (if problem.max_latency < 0 + then failwith "quantifier explosion needs max latency"); + for t=0 to problem.max_latency + do + Printf.fprintf channel + "; resource #%d <= %d at t=%d\n(assert " + j problem.resource_bounds.(j) t; + gen_smt_resource_constraint (string_of_int t) j; + output_string channel ")\n" + done + end + end + done; + output_string channel "(check-sat)(get-model)\n";; + + +let ilp_print_problem channel problem pb_type = + let deadline = problem.max_latency in + assert (deadline > 0); + let nr_instructions = get_nr_instructions problem + and nr_resources = get_nr_resources problem + and successors = get_successors problem + and predecessors = get_predecessors problem in + let earliest_dates = get_earliest_dates predecessors + and latest_dates = get_latest_dates deadline successors in + + let pb_var i t = + Printf.sprintf "x%d_%d" i t in + + let gen_latency_constraint i_to i_from latency t_to = + Printf.fprintf channel "\\ t[%d] - t[%d] >= %d when t[%d]=%d\n" + i_to i_from latency i_to t_to; + Printf.fprintf channel "c_%d_%d_%d_%d: " + i_to i_from latency t_to; + for t_from=earliest_dates.(i_from) to + int_min latest_dates.(i_from) (t_to - latency) + do + Printf.fprintf channel "+1 %s " (pb_var i_from t_from) + done; + Printf.fprintf channel "-1 %s " (pb_var i_to t_to); + output_string channel ">= 0\n" + + and gen_dual_latency_constraint i_to i_from latency t_from = + Printf.fprintf channel "\\ t[%d] - t[%d] >= %d when t[%d]=%d\n" + i_to i_from latency i_to t_from; + Printf.fprintf channel "d_%d_%d_%d_%d: " + i_to i_from latency t_from; + for t_to=int_max earliest_dates.(i_to) (t_from + latency) + to latest_dates.(i_to) + do + Printf.fprintf channel "+1 %s " (pb_var i_to t_to) + done; + Printf.fprintf channel "-1 %s " (pb_var i_from t_from); + Printf.fprintf channel ">= 0\n" + + and gen_delta_constraint i_from i_to latency = + if delta_encoding + then Printf.fprintf channel "l_%d_%d_%d: +1 t%d -1 t%d >= %d\n" + i_from i_to latency i_to i_from latency + + in + + Printf.fprintf channel "\\ nr_instructions=%d deadline=%d\n" nr_instructions deadline; + begin + match pb_type with + | SATISFIABILITY -> output_string channel "Minimize dummy: 0\n" + | OPTIMIZATION -> + Printf.fprintf channel "Minimize\nmakespan: t%d\n" nr_instructions + end; + output_string channel "Subject To\n"; + for i=0 to (match pb_type with + | OPTIMIZATION -> nr_instructions + | SATISFIABILITY -> nr_instructions-1) + do + let early = earliest_dates.(i) and late= latest_dates.(i) in + Printf.fprintf channel "\\ t[%d] in %d..%d\ntimes%d: " i early late i; + for t=early to late + do + Printf.fprintf channel "+1 %s " (pb_var i t) + done; + Printf.fprintf channel "= 1\n" + done; + + for t=0 to deadline-1 + do + for j=0 to nr_resources-1 + do + let bound = problem.resource_bounds.(j) + and coeffs = ref [] in + for i=0 to nr_instructions-1 + do + let usage = problem.instruction_usages.(i).(j) in + if t >= earliest_dates.(i) && t <= latest_dates.(i) + && usage > 0 + then coeffs := (i, usage) :: !coeffs + done; + if !coeffs <> [] then + begin + Printf.fprintf channel "\\ resource #%d at t=%d <= %d\nr%d_%d: " j t bound j t; + List.iter (fun (i, usage) -> + Printf.fprintf channel "%+d %s " (-usage) (pb_var i t)) !coeffs; + Printf.fprintf channel ">= %d\n" (-bound) + end + done + done; + + List.iter + (fun ctr -> + if ctr.instr_to < nr_instructions then + begin + gen_delta_constraint ctr.instr_from ctr.instr_to ctr.latency; + begin + if direct_encoding + then + for t_to=earliest_dates.(ctr.instr_to) to latest_dates.(ctr.instr_to) + do + gen_latency_constraint ctr.instr_to ctr.instr_from ctr.latency t_to + done + end; + begin + if reverse_encoding + then + for t_from=earliest_dates.(ctr.instr_from) to latest_dates.(ctr.instr_from) + do + gen_dual_latency_constraint ctr.instr_to ctr.instr_from ctr.latency t_from + done + end + end + ) problem.latency_constraints; + + begin + match pb_type with + | SATISFIABILITY -> () + | OPTIMIZATION -> + let final_latencies = Array.make nr_instructions 1 in + List.iter (fun (i, latency) -> + final_latencies.(i) <- int_max final_latencies.(i) latency) + predecessors.(nr_instructions); + for i_from = 0 to nr_instructions -1 + do + gen_delta_constraint i_from nr_instructions final_latencies.(i_from) + done; + for t_to=earliest_dates.(nr_instructions) to deadline + do + for i_from = 0 to nr_instructions -1 + do + gen_latency_constraint nr_instructions i_from final_latencies.(i_from) t_to + done + done + end; + for i=0 to (match pb_type with + | OPTIMIZATION -> nr_instructions + | SATISFIABILITY -> nr_instructions-1) + do + Printf.fprintf channel "ct%d : -1 t%d" i i; + let early = earliest_dates.(i) and late= latest_dates.(i) in + for t=early to late do + Printf.fprintf channel " +%d %s" t (pb_var i t) + done; + output_string channel " = 0\n" + done; + output_string channel "Bounds\n"; + for i=0 to (match pb_type with + | OPTIMIZATION -> nr_instructions + | SATISFIABILITY -> nr_instructions-1) + do + let early = earliest_dates.(i) and late= latest_dates.(i) in + begin + Printf.fprintf channel "%d <= t%d <= %d\n" early i late; + if true then + for t=early to late do + Printf.fprintf channel "0 <= %s <= 1\n" (pb_var i t) + done + end + done; + output_string channel "Integer\n"; + for i=0 to (match pb_type with + | OPTIMIZATION -> nr_instructions + | SATISFIABILITY -> nr_instructions-1) + do + Printf.fprintf channel "t%d " i + done; + output_string channel "\nBinary\n"; + for i=0 to (match pb_type with + | OPTIMIZATION -> nr_instructions + | SATISFIABILITY -> nr_instructions-1) + do + let early = earliest_dates.(i) and late= latest_dates.(i) in + for t=early to late do + output_string channel (pb_var i t); + output_string channel " " + done; + output_string channel "\n" + done; + output_string channel "End\n"; + { + mapper_pb_type = pb_type; + mapper_nr_instructions = nr_instructions; + mapper_nr_pb_variables = 0; + mapper_earliest_dates = earliest_dates; + mapper_latest_dates = latest_dates; + mapper_var_offsets = [| |]; + mapper_final_predecessors = predecessors.(nr_instructions) + };; + +(* Guess what? Cplex sometimes outputs 11.000000004 instead of integer 11 *) + +let positive_float_round x = truncate (x +. 0.5) + +let float_round (x : float) : int = + if x > 0.0 + then positive_float_round x + else - (positive_float_round (-. x)) + +let rounded_int_of_string x = float_round (float_of_string x) + +let ilp_read_solution mapper channel = + let times = Array.make + (match mapper.mapper_pb_type with + | OPTIMIZATION -> 1+mapper.mapper_nr_instructions + | SATISFIABILITY -> mapper.mapper_nr_instructions) (-1) in + try + while true do + let line = input_line channel in + ( if (String.length line) < 3 + then failwith (Printf.sprintf "bad ilp output: length(line) < 3: %s" line)); + match String.get line 0 with + | 'x' -> () + | 't' -> let space = + try String.index line ' ' + with Not_found -> + failwith "bad ilp output: no t variable number" + in + let tnumber = + try int_of_string (String.sub line 1 (space-1)) + with Failure _ -> + failwith "bad ilp output: not a variable number" + in + (if tnumber < 0 || tnumber >= (Array.length times) + then failwith (Printf.sprintf "bad ilp output: not a correct variable number: %d (%d)" tnumber (Array.length times))); + let value = + let s = String.sub line (space+1) ((String.length line)-space-1) in + try rounded_int_of_string s + with Failure _ -> + failwith (Printf.sprintf "bad ilp output: not a time number (%s)" s) + in + (if value < 0 + then failwith "bad ilp output: negative time"); + times.(tnumber) <- value + | '#' -> () + | '0' -> () + | _ -> failwith (Printf.sprintf "bad ilp output: bad variable initial, line = %s" line) + done; + assert false + with End_of_file -> + Array.iteri (fun i x -> + if i<(Array.length times)-1 + && x<0 then raise Unschedulable) times; + times;; + +let ilp_solver = ref "ilp_solver" + +let problem_nr = ref 0 + +let ilp_scheduler pb_type problem = + try + let filename_in = Printf.sprintf "problem%05d.lp" !problem_nr + and filename_out = Printf.sprintf "problem%05d.sol" !problem_nr in + incr problem_nr; + let mapper = with_out_channel (open_out filename_in) + (fun opb_problem -> ilp_print_problem opb_problem problem pb_type) in + + begin + match Unix.system (!ilp_solver ^ " " ^ filename_in ^ " " ^ filename_out) with + | Unix.WEXITED 0 -> + Some (with_in_channel + (open_in filename_out) + (fun opb_solution -> + adjust_check_solution mapper + (ilp_read_solution mapper opb_solution))) + | Unix.WEXITED _ -> failwith "failed to start ilp solver" + | _ -> None + end + with + | Unschedulable -> None;; + +let current_utime_all () = + let t = Unix.times() in + t.Unix.tms_cutime +. t.Unix.tms_utime;; + +let utime_all_fn fn arg = + let utime_start = current_utime_all () in + let output = fn arg in + let utime_end = current_utime_all () in + (output, utime_end -. utime_start);; + +let cascaded_scheduler (problem : problem) = + let (some_initial_solution, list_scheduler_time) = + utime_all_fn (validated_scheduler list_scheduler) problem in + match some_initial_solution with + | None -> None + | Some initial_solution -> + let (solution, reoptimizing_time) = utime_all_fn (reoptimizing_scheduler (validated_scheduler (ilp_scheduler SATISFIABILITY)) initial_solution) problem in + begin + let latency2 = get_max_latency solution + and latency1 = get_max_latency initial_solution in + Printf.printf "postpass %s: %d, %d, %d, %g, %g\n" + (if latency2 < latency1 then "REOPTIMIZED" else "unchanged") + (get_nr_instructions problem) + latency1 latency2 + list_scheduler_time reoptimizing_time; + flush stdout + end; + Some solution;; + +let scheduler_by_name name = + match name with + | "ilp" -> validated_scheduler cascaded_scheduler + | "list" -> validated_scheduler list_scheduler + | "revlist" -> validated_scheduler reverse_list_scheduler + | "greedy" -> greedy_scheduler + | s -> failwith ("unknown scheduler: " ^ s);; diff --git a/aarch64/InstructionScheduler.mli b/aarch64/InstructionScheduler.mli new file mode 100644 index 00000000..85e2a5c6 --- /dev/null +++ b/aarch64/InstructionScheduler.mli @@ -0,0 +1,113 @@ +(** Schedule instructions on a synchronized pipeline +by David Monniaux, CNRS, VERIMAG *) + +(** A latency constraint: instruction number [instr_to] should be scheduled at least [latency] clock ticks before [instr_from]. + +It is possible to specify [latency]=0, meaning that [instr_to] can be scheduled at the same clock tick as [instr_from], but not before. + +[instr_to] can be the special value equal to the number of instructions, meaning that it refers to the final output latency. *) +type latency_constraint = { + instr_from : int; + instr_to : int; + latency : int; + } + +(** A scheduling problem. + +In addition to the latency constraints, the resource constraints should be satisfied: at every clock tick, the sum of vectors of resources used by the instructions scheduled at that tick does not exceed the resource bounds. +*) +type problem = { + max_latency : int; + (** An optional maximal total latency of the problem, after which the problem is deemed not schedulable. -1 means there should be no maximum. *) + + resource_bounds : int array; + (** An array of number of units available indexed by the kind of resources to be allocated. It can be empty, in which case the problem is scheduling without resource constraints. *) + + instruction_usages: int array array; + (** At index {i i} the vector of resources used by instruction number {i i}. It must be the same length as [resource_bounds] *) + + latency_constraints : latency_constraint list + (** The latency constraints that must be satisfied *) + };; + +(** Print problem for human readability. *) +val print_problem : out_channel -> problem -> unit;; + +(** Scheduling solution. For {i n} instructions to schedule, and 0≤{i i}<{i n}, position {i i} contains the time to which instruction {i i} should be scheduled. Position {i n} contains the final output latency. *) +type solution = int array + +(** A scheduling algorithm. +The return value [Some x] is a solution [x]. +[None] means that scheduling failed. *) +type scheduler = problem -> solution option;; + +(* DISABLED +(** Schedule the problem optimally by constraint solving using the Gecode solver. *) +external gecode_scheduler : problem -> solution option + = "caml_gecode_schedule_instr" + *) + +(** Get the number the last scheduling time used for an instruction in a solution. +@return The last clock tick used *) +val maximum_slot_used : solution -> int + +(** Validate that a solution is truly a solution of a scheduling problem. +@raise Failure if validation fails *) +val check_schedule : problem -> solution -> unit + +(** Schedule the problem using a greedy list scheduling algorithm, from the start. +The first (according to instruction ordering) instruction that is ready (according to the latency constraints) is scheduled at the current clock tick. +Once a clock tick is full go to the next. + +@return [Some solution] when a solution is found, [None] if not. *) +val list_scheduler : problem -> solution option + +(** Schedule the problem using the order of instructions without any reordering *) +val greedy_scheduler : problem -> solution option + +(** Schedule a problem using a scheduler applied in the opposite direction, e.g. for list scheduling from the end instead of the start. BUGGY *) +val schedule_reversed : scheduler -> problem -> int array option + +(** Schedule a problem from the end using a list scheduler. BUGGY *) +val reverse_list_scheduler : problem -> int array option + +(** Check that a problem is well-formed. +@raise Failure if validation fails *) +val check_problem : problem -> unit + +(** Apply a scheduler and validate the result against the input problem. +@return The solution found +@raise Failure if validation fails *) +val validated_scheduler : scheduler -> problem -> solution option;; + +(** Get max latency from solution +@return Max latency *) +val get_max_latency : solution -> int;; + +(** Get the length of a maximal critical path +@return Max length *) +val maximum_critical_path : problem -> int;; + +(** Apply line scheduler then advanced solver +@return A solution if found *) +val cascaded_scheduler : problem -> solution option;; + +val show_date_ranges : problem -> unit;; + +type pseudo_boolean_problem_type = + | SATISFIABILITY + | OPTIMIZATION;; + +type pseudo_boolean_mapper +val pseudo_boolean_print_problem : out_channel -> problem -> pseudo_boolean_problem_type -> pseudo_boolean_mapper;; +val pseudo_boolean_read_solution : pseudo_boolean_mapper -> in_channel -> solution;; +val pseudo_boolean_scheduler : pseudo_boolean_problem_type -> problem -> solution option;; + +val smt_print_problem : out_channel -> problem -> unit;; + +val ilp_print_problem : out_channel -> problem -> pseudo_boolean_problem_type -> pseudo_boolean_mapper;; + +val ilp_scheduler : pseudo_boolean_problem_type -> problem -> solution option;; + +(** Schedule a problem using a scheduler given by a string name *) +val scheduler_by_name : string -> problem -> int array option;; diff --git a/aarch64/OpWeightsAsm.ml b/aarch64/OpWeightsAsm.ml new file mode 100644 index 00000000..c1d0583a --- /dev/null +++ b/aarch64/OpWeightsAsm.ml @@ -0,0 +1,377 @@ +(* *************************************************************) +(* *) +(* The Compcert verified compiler *) +(* *) +(* David Monniaux CNRS, VERIMAG *) +(* Léo Gourdin UGA, VERIMAG *) +(* *) +(* Copyright Kalray. Copyright VERIMAG. All rights reserved. *) +(* This file is distributed under the terms of the INRIA *) +(* Non-Commercial License Agreement. *) +(* *) +(* *************************************************************) + +(*type called_function = (Registers.reg, AST.ident) Datatypes.sum*) + +type real_instruction = + | Add + | Adr + | Adrp + | And + | Asr + | B + | Bic + | Bl + | Blr + | Br + | Cbnz + | Cbz + | Cls + | Clz + | Cmn + | Cmp + | Csel + | Cset + | Eon + | Eor + | Fabs + | Fadd + | Fcmp + | Fcsel + | Fcvt + | Fcvtzs + | Fcvtzu + | Fdiv + | Fmadd + | Fmov + | Fmsub + | Fmul + | Fnmadd + | Fnmul + | Fnmsub + | Fneg + | Fsqrt + | Fsub + | Ldaxr + | Ldp + | Ldr + | Ldrb + | Ldrh + | Ldrsb + | Ldrsh + | Ldrsw + | Lr + | Lsl + | Lsr + | Madd + | Mov + | Movk + | Movn + | Movz + | Msub + | Nop + | Orn + | Orr + | Ret + | Rev + | Rev16 + | Ror + | Sbfiz + | Sbfx + | Scvtf + | Sdiv + | Smulh + | Stlxr + | Stp + | Str + | Strb + | Strh + | Sub + | Sxtb + | Sxth + | Sxtw + | Tbnz + | Tbz + | Tst + | Ubfiz + | Ubfx + | Ucvtf + | Udiv + | Umulh + | Uxtb + | Uxth + | Uxtw + | Uxtx + (* Pseudo instr *) + | Btbl + | Allocframe + | Freeframe + | Builtin + | Cvtx2w + +type opweights = { + pipelined_resource_bounds : int array; + nr_non_pipelined_units : int; + latency_of_op : real_instruction -> int -> int; + resources_of_op : real_instruction -> int -> int array; + (*non_pipelined_resources_of_op : Op.operation -> int -> int array;*) + (*latency_of_load : AST.trapping_mode -> AST.memory_chunk -> Op.addressing -> int -> int;*) + (*resources_of_load : AST.trapping_mode -> AST.memory_chunk -> Op.addressing -> int -> int array;*) + (*resources_of_store : AST.memory_chunk -> Op.addressing -> int -> int array;*) + (*resources_of_cond : Op.condition -> int -> int array;*) + (*latency_of_call : AST.signature -> called_function -> int;*) + (*resources_of_call : AST.signature -> called_function -> int array;*) + (*resources_of_builtin : AST.external_function -> int array*) +} + +module Cortex_A53 = struct + let resource_bounds = [| 2; 2; 1; 1 |] + + (* instr ; ALU ; MAC; LSU *) + let nr_non_pipelined_units = 1 + + let latency_of_op (i : real_instruction) (nargs : int) = + match i with + | Add -> 1 + | Adr -> 1 + | Adrp -> 1 (* XXX *) + | And -> 1 + | Asr -> 2 + | B -> 1 + | Bic -> 1 + | Bl -> 1 + | Blr -> 1 + | Br -> 1 + | Cbnz -> 1 + | Cbz -> 1 + | Cls -> 1 + | Clz -> 1 + | Cmn -> 6 + | Cmp -> 6 + | Csel -> 2 + | Cset -> 2 + | Eon -> 1 + | Eor -> 1 + | Fabs -> 6 + | Fadd -> 1 + | Fcmp -> 6 + | Fcsel -> 1 + | Fcvt -> 6 + | Fcvtzs -> 6 + | Fcvtzu -> 6 + | Fdiv -> 50 + | Fmadd -> 1 + | Fmov -> 1 + | Fmsub -> 1 + | Fmul -> 6 + | Fnmadd -> 1 + | Fnmul -> 1 + | Fnmsub -> 1 + | Fneg -> 6 + | Fsqrt -> 1 + | Fsub -> 6 + | Ldaxr -> 3 + | Ldp -> 3 + | Ldr -> 3 + | Ldrb -> 3 + | Ldrh -> 3 + | Ldrsb -> 3 + | Ldrsh -> 3 + | Ldrsw -> 3 + | Lr -> 3 + | Lsl -> 2 + | Lsr -> 2 + | Madd -> 4 + | Mov -> 1 (* XXX *) + | Movk -> 1 + | Movn -> 1 + | Movz -> 1 + | Msub -> 4 + | Nop -> 1 + | Orn -> 1 + | Orr -> 1 + | Ret -> 1 + | Rev -> 1 + | Rev16 -> 1 + | Ror -> 2 + | Sbfiz -> 2 (* XXX *) + | Sbfx -> 2 + | Scvtf -> 6 + | Sdiv -> 50 + | Smulh -> 4 + | Stlxr -> 2 + | Stp -> 2 + | Str -> 2 + | Strb -> 2 + | Strh -> 2 + | Sub -> 1 + | Sxtb -> 1 + | Sxth -> 1 + | Sxtw -> 1 + | Tbnz -> 1 + | Tbz -> 1 + | Tst -> 6 + | Ubfiz -> 2 (* XXX *) + | Ubfx -> 2 + | Ucvtf -> 6 + | Udiv -> 50 + | Umulh -> 4 + | Uxtb -> 1 + | Uxth -> 1 + | Uxtw -> 1 + | Uxtx -> 1 + | Btbl -> 1 + | Allocframe -> 51 + | Freeframe -> 51 + | Builtin -> 51 + | Cvtx2w -> 51 + + let resources_of_op (i : real_instruction) (nargs : int) = + match i with + | Add -> [| 1; 1; 0; 0 |] + | Adr -> [| 1; 1; 0; 0 |] + | Adrp -> [| 1; 1; 0; 0 |] + | And -> [| 1; 1; 0; 0 |] + | Asr -> [| 1; 1; 0; 0 |] + | B -> [| 1; 1; 0; 0 |] + | Bic -> [| 1; 1; 0; 0 |] + | Bl -> [| 1; 1; 0; 0 |] + | Blr -> [| 1; 1; 0; 0 |] + | Br -> [| 1; 1; 0; 0 |] + | Cbnz -> [| 1; 1; 0; 0 |] + | Cbz -> [| 1; 1; 0; 0 |] + | Cls -> [| 1; 1; 0; 0 |] + | Clz -> [| 1; 1; 0; 0 |] + | Cmn -> [| 1; 1; 1; 0 |] + | Cmp -> [| 1; 1; 1; 0 |] + | Csel -> [| 1; 1; 1; 0 |] + | Cset -> [| 1; 1; 1; 0 |] + | Eon -> [| 1; 1; 0; 0 |] + | Eor -> [| 1; 1; 0; 0 |] + | Fabs -> [| 1; 1; 1; 0 |] + | Fadd -> [| 1; 1; 1; 0 |] + | Fcmp -> [| 1; 1; 1; 0 |] + | Fcsel -> [| 1; 1; 0; 0 |] + | Fcvt -> [| 1; 1; 1; 0 |] + | Fcvtzs -> [| 1; 1; 1; 0 |] + | Fcvtzu -> [| 1; 1; 1; 0 |] + | Fdiv -> [| 1; 1; 1; 0 |] + | Fmadd -> [| 1; 1; 0; 0 |] + | Fmov -> [| 1; 1; 0; 0 |] + | Fmsub -> [| 1; 1; 0; 0 |] + | Fmul -> [| 1; 1; 1; 0 |] + | Fnmadd -> [| 1; 1; 0; 0 |] + | Fnmul -> [| 1; 1; 0; 0 |] + | Fnmsub -> [| 1; 1; 0; 0 |] + | Fneg -> [| 1; 1; 1; 0 |] + | Fsqrt -> [| 1; 1; 0; 0 |] + | Fsub -> [| 1; 1; 1; 0 |] + | Ldaxr -> [| 1; 0; 0; 1 |] + | Ldp -> [| 1; 0; 0; 1 |] + | Ldr -> [| 1; 0; 0; 1 |] + | Ldrb -> [| 1; 0; 0; 1 |] + | Ldrh -> [| 1; 0; 0; 1 |] + | Ldrsb -> [| 1; 0; 0; 1 |] + | Ldrsh -> [| 1; 0; 0; 1 |] + | Ldrsw -> [| 1; 0; 0; 1 |] + | Lr -> [| 1; 0; 0; 1 |] + | Lsl -> [| 1; 1; 0; 0 |] + | Lsr -> [| 1; 1; 0; 0 |] + | Madd -> [| 1; 1; 1; 0 |] + | Mov -> [| 1; 1; 0; 0 |] + | Movk -> [| 1; 1; 0; 0 |] + | Movn -> [| 1; 1; 0; 0 |] + | Movz -> [| 1; 1; 0; 0 |] + | Msub -> [| 1; 1; 1; 0 |] + | Nop -> [| 1; 1; 0; 0 |] + | Orn -> [| 1; 1; 0; 0 |] + | Orr -> [| 1; 1; 0; 0 |] + | Ret -> [| 1; 1; 0; 0 |] + | Rev -> [| 1; 1; 0; 0 |] + | Rev16 -> [| 1; 1; 0; 0 |] + | Ror -> [| 1; 1; 0; 0 |] + | Sbfiz -> [| 1; 1; 0; 0 |] + | Sbfx -> [| 1; 1; 0; 0 |] + | Scvtf -> [| 1; 1; 1; 0 |] + | Sdiv -> [| 1; 0; 0; 0 |] + | Smulh -> [| 1; 1; 0; 0 |] + | Stlxr -> [| 1; 0; 0; 1 |] + | Stp -> [| 1; 0; 0; 1 |] + | Str -> [| 1; 0; 0; 1 |] + | Strb -> [| 1; 0; 0; 1 |] + | Strh -> [| 1; 0; 0; 1 |] + | Sub -> [| 1; 1; 0; 0 |] + | Sxtb -> [| 1; 1; 0; 0 |] + | Sxth -> [| 1; 1; 0; 0 |] + | Sxtw -> [| 1; 1; 0; 0 |] + | Tbnz -> [| 1; 1; 0; 0 |] + | Tbz -> [| 1; 1; 0; 0 |] + | Tst -> [| 1; 1; 1; 0 |] + | Ubfiz -> [| 1; 1; 0; 0 |] + | Ubfx -> [| 1; 1; 0; 0 |] + | Ucvtf -> [| 1; 1; 1; 0 |] + | Udiv -> [| 1; 0; 0; 0 |] + | Umulh -> [| 1; 1; 0; 0 |] + | Uxtb -> [| 1; 1; 0; 0 |] + | Uxth -> [| 1; 1; 0; 0 |] + | Uxtw -> [| 1; 1; 0; 0 |] + | Uxtx -> [| 1; 1; 0; 0 |] + | Btbl -> [| 1; 1; 0; 0 |] + | Allocframe -> [| 1; 1; 1; 1 |] + | Freeframe -> [| 1; 1; 1; 1 |] + | Builtin -> [| 1; 1; 1; 1 |] + | Cvtx2w -> [| 1; 1; 1; 1 |] + + (*let non_pipelined_resources_of_op (op : operation) (nargs : int) = + match op with + | Odiv | Odivu -> [| 29 |] + | Odivfs -> [| 20 |] + | Odivl | Odivlu | Odivf -> [| 50 |] + | _ -> [| -1 |];; + + let resources_of_cond (cmp : condition) (nargs : int) = + (match cmp with + | Ccompf _ (* r FP comparison *) + | Cnotcompf _ (* r negation of an FP comparison *) + | Ccompfzero _ (* r comparison with 0.0 *) + | Cnotcompfzero _ (* r negation of comparison with 0.0 *) + | Ccompfs _ (* r FP comparison *) + | Cnotcompfs _ (* r negation of an FP comparison *) + | Ccompfszero _ (* r equal to 0.0 *) + | Cnotcompfszero _ (* r not equal to 0.0 *) -> + [| 1; 1; 1; 0 |] + | _ -> [| 1; 1; 0; 0 |] )*) + + let latency_of_load trap chunk _ _ = 3 + + let latency_of_call _ _ = 6 + + let resources_of_load trap chunk addressing nargs = [| 1; 0; 0; 1 |] + + let resources_of_store chunk addressing nargs = [| 1; 0; 0; 1 |] + + let resources_of_call _ _ = resource_bounds + + let resources_of_builtin _ = resource_bounds +end + +let get_opweights () : opweights = + (*match !Clflags.option_mtune with*) + (*| "cortex-a53" | "cortex-a35" | "" ->*) + { + pipelined_resource_bounds = Cortex_A53.resource_bounds; + nr_non_pipelined_units = Cortex_A53.nr_non_pipelined_units; + latency_of_op = Cortex_A53.latency_of_op; + resources_of_op = + Cortex_A53.resources_of_op + (*non_pipelined_resources_of_op = Cortex_A53.non_pipelined_resources_of_op;*) + (*latency_of_load = Cortex_A53.latency_of_load;*) + (*resources_of_load = Cortex_A53.resources_of_load;*) + (*resources_of_store = Cortex_A53.resources_of_store;*) + (*resources_of_cond = Cortex_A53.resources_of_cond;*) + (*latency_of_call = Cortex_A53.latency_of_call;*) + (*resources_of_call = Cortex_A53.resources_of_call;*) + (*resources_of_builtin = Cortex_A53.resources_of_builtin*); + } + +(*| xxx -> failwith (Printf.sprintf "unknown -mtune: %s" xxx);;*) diff --git a/aarch64/OrigAsmgen.ml b/aarch64/OrigAsmgen.ml new file mode 100644 index 00000000..1bbcf085 --- /dev/null +++ b/aarch64/OrigAsmgen.ml @@ -0,0 +1,282 @@ +(** File (more or less) extracted from the official aarch64/Asmgen.v of CompCert + +TODO: prune some definition in these files by reusing the ones of Asmblockgen that are identical... +e.g. all those which do not involve Asm.code + +**) + +open Asm +open BinInt +open BinNums +open Integers +open List0 +open Zbits + +module I = Integers.Int +module I64 = Integers.Int64 +module N = PeanoNat.Nat + +let s_ x = Datatypes.S x +let o_ = Datatypes.O + +module Automaton = + struct + type state = + | SA + | SB + | SC + | SD + | SE + | SF + | SG + | Sbad + + (** val start : state **) + + let start = + SA + + (** val next : state -> bool -> state **) + + let next s b = + match s with + | SA -> if b then SC else SB + | SB -> if b then SD else SB + | SC -> if b then SC else SE + | SD -> if b then SD else SF + | SE -> if b then SG else SE + | SF -> if b then Sbad else SF + | SG -> if b then SG else Sbad + | Sbad -> Sbad + + (** val accepting : state -> bool **) + + let accepting = function + | Sbad -> false + | _ -> true + + (** val run : nat -> state -> coq_Z -> bool **) + + let rec run len s x = + match len with + | Datatypes.O -> accepting s + | Datatypes.S len0 -> run len0 (next s (Z.odd x)) (Z.div2 x) + end + +(** val logical_imm_length : coq_Z -> bool -> nat **) + +let logical_imm_length x sixtyfour = + let test = fun n -> + Z.eqb (coq_Zzero_ext n x) (coq_Zzero_ext n (Z.shiftr x n)) + in + if (&&) sixtyfour + (Datatypes.negb + (test (Zpos (Coq_xO (Coq_xO (Coq_xO (Coq_xO (Coq_xO Coq_xH)))))))) + then s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ + (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ + (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ + o_))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) + else if Datatypes.negb (test (Zpos (Coq_xO (Coq_xO (Coq_xO (Coq_xO Coq_xH)))))) + then s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ + (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ o_))))))))))))))))))))))))))))))) + else if Datatypes.negb (test (Zpos (Coq_xO (Coq_xO (Coq_xO Coq_xH))))) + then s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ + o_))))))))))))))) + else if Datatypes.negb (test (Zpos (Coq_xO (Coq_xO Coq_xH)))) + then s_ (s_ (s_ (s_ (s_ (s_ (s_ (s_ o_))))))) + else if Datatypes.negb (test (Zpos (Coq_xO Coq_xH))) + then s_ (s_ (s_ (s_ o_))) + else s_ (s_ o_) + +(** val is_logical_imm32 : I.int -> bool **) + +let is_logical_imm32 x = + (&&) ((&&) (Datatypes.negb (I.eq x I.zero)) (Datatypes.negb (I.eq x I.mone))) + (Automaton.run (logical_imm_length (I.unsigned x) false) + Automaton.start (I.unsigned x)) + +(** val is_logical_imm64 : I64.int -> bool **) + +let is_logical_imm64 x = + (&&) ((&&) (Datatypes.negb (I64.eq x I64.zero)) (Datatypes.negb (I64.eq x I64.mone))) + (Automaton.run (logical_imm_length (I64.unsigned x) true) + Automaton.start (I64.unsigned x)) + +(** val is_arith_imm32 : I.int -> bool **) + +let is_arith_imm32 x = + (||) (I.eq x (I.zero_ext (Zpos (Coq_xO (Coq_xO (Coq_xI Coq_xH)))) x)) + (I.eq x + (I.shl + (I.zero_ext (Zpos (Coq_xO (Coq_xO (Coq_xI Coq_xH)))) + (I.shru x (I.repr (Zpos (Coq_xO (Coq_xO (Coq_xI Coq_xH))))))) + (I.repr (Zpos (Coq_xO (Coq_xO (Coq_xI Coq_xH))))))) + +(** val is_arith_imm64 : I64.int -> bool **) + +let is_arith_imm64 x = + (||) + (I64.eq x (I64.zero_ext (Zpos (Coq_xO (Coq_xO (Coq_xI Coq_xH)))) x)) + (I64.eq x + (I64.shl + (I64.zero_ext (Zpos (Coq_xO (Coq_xO (Coq_xI Coq_xH)))) + (I64.shru x (I64.repr (Zpos (Coq_xO (Coq_xO (Coq_xI Coq_xH))))))) + (I64.repr (Zpos (Coq_xO (Coq_xO (Coq_xI Coq_xH))))))) + +(** val decompose_int : nat -> coq_Z -> coq_Z -> (coq_Z * coq_Z) list **) + +let rec decompose_int n n0 p = + match n with + | Datatypes.O -> [] + | Datatypes.S n1 -> + let frag = + coq_Zzero_ext (Zpos (Coq_xO (Coq_xO (Coq_xO (Coq_xO Coq_xH))))) + (Z.shiftr n0 p) + in + if Z.eqb frag Z0 + then decompose_int n1 n0 + (Z.add p (Zpos (Coq_xO (Coq_xO (Coq_xO (Coq_xO Coq_xH)))))) + else (frag, + p) :: (decompose_int n1 + (Z.ldiff n0 + (Z.shiftl (Zpos (Coq_xI (Coq_xI (Coq_xI (Coq_xI (Coq_xI + (Coq_xI (Coq_xI (Coq_xI (Coq_xI (Coq_xI (Coq_xI + (Coq_xI (Coq_xI (Coq_xI (Coq_xI Coq_xH)))))))))))))))) + p)) + (Z.add p (Zpos (Coq_xO (Coq_xO (Coq_xO (Coq_xO Coq_xH))))))) + +(** val negate_decomposition : + (coq_Z * coq_Z) list -> (coq_Z * coq_Z) list **) + +let negate_decomposition l = + map (fun np -> + ((Z.coq_lxor (fst np) (Zpos (Coq_xI (Coq_xI (Coq_xI (Coq_xI (Coq_xI + (Coq_xI (Coq_xI (Coq_xI (Coq_xI (Coq_xI (Coq_xI (Coq_xI (Coq_xI + (Coq_xI (Coq_xI Coq_xH))))))))))))))))), (snd np))) l + +(** val loadimm_k : + isize -> ireg -> (coq_Z * coq_Z) list -> Asm.code -> Asm.code **) + +let loadimm_k sz rd l k = + fold_right (fun np k0 -> (Pmovk (sz, rd, (fst np), (snd np))) :: k0) k l + +(** val loadimm_z : + isize -> ireg -> (coq_Z * coq_Z) list -> Asm.code -> Asm.code **) + +let loadimm_z sz rd l k = + match l with + | [] -> (Pmovz (sz, rd, Z0, Z0)) :: k + | p :: l0 -> + let (n1, p1) = p in (Pmovz (sz, rd, n1, p1)) :: (loadimm_k sz rd l0 k) + +(** val loadimm_n : + isize -> ireg -> (coq_Z * coq_Z) list -> Asm.code -> Asm.code **) + +let loadimm_n sz rd l k = + match l with + | [] -> (Pmovn (sz, rd, Z0, Z0)) :: k + | p :: l0 -> + let (n1, p1) = p in + (Pmovn (sz, rd, n1, p1)) :: (loadimm_k sz rd (negate_decomposition l0) k) + +(** val loadimm : isize -> ireg -> coq_Z -> Asm.code -> Asm.code **) + +let loadimm sz rd n k = + let n0 = match sz with + | W -> s_ (s_ o_) + | X -> s_ (s_ (s_ (s_ o_))) in + let dz = decompose_int n0 n Z0 in + let dn = decompose_int n0 (Z.lnot n) Z0 in + if N.leb (Datatypes.length dz) (Datatypes.length dn) + then loadimm_z sz rd dz k + else loadimm_n sz rd dn k + +(** val loadimm32 : ireg -> I.int -> Asm.code -> Asm.code **) + +let loadimm32 rd n k = + if is_logical_imm32 n + then (Porrimm (W, rd, XZR, (I.unsigned n))) :: k + else loadimm W rd (I.unsigned n) k + +(** val loadimm64 : ireg -> I64.int -> Asm.code -> Asm.code **) + +let loadimm64 rd n k = + if is_logical_imm64 n + then (Porrimm (X, rd, XZR, (I64.unsigned n))) :: k + else loadimm X rd (I64.unsigned n) k + +(** val addimm_aux : + (iregsp -> iregsp -> coq_Z -> Asm.instruction) -> iregsp -> iregsp -> + coq_Z -> Asm.code -> Asm.instruction list **) + +let addimm_aux insn rd r1 n k = + let nlo = coq_Zzero_ext (Zpos (Coq_xO (Coq_xO (Coq_xI Coq_xH)))) n in + let nhi = Z.sub n nlo in + if Z.eqb nhi Z0 + then (insn rd r1 nlo) :: k + else if Z.eqb nlo Z0 + then (insn rd r1 nhi) :: k + else (insn rd r1 nhi) :: ((insn rd rd nlo) :: k) + +(** val addimm32 : ireg -> ireg -> I.int -> Asm.code -> Asm.code **) + +let addimm32 rd r1 n k = + let m = I.neg n in + if I.eq n + (I.zero_ext (Zpos (Coq_xO (Coq_xO (Coq_xO (Coq_xI Coq_xH))))) n) + then addimm_aux (fun x x0 x1 -> Paddimm (W, x, x0, x1)) (RR1 rd) (RR1 r1) + (I.unsigned n) k + else if I.eq m + (I.zero_ext (Zpos (Coq_xO (Coq_xO (Coq_xO (Coq_xI Coq_xH))))) m) + then addimm_aux (fun x x0 x1 -> Psubimm (W, x, x0, x1)) (RR1 rd) (RR1 + r1) (I.unsigned m) k + else if I.lt n I.zero + then loadimm32 X16 m ((Psub (W, rd, (RR0 r1), X16, SOnone)) :: k) + else loadimm32 X16 n ((Padd (W, rd, (RR0 r1), X16, SOnone)) :: k) + +(** val addimm64 : iregsp -> iregsp -> I64.int -> Asm.code -> Asm.code **) + +let addimm64 rd r1 n k = + let m = I64.neg n in + if I64.eq n + (I64.zero_ext (Zpos (Coq_xO (Coq_xO (Coq_xO (Coq_xI Coq_xH))))) n) + then addimm_aux (fun x x0 x1 -> Paddimm (X, x, x0, x1)) rd r1 + (I64.unsigned n) k + else if I64.eq m + (I64.zero_ext (Zpos (Coq_xO (Coq_xO (Coq_xO (Coq_xI Coq_xH))))) + m) + then addimm_aux (fun x x0 x1 -> Psubimm (X, x, x0, x1)) rd r1 + (I64.unsigned m) k + else if I64.lt n I64.zero + then loadimm64 X16 m ((Psubext (rd, r1, X16, (EOuxtx + I.zero))) :: k) + else loadimm64 X16 n ((Paddext (rd, r1, X16, (EOuxtx + I.zero))) :: k) + +(** val offset_representable : coq_Z -> I64.int -> bool **) + +let offset_representable sz ofs = + let isz = I64.repr sz in + (||) + (I64.eq ofs + (I64.sign_ext (Zpos (Coq_xI (Coq_xO (Coq_xO Coq_xH)))) ofs)) + ((&&) (I64.eq (I64.modu ofs isz) I64.zero) + (I64.ltu ofs + (I64.shl isz (I64.repr (Zpos (Coq_xO (Coq_xO (Coq_xI Coq_xH)))))))) + +(** val indexed_memory_access : + (Asm.addressing -> Asm.instruction) -> coq_Z -> iregsp -> Ptrofs.int -> + Asm.code -> Asm.instruction list **) + +let indexed_memory_access insn sz base ofs k = + let ofs0 = Ptrofs.to_int64 ofs in + if offset_representable sz ofs0 + then (insn (ADimm (base, ofs0))) :: k + else loadimm64 X16 ofs0 ((insn (ADreg (base, X16))) :: k) + +(** val storeptr : + ireg -> iregsp -> Ptrofs.int -> Asm.code -> Asm.instruction list **) + +let storeptr src base ofs k = + indexed_memory_access (fun x -> Pstrx (src, x)) (Zpos (Coq_xO (Coq_xO + (Coq_xO Coq_xH)))) base ofs k diff --git a/aarch64/PostpassScheduling.v b/aarch64/PostpassScheduling.v new file mode 100644 index 00000000..a9473789 --- /dev/null +++ b/aarch64/PostpassScheduling.v @@ -0,0 +1,495 @@ +(* *************************************************************) +(* *) +(* The Compcert verified compiler *) +(* *) +(* Sylvain Boulmé Grenoble-INP, VERIMAG *) +(* David Monniaux CNRS, VERIMAG *) +(* Cyril Six Kalray *) +(* Léo Gourdin UGA, VERIMAG *) +(* *) +(* Copyright Kalray. Copyright VERIMAG. All rights reserved. *) +(* This file is distributed under the terms of the INRIA *) +(* Non-Commercial License Agreement. *) +(* *) +(* *************************************************************) + +(** Implementation (and basic properties) of the verified postpass scheduler *) + +Require Import Coqlib Errors AST Integers. +Require Import Asmblock Axioms Memory Globalenvs. +Require Import Asmblockdeps Asmblockgenproof0 Asmblockprops. +(*Require Peephole.*) + +Local Open Scope error_monad_scope. + +(** * Oracle taking as input a basic block, + returns a scheduled basic block *) +Axiom schedule: bblock -> (list basic) * option control. + +Extract Constant schedule => "PostpassSchedulingOracle.schedule". + +(* +(** * Concat all bundles into one big basic block *) + +(* Lemmas necessary for defining concat_all *) +Lemma app_nonil {A: Type} (l l': list A) : l <> nil -> l ++ l' <> nil. +Proof. + intros. destruct l; simpl. + - contradiction. + - discriminate. +Qed. + +Lemma app_nonil2 {A: Type} : forall (l l': list A), l' <> nil -> l ++ l' <> nil. +Proof. + destruct l. + - intros. simpl; auto. + - intros. rewrite <- app_comm_cons. discriminate. +Qed. + +Definition check_size bb := + if zlt Ptrofs.max_unsigned (size bb) + then Error (msg "PostpassSchedulingproof.check_size") + else OK tt. + +Program Definition concat2 (bb bb': bblock) : res bblock := + do ch <- check_size bb; + do ch' <- check_size bb'; + match (exit bb) with + | None => + match (header bb') with + | nil => + match (exit bb') with + | Some (PExpand (Pbuiltin _ _ _)) => Error (msg "PostpassSchedulingproof.concat2: builtin not alone") + | _ => OK {| header := header bb; body := body bb ++ body bb'; exit := exit bb' |} + end + | _ => Error (msg "PostpassSchedulingproof.concat2") + end + | _ => Error (msg "PostpassSchedulingproof.concat2") + end. +Next Obligation. + apply wf_bblock_refl. constructor. + - destruct bb' as [hd' bdy' ex' WF']. destruct bb as [hd bdy ex WF]. simpl in *. + apply wf_bblock_refl in WF'. apply wf_bblock_refl in WF. + inversion_clear WF'. inversion_clear WF. clear H1 H3. + inversion H2; inversion H0. + + left. apply app_nonil. auto. + + right. auto. + + left. apply app_nonil2. auto. + + right. auto. + - unfold builtin_alone. intros. rewrite H0 in H. + assert (Some (PExpand (Pbuiltin ef args res)) <> Some (PExpand (Pbuiltin ef args res))). + apply (H ef args res). contradict H1. auto. +Defined. + +Lemma concat2_zlt_size: + forall a b bb, + concat2 a b = OK bb -> + size a <= Ptrofs.max_unsigned + /\ size b <= Ptrofs.max_unsigned. +Proof. + intros. monadInv H. + split. + - unfold check_size in EQ. destruct (zlt Ptrofs.max_unsigned (size a)); monadInv EQ. omega. + - unfold check_size in EQ1. destruct (zlt Ptrofs.max_unsigned (size b)); monadInv EQ1. omega. +Qed. + +Lemma concat2_noexit: + forall a b bb, + concat2 a b = OK bb -> + exit a = None. +Proof. + intros. destruct a as [hd bdy ex WF]; simpl in *. + destruct ex as [e|]; simpl in *; auto. + unfold concat2 in H. simpl in H. monadInv H. +Qed. + +Lemma concat2_decomp: + forall a b bb, + concat2 a b = OK bb -> + body bb = body a ++ body b + /\ exit bb = exit b. +Proof. + intros. exploit concat2_noexit; eauto. intros. + destruct a as [hda bda exa WFa]; destruct b as [hdb bdb exb WFb]; destruct bb as [hd bd ex WF]; simpl in *. + subst exa. + unfold concat2 in H; simpl in H. + destruct hdb. + - destruct exb. + + destruct c. + * destruct i; monadInv H; split; auto. + * monadInv H. split; auto. + + monadInv H. split; auto. + - monadInv H. +Qed. + +Lemma concat2_size: + forall a b bb, concat2 a b = OK bb -> size bb = size a + size b. +Proof. + intros. unfold concat2 in H. + destruct a as [hda bda exa WFa]; destruct b as [hdb bdb exb WFb]; destruct bb as [hd bdy ex WF]; simpl in *. + destruct exa; monadInv H. destruct hdb; try (monadInv EQ2). destruct exb; try (monadInv EQ2). + - destruct c. + + destruct i; monadInv EQ2; + unfold size; simpl; rewrite app_length; rewrite Nat.add_0_r; rewrite <- Nat2Z.inj_add; rewrite Nat.add_assoc; reflexivity. + + monadInv EQ2. unfold size; simpl. rewrite app_length. rewrite Nat.add_0_r. rewrite <- Nat2Z.inj_add. rewrite Nat.add_assoc. reflexivity. + - unfold size; simpl. rewrite app_length. repeat (rewrite Nat.add_0_r). rewrite <- Nat2Z.inj_add. reflexivity. +Qed. + +Lemma concat2_header: + forall bb bb' tbb, + concat2 bb bb' = OK tbb -> header bb = header tbb. +Proof. + intros. destruct bb as [hd bdy ex COR]; destruct bb' as [hd' bdy' ex' COR']; destruct tbb as [thd tbdy tex tCOR]; simpl in *. + unfold concat2 in H. simpl in H. monadInv H. + destruct ex; try discriminate. destruct hd'; try discriminate. destruct ex'. + - destruct c. + + destruct i; try discriminate; congruence. + + congruence. + - congruence. +Qed. + +Lemma concat2_no_header_in_middle: + forall bb bb' tbb, + concat2 bb bb' = OK tbb -> + header bb' = nil. +Proof. + intros. destruct bb as [hd bdy ex COR]; destruct bb' as [hd' bdy' ex' COR']; destruct tbb as [thd tbdy tex tCOR]; simpl in *. + unfold concat2 in H. simpl in H. monadInv H. + destruct ex; try discriminate. destruct hd'; try discriminate. reflexivity. +Qed. + + + +Fixpoint concat_all (lbb: list bblock) : res bblock := + match lbb with + | nil => Error (msg "PostpassSchedulingproof.concatenate: empty list") + | bb::nil => OK bb + | bb::lbb => + do bb' <- concat_all lbb; + concat2 bb bb' + end. + +Lemma concat_all_size : + forall lbb a bb bb', + concat_all (a :: lbb) = OK bb -> + concat_all lbb = OK bb' -> + size bb = size a + size bb'. +Proof. + intros. unfold concat_all in H. fold concat_all in H. + destruct lbb; try discriminate. + monadInv H. rewrite H0 in EQ. inv EQ. + apply concat2_size. assumption. +Qed. + +Lemma concat_all_header: + forall lbb bb tbb, + concat_all (bb::lbb) = OK tbb -> header bb = header tbb. +Proof. + destruct lbb. + - intros. simpl in H. congruence. + - intros. simpl in H. destruct lbb. + + inv H. eapply concat2_header; eassumption. + + monadInv H. eapply concat2_header; eassumption. +Qed. + +Lemma concat_all_no_header_in_middle: + forall lbb tbb, + concat_all lbb = OK tbb -> + Forall (fun b => header b = nil) (tail lbb). +Proof. + induction lbb; intros; try constructor. + simpl. simpl in H. destruct lbb. + - constructor. + - monadInv H. simpl tl in IHlbb. constructor. + + apply concat2_no_header_in_middle in EQ0. apply concat_all_header in EQ. congruence. + + apply IHlbb in EQ. assumption. +Qed. + +Inductive is_concat : bblock -> list bblock -> Prop := + | mk_is_concat: forall tbb lbb, concat_all lbb = OK tbb -> is_concat tbb lbb. +*) +(** * Remainder of the verified scheduler *) + +Definition verify_schedule (bb bb' : bblock) : res unit := + match bblock_simub bb bb' with + | true => OK tt + | false => Error (msg "PostpassScheduling.verify_schedule") + end. + +(*Definition verify_size bb lbb := if (Z.eqb (size bb) (size_blocks lbb)) then OK tt else Error (msg "PostpassScheduling:verify_size: wrong size").*) + +(*Lemma verify_size_size:*) + (*forall bb lbb, verify_size bb lbb = OK tt -> size bb = size_blocks lbb.*) +(*Proof.*) + (*intros. unfold verify_size in H. destruct (size bb =? size_blocks lbb) eqn:SIZE; try discriminate.*) + (*apply Z.eqb_eq. assumption.*) +(*Qed.*) + +(*Lemma verify_schedule_no_header:*) + (*forall bb bb',*) + (*verify_schedule (no_header bb) bb' = verify_schedule bb bb'.*) +(*Proof.*) + (*intros. unfold verify_schedule. unfold bblock_simub. unfold pure_bblock_simu_test, bblock_simu_test. rewrite trans_block_noheader_inv.*) + (*reflexivity.*) +(*Qed.*) + + +(*Lemma stick_header_verify_schedule:*) + (*forall hd bb' hbb' bb,*) + (*stick_header hd bb' = hbb' ->*) + (*verify_schedule bb bb' = verify_schedule bb hbb'.*) +(*Proof.*) + (*intros. unfold verify_schedule. unfold bblock_simub, pure_bblock_simu_test, bblock_simu_test.*) + (*rewrite <- H. rewrite trans_block_header_inv. reflexivity.*) +(*Qed.*) + +(*Lemma check_size_stick_header:*) + (*forall bb hd,*) + (*check_size bb = check_size (stick_header hd bb).*) +(*Proof.*) + (*intros. unfold check_size. rewrite stick_header_size. reflexivity.*) +(*Qed.*) + +(*Lemma stick_header_concat2:*) + (*forall bb bb' hd tbb,*) + (*concat2 bb bb' = OK tbb ->*) + (*concat2 (stick_header hd bb) bb' = OK (stick_header hd tbb).*) +(*Proof.*) + (*intros. monadInv H. erewrite check_size_stick_header in EQ.*) + (*unfold concat2. rewrite EQ. rewrite EQ1. simpl.*) + (*destruct bb as [hdr bdy ex COR]; destruct bb' as [hdr' bdy' ex' COR']; simpl in *.*) + (*destruct ex; try discriminate. destruct hdr'; try discriminate. destruct ex'.*) + (*- destruct c.*) + (*+ destruct i; try discriminate; inv EQ2; unfold stick_header; simpl; reflexivity.*) + (*+ inv EQ2. unfold stick_header; simpl. reflexivity.*) + (*- inv EQ2. unfold stick_header; simpl. reflexivity.*) +(*Qed.*) + +(*Lemma stick_header_concat_all:*) + (*forall bb c tbb hd,*) + (*concat_all (bb :: c) = OK tbb ->*) + (*concat_all (stick_header hd bb :: c) = OK (stick_header hd tbb).*) +(*Proof.*) + (*intros. simpl in *. destruct c; try congruence.*) + (*monadInv H. rewrite EQ. simpl.*) + (*apply stick_header_concat2. assumption.*) +(*Qed.*) + +(*Lemma stick_header_code_no_header:*) + (*forall bb c,*) + (*stick_header_code (header bb) (no_header bb :: c) = OK (bb :: c).*) +(*Proof.*) + (*intros. unfold stick_header_code. simpl. rewrite stick_header_no_header. reflexivity.*) +(*Qed.*) + +(*Lemma hd_tl_size:*) + (*forall lbb bb, hd_error lbb = Some bb -> size_blocks lbb = size bb + size_blocks (tl lbb).*) +(*Proof.*) + (*destruct lbb.*) + (*- intros. simpl in H. discriminate.*) + (*- intros. simpl in H. inv H. simpl. reflexivity.*) +(*Qed.*) + +(*Lemma stick_header_code_size:*) + (*forall h lbb lbb', stick_header_code h lbb = OK lbb' -> size_blocks lbb = size_blocks lbb'.*) +(*Proof.*) + (*intros. unfold stick_header_code in H. destruct (hd_error lbb) eqn:HD; try discriminate.*) + (*inv H. simpl. rewrite stick_header_size. erewrite hd_tl_size; eauto.*) +(*Qed.*) + +(*Lemma stick_header_code_no_header_in_middle:*) + (*forall c h lbb,*) + (*stick_header_code h c = OK lbb ->*) + (*Forall (fun b => header b = nil) (tl c) ->*) + (*Forall (fun b => header b = nil) (tl lbb).*) +(*Proof.*) + (*destruct c; intros.*) + (*- unfold stick_header_code in H. simpl in H. discriminate.*) + (*- unfold stick_header_code in H. simpl in H. inv H. simpl in H0.*) + (*simpl. assumption.*) +(*Qed.*) + +(*Lemma stick_header_code_concat_all:*) + (*forall hd lbb hlbb tbb,*) + (*stick_header_code hd lbb = OK hlbb ->*) + (*concat_all lbb = OK tbb ->*) + (*exists htbb,*) + (*concat_all hlbb = OK htbb*) + (*/\ stick_header hd tbb = htbb.*) +(*Proof.*) + (*intros. exists (stick_header hd tbb). split; auto.*) + (*destruct lbb.*) + (*- unfold stick_header_code in H. simpl in H. discriminate.*) + (*- unfold stick_header_code in H. simpl in H. inv H.*) + (*apply stick_header_concat_all. assumption.*) +(*Qed.*) + +Program Definition make_bblock_from_basics lb := + match lb with + | nil => Error (msg "PostpassScheduling.make_bblock_from_basics") + | b :: lb => OK {| header := nil; body := b::lb; exit := None |} + end. + +Program Definition schedule_to_bblock (lb: list basic) (oc: option control) : res bblock := + match oc with + | None => make_bblock_from_basics lb + | Some c => OK {| header := nil; body := lb; exit := Some c |} + end. +Next Obligation. + unfold Is_true, AB.non_empty_bblockb. + unfold AB.non_empty_exit. rewrite orb_true_r. reflexivity. +Qed. + +Definition do_schedule (bb: bblock) : res bblock := + if (Z.eqb (size bb) 1) then OK (bb) + else match (schedule bb) with (lb, oc) => schedule_to_bblock lb oc end. (* TODO Something here *) + +(* TODO to remove ? *) +(*Definition verify_par_bblock (bb: bblock) : res unit :=*) + (*if (bblock_para_check bb) then OK tt else Error (msg "PostpassScheduling.verify_par_bblock").*) +(*Fixpoint verify_par (lbb: list bblock) :=*) + (*match lbb with*) + (*| nil => OK tt*) + (*| bb :: lbb => do res <- verify_par_bblock bb; verify_par lbb*) + (*end.*) + +Definition verified_schedule (bb : bblock) : res bblock := + let bb' := no_header bb in + (* TODO remove? let bb'' := Peephole.optimize_bblock bb' in *) + do lb <- do_schedule bb'; + (*do tbb <- concat_all lbb;*) + (*do sizecheck <- verify_size bb lbb;*) + do schedcheck <- verify_schedule bb' lb; (* TODO Keep this one *) + (*do parcheck <- verify_par res;*) + OK (stick_header (header bb) lb). + +(*Lemma verified_schedule_nob_size:*) + (*forall bb lbb, verified_schedule_nob bb = OK lbb -> size bb = size_blocks lbb.*) +(*Proof.*) + (*intros. monadInv H. erewrite <- stick_header_code_size; eauto.*) + (*apply verify_size_size.*) + (*destruct x1; try discriminate. assumption.*) +(*Qed.*) + +(*Lemma verified_schedule_nob_no_header_in_middle:*) + (*forall lbb bb,*) + (*verified_schedule_nob bb = OK lbb ->*) + (*Forall (fun b => header b = nil) (tail lbb).*) +(*Proof.*) + (*intros. monadInv H. eapply stick_header_code_no_header_in_middle; eauto.*) + (*eapply concat_all_no_header_in_middle. eassumption.*) +(*Qed.*) + +(*Lemma verified_schedule_nob_header:*) + (*forall bb tbb lbb,*) + (*verified_schedule_nob bb = OK (tbb :: lbb) ->*) + (*header bb = header tbb*) + (*/\ Forall (fun b => header b = nil) lbb.*) +(*Proof.*) + (*intros. split.*) + (*- monadInv H. unfold stick_header_code in EQ3. destruct (hd_error _); try discriminate. inv EQ3.*) + (*simpl. reflexivity.*) + (*- apply verified_schedule_nob_no_header_in_middle in H. assumption.*) +(*Qed.*) + + +(*Definition verified_schedule (bb : bblock) : res (list bblock) :=*) + (*verified_schedule_nob bb.*) +(* TODO Remove? + match exit bb with + | Some (PExpand (Pbuiltin ef args res)) => OK (bb::nil) (* Special case for ensuring the lemma verified_schedule_builtin_idem *) + | _ => verified_schedule_nob bb + end.*) + +(*Lemma verified_schedule_size:*) + (*forall bb lbb, verified_schedule bb = OK lbb -> size bb = size_blocks lbb.*) +(*Proof.*) + (*intros. unfold verified_schedule in H. destruct (exit bb). destruct c. destruct i.*) + (*all: try (apply verified_schedule_nob_size; auto; fail).*) + (*inv H. simpl. omega.*) +(*Qed.*) + +(*Lemma verified_schedule_no_header_in_middle:*) + (*forall lbb bb,*) + (*verified_schedule bb = OK lbb ->*) + (*Forall (fun b => header b = nil) (tail lbb).*) +(*Proof.*) + (*intros. unfold verified_schedule in H. destruct (exit bb). destruct c. destruct i.*) + (*all: try (eapply verified_schedule_nob_no_header_in_middle; eauto; fail).*) + (*inv H. simpl. auto.*) +(*Qed.*) + +(*Lemma verified_schedule_header:*) + (*forall bb tbb lbb,*) + (*verified_schedule bb = OK (tbb :: lbb) ->*) + (*header bb = header tbb*) + (*/\ Forall (fun b => header b = nil) lbb.*) +(*Proof.*) + (*intros. unfold verified_schedule in H. destruct (exit bb). destruct c. destruct i.*) + (*all: try (eapply verified_schedule_nob_header; eauto; fail).*) + (*inv H. split; simpl; auto.*) +(*Qed.*) + + +(*Lemma verified_schedule_nob_correct:*) + (*forall ge f bb lbb,*) + (*verified_schedule_nob bb = OK lbb ->*) + (*exists tbb,*) + (*is_concat tbb lbb*) + (*/\ bblock_simu ge f bb tbb.*) +(*Proof.*) + (*intros. monadInv H.*) + (*exploit stick_header_code_concat_all; eauto.*) + (*intros (tbb & CONC & STH).*) + (*exists tbb. split; auto. constructor; auto.*) + (*rewrite verify_schedule_no_header in EQ2. erewrite stick_header_verify_schedule in EQ2; eauto.*) + (*eapply bblock_simub_correct; eauto. unfold verify_schedule in EQ2.*) + (*destruct (bblock_simub _ _); auto; try discriminate.*) +(*Qed.*) + +(*Theorem verified_schedule_correct:*) + (*forall ge f bb lbb,*) + (*verified_schedule bb = OK lbb ->*) + (*exists tbb,*) + (*is_concat tbb lbb*) + (*/\ bblock_simu ge f bb tbb.*) +(*Proof.*) + (*intros. unfold verified_schedule in H. destruct (exit bb). destruct c. destruct i.*) + (*all: try (eapply verified_schedule_nob_correct; eauto; fail).*) + (*inv H. eexists. split; simpl; auto. constructor; auto. simpl; auto. constructor; auto.*) +(*Qed.*) + +(*Lemma verified_schedule_builtin_idem:*) + (*forall bb ef args res lbb,*) + (*exit bb = Some (PExpand (Pbuiltin ef args res)) ->*) + (*verified_schedule bb = OK lbb ->*) + (*lbb = bb :: nil.*) +(*Proof.*) + (*intros. unfold verified_schedule in H0. rewrite H in H0. inv H0. reflexivity.*) +(*Qed.*) + + +Fixpoint transf_blocks (lbb : list bblock) : res (list bblock) := + match lbb with + | nil => OK nil + | bb :: lbb => + do tlbb <- transf_blocks lbb; + do tbb <- verified_schedule bb; + OK (tbb :: tlbb) + end. + +Definition transl_function (f: function) : res function := + do lb <- transf_blocks (fn_blocks f); + OK (mkfunction (fn_sig f) lb). + +Definition transf_function (f: function) : res function := + do tf <- transl_function f; + if zlt Ptrofs.max_unsigned (size_blocks tf.(fn_blocks)) + then Error (msg "code size exceeded") + else OK tf. + +Definition transf_fundef (f: fundef) : res fundef := + transf_partial_fundef transf_function f. + +Definition transf_program (p: program) : res program := + transform_partial_program transf_fundef p. diff --git a/aarch64/PostpassSchedulingOracle.ml b/aarch64/PostpassSchedulingOracle.ml new file mode 100644 index 00000000..821a1d53 --- /dev/null +++ b/aarch64/PostpassSchedulingOracle.ml @@ -0,0 +1,984 @@ +(* *************************************************************) +(* *) +(* The Compcert verified compiler *) +(* *) +(* Sylvain Boulmé Grenoble-INP, VERIMAG *) +(* David Monniaux CNRS, VERIMAG *) +(* Cyril Six Kalray *) +(* Léo Gourdin UGA, VERIMAG *) +(* *) +(* Copyright Kalray. Copyright VERIMAG. All rights reserved. *) +(* This file is distributed under the terms of the INRIA *) +(* Non-Commercial License Agreement. *) +(* *) +(* *************************************************************) + +open Asmblock +open OpWeightsAsm +open InstructionScheduler + +let debug = true + +(** + * Extracting infos from Asm instructions + *) + +type location = Reg of Asm.preg | Mem | IREG0_XZR + +type ab_inst_rec = { + inst : real_instruction; + write_locs : location list; + read_locs : location list; + is_control : bool; +} + +(** Asm constructor to real instructions *) + +exception OpaqueInstruction + +let arith_p_real = function + | Padrp (_, _) -> Adrp + | Pmovz (_, _, _) -> Movz + | Pmovn (_, _, _) -> Movn + | Pfmovimms _ -> Fmov (* TODO not sure about this and below too *) + | Pfmovimmd _ -> Fmov + +let arith_pp_real = function + | Pmov -> Mov + | Pmovk (_, _, _) -> Movk + | Paddadr (_, _) -> Add + | Psbfiz (_, _, _) -> Sbfiz + | Psbfx (_, _, _) -> Sbfx + | Pubfiz (_, _, _) -> Ubfiz + | Pubfx (_, _, _) -> Ubfx + | Pfmov -> Fmov + | Pfcvtds -> Fcvt + | Pfcvtsd -> Fcvt + | Pfabs _ -> Fabs + | Pfneg _ -> Fneg + | Pscvtf (_, _) -> Scvtf + | Pucvtf (_, _) -> Ucvtf + | Pfcvtzs (_, _) -> Fcvtzs + | Pfcvtzu (_, _) -> Fcvtzu + | Paddimm (_, _) -> Add + | Psubimm (_, _) -> Sub + +let arith_ppp_real = function + | Pasrv _ -> Asr + | Plslv _ -> Lsl + | Plsrv _ -> Lsr + | Prorv _ -> Ror + | Psmulh -> Smulh + | Pumulh -> Umulh + | Psdiv _ -> Sdiv + | Pudiv _ -> Udiv + | Paddext _ -> Add + | Psubext _ -> Sub + | Pfadd _ -> Fadd + | Pfdiv _ -> Fdiv + | Pfmul _ -> Fmul + | Pfsub _ -> Fsub + +let arith_rr0r_real = function + | Padd (_, _) -> Add + | Psub (_, _) -> Sub + | Pand (_, _) -> And + | Pbic (_, _) -> Bic + | Peon (_, _) -> Eon + | Peor (_, _) -> Eor + | Porr (_, _) -> Orr + | Porn (_, _) -> Orn + +let arith_rr0_real = function + | Pandimm (_, _) -> And + | Peorimm (_, _) -> Eor + | Porrimm (_, _) -> Orr + +let arith_arrrr0_real = function Pmadd _ -> Madd | Pmsub _ -> Msub + +let arith_comparison_p_real = function + | Pfcmp0 _ -> Fcmp + | Pcmpimm (_, _) -> Cmp + | Pcmnimm (_, _) -> Cmn + | Ptstimm (_, _) -> Tst + +let arith_comparison_pp_real = function + | Pcmpext _ -> Cmp + | Pcmnext _ -> Cmn + | Pfcmp _ -> Fcmp + +let arith_comparison_r0r_real = function + | Pcmp (_, _) -> Cmp + | Pcmn (_, _) -> Cmn + | Ptst (_, _) -> Tst + +let arith_comparison_rr0r_real = function + | Padd (_, _) -> Add + | Psub (_, _) -> Sub + | Pand (_, _) -> And + | Pbic (_, _) -> Bic + | Peon (_, _) -> Eon + | Peor (_, _) -> Eor + | Porr (_, _) -> Orr + | Porn (_, _) -> Orn + +let arith_comparison_rr0_real = function + | Pandimm (_, _) -> And + | Peorimm (_, _) -> Eor + | Porrimm (_, _) -> Orr + +let arith_comparison_arrrr0_real = function Pmadd _ -> Madd | Pmsub _ -> Msub + +let store_rs_a_real = function + | Pstrw -> Str + | Pstrw_a -> Str + | Pstrx -> Str + | Pstrx_a -> Str + | Pstrb -> Strb + | Pstrh -> Strh + | Pstrs -> Str + | Pstrd -> Str + | Pstrd_a -> Str + +let load_rd_a_real = function + | Pldrw -> Ldr + | Pldrw_a -> Ldr + | Pldrx -> Ldr + | Pldrx_a -> Ldr + | Pldrb _ -> Ldrb + | Pldrsb _ -> Ldrsb + | Pldrh _ -> Ldrh + | Pldrsh _ -> Ldrsh + | Pldrzw -> Ldr + | Pldrsw -> Ldrsw + | Pldrs -> Ldr + | Pldrd -> Ldr + | Pldrd_a -> Ldr + +let loadsymbol_real = Ldr + +let cvtsw2x_real = Sxtw + +let cvtuw2x_real = Uxtw + +let cset_real = Cset + +let csel_real = Csel + +let fmovi_real = Fmov + +let fnmul_real = Fnmul + +let b_real = B + +let bc_real = B + +let bl_real = Bl + +let bs_real = B + +let blr_real = Blr + +let br_real = Br + +let ret_real = Ret + +let cbnz_real = Cbnz + +let cbz_real = Cbz + +let tbnz_real = Tbnz + +let tbz_real = Tbz + +let btbl_real = Btbl + +let allocframe_real = Allocframe + +let freeframe_real = Freeframe + +let builtin_real = Builtin + +let cvtx2w_real = Cvtx2w + +let is_XZR = function IREG0_XZR -> true | _ -> false + +let reg_of_pc = Reg Asm.PC + +let reg_of_dreg r = Reg (Asm.DR r) + +let reg_of_ireg r = Reg (Asm.DR (Asm.IR (Asm.RR1 r))) + +let reg_of_iregsp r = Reg (Asm.DR (Asm.IR r)) + +let reg_of_ireg0 r = + match r with Asm.RR0 ir -> reg_of_ireg ir | Asm.XZR -> IREG0_XZR + +let reg_of_freg r = Reg (Asm.DR (Asm.FR r)) + +let reg_of_cr r = Reg (Asm.CR r) + +let regXSP = Reg (Asm.DR (Asm.IR Asm.XSP)) + +let flags_wlocs = + [ reg_of_cr Asm.CN; reg_of_cr Asm.CZ; reg_of_cr Asm.CC; reg_of_cr Asm.CV ] + +let arith_p_rec i rd = + { + inst = arith_p_real i; + write_locs = [ rd ]; + read_locs = []; + is_control = false; + } + +let arith_pp_rec i rd rs = + { + inst = arith_pp_real i; + write_locs = [ rd ]; + read_locs = [ rs ]; + is_control = false; + } + +let arith_ppp_rec i rd r1 r2 = + { + inst = arith_ppp_real i; + write_locs = [ rd ]; + read_locs = [ r1; r2 ]; + is_control = false; + } + +let arith_rr0r_rec i rd r1 r2 = + let rlocs = if is_XZR r1 then [ r2 ] else [ r1; r2 ] in + { + inst = arith_rr0r_real i; + write_locs = [ rd ]; + read_locs = rlocs; + is_control = false; + } + +let arith_rr0_rec i rd r1 = + let rlocs = if is_XZR r1 then [] else [ r1 ] in + { + inst = arith_rr0_real i; + write_locs = [ rd ]; + read_locs = rlocs; + is_control = false; + } + +let arith_arrrr0_rec i rd r1 r2 r3 = + let rlocs = if is_XZR r3 then [ r1; r2 ] else [ r1; r2; r3 ] in + { + inst = arith_arrrr0_real i; + write_locs = [ rd ]; + read_locs = rlocs; + is_control = false; + } + +let arith_comparison_pp_rec i r1 r2 = + { + inst = arith_comparison_pp_real i; + write_locs = flags_wlocs; + read_locs = [ r1; r2 ]; + is_control = false; + } + +let arith_comparison_r0r_rec i r1 r2 = + let rlocs = if is_XZR r1 then [ r2 ] else [ r1; r2 ] in + { + inst = arith_comparison_r0r_real i; + write_locs = flags_wlocs; + read_locs = rlocs; + is_control = false; + } + +let arith_comparison_p_rec i r1 = + { + inst = arith_comparison_p_real i; + write_locs = flags_wlocs; + read_locs = [ r1 ]; + is_control = false; + } + +let get_eval_addressing_rlocs a = + match a with + | Asm.ADimm (base, _) -> [ reg_of_iregsp base ] + | Asm.ADreg (base, r) -> [ reg_of_iregsp base; reg_of_ireg r ] + | Asm.ADlsl (base, r, _) -> [ reg_of_iregsp base; reg_of_ireg r ] + | Asm.ADsxt (base, r, _) -> [ reg_of_iregsp base; reg_of_ireg r ] + | Asm.ADuxt (base, r, _) -> [ reg_of_iregsp base; reg_of_ireg r ] + | Asm.ADadr (base, _, _) -> [ reg_of_iregsp base ] + | Asm.ADpostincr (base, _) -> [] + +let load_rec ld rd a = + { + inst = load_rd_a_real ld; + write_locs = [ rd ]; + read_locs = [ Mem ] @ get_eval_addressing_rlocs a; + is_control = false; + } + +let store_rec st r a = + { + inst = store_rs_a_real st; + write_locs = [ Mem ]; + read_locs = [ r; Mem ] @ get_eval_addressing_rlocs a; + is_control = false; + } + +let loadsymbol_rec rd id = + { + inst = loadsymbol_real; + write_locs = [ rd ]; + read_locs = [ Mem ]; + is_control = false; + } + +let cvtsw2x_rec rd r1 = + { + inst = cvtsw2x_real; + write_locs = [ rd ]; + read_locs = [ r1 ]; + is_control = false; + } + +let cvtuw2x_rec rd r1 = + { + inst = cvtuw2x_real; + write_locs = [ rd ]; + read_locs = [ r1 ]; + is_control = false; + } + +let cvtx2w_rec rd = + { + inst = cvtx2w_real; + write_locs = [ rd ]; + read_locs = [ rd ]; + is_control = false; + } + +let get_testcond_rlocs c = + match c with + | Asm.TCeq -> [ reg_of_cr Asm.CZ ] + | Asm.TCne -> [ reg_of_cr Asm.CZ ] + | Asm.TChs -> [ reg_of_cr Asm.CC ] + | Asm.TClo -> [ reg_of_cr Asm.CC ] + | Asm.TCmi -> [ reg_of_cr Asm.CN ] + | Asm.TCpl -> [ reg_of_cr Asm.CN ] + | Asm.TChi -> [ reg_of_cr Asm.CZ; reg_of_cr Asm.CC ] + | Asm.TCls -> [ reg_of_cr Asm.CZ; reg_of_cr Asm.CC ] + | Asm.TCge -> [ reg_of_cr Asm.CN; reg_of_cr Asm.CV ] + | Asm.TClt -> [ reg_of_cr Asm.CN; reg_of_cr Asm.CV ] + | Asm.TCgt -> [ reg_of_cr Asm.CN; reg_of_cr Asm.CZ; reg_of_cr Asm.CV ] + | Asm.TCle -> [ reg_of_cr Asm.CN; reg_of_cr Asm.CZ; reg_of_cr Asm.CV ] + +let cset_rec rd c = + { + inst = cset_real; + write_locs = [ rd ]; + read_locs = get_testcond_rlocs c; + is_control = false; + } + +let csel_rec rd r1 r2 c = + { + inst = csel_real; + write_locs = [ rd ]; + read_locs = [ r1; r2 ] @ get_testcond_rlocs c; + is_control = false; + } + +let fmovi_rec fsz rd r1 = + let rlocs = if is_XZR r1 then [] else [ r1 ] in + { + inst = fmovi_real; + write_locs = [ rd ]; + read_locs = rlocs; + is_control = false; + } + +let fnmul_rec fsz rd r1 r2 = + { + inst = fnmul_real; + write_locs = [ rd ]; + read_locs = [ r1; r2 ]; + is_control = false; + } + +let allocframe_rec sz linkofs = + { + inst = allocframe_real; + write_locs = [ Mem; regXSP; reg_of_ireg Asm.X16; reg_of_ireg Asm.X29 ]; + read_locs = [ regXSP; Mem ]; + is_control = false; + } + +let freeframe_rec sz linkofs = + { + inst = freeframe_real; + write_locs = [ Mem; regXSP; reg_of_ireg Asm.X16 ]; + read_locs = [ regXSP; Mem ]; + is_control = false; + } + +let arith_rec i = + match i with + | PArithP (i', rd) -> arith_p_rec i' (reg_of_dreg rd) + | PArithPP (i', rd, rs) -> arith_pp_rec i' (reg_of_dreg rd) (reg_of_dreg rs) + | PArithPPP (i', rd, r1, r2) -> + arith_ppp_rec i' (reg_of_dreg rd) (reg_of_dreg r1) (reg_of_dreg r2) + | PArithRR0R (i', rd, r1, r2) -> + arith_rr0r_rec i' (reg_of_ireg rd) (reg_of_ireg0 r1) (reg_of_ireg r2) + | PArithRR0 (i', rd, r1) -> + arith_rr0_rec i' (reg_of_ireg rd) (reg_of_ireg0 r1) + | PArithARRRR0 (i', rd, r1, r2, r3) -> + arith_arrrr0_rec i' (reg_of_ireg rd) (reg_of_ireg r1) (reg_of_ireg r2) + (reg_of_ireg0 r3) + | PArithComparisonPP (i', r1, r2) -> + arith_comparison_pp_rec i' (reg_of_dreg r1) (reg_of_dreg r2) + | PArithComparisonR0R (i', r1, r2) -> + arith_comparison_r0r_rec i' (reg_of_ireg0 r1) (reg_of_ireg r2) + | PArithComparisonP (i', r1) -> arith_comparison_p_rec i' (reg_of_dreg r1) + | Pcset (rd, c) -> cset_rec (reg_of_ireg rd) c + | Pfmovi (fsz, rd, r1) -> fmovi_rec fsz (reg_of_freg rd) (reg_of_ireg0 r1) + | Pcsel (rd, r1, r2, c) -> + csel_rec (reg_of_dreg rd) (reg_of_dreg r1) (reg_of_dreg r2) c + | Pfnmul (fsz, rd, r1, r2) -> + fnmul_rec fsz (reg_of_freg rd) (reg_of_freg r1) (reg_of_freg r2) + +let basic_rec i = + match i with + | PArith i' -> arith_rec i' + | PLoad (ld, rd, a) -> load_rec ld (reg_of_dreg rd) a + | PStore (st, r, a) -> store_rec st (reg_of_dreg r) a + | Pallocframe (sz, linkofs) -> allocframe_rec sz linkofs + | Pfreeframe (sz, linkofs) -> freeframe_rec sz linkofs + | Ploadsymbol (rd, id) -> loadsymbol_rec (reg_of_ireg rd) id + | Pcvtsw2x (rd, r1) -> cvtsw2x_rec (reg_of_ireg rd) (reg_of_ireg r1) + | Pcvtuw2x (rd, r1) -> cvtuw2x_rec (reg_of_ireg rd) (reg_of_ireg r1) + | Pcvtx2w rd -> cvtx2w_rec (reg_of_ireg rd) + +let builtin_rec ef args res = + (* XXX verify this *) + { + inst = builtin_real; + write_locs = [ Mem ]; + read_locs = [ Mem ]; + is_control = true; + } + +let ctl_flow_rec i = + match i with + | Pb lbl -> + { + inst = b_real; + write_locs = [ reg_of_pc ]; + read_locs = [ reg_of_pc ]; + is_control = true; + } + | Pbc (c, lbl) -> + { + inst = bc_real; + write_locs = [ reg_of_pc ]; + read_locs = [ reg_of_pc ]; + is_control = true; + } + | Pbl (id, sg) -> + { + inst = bl_real; + write_locs = [ reg_of_ireg Asm.X30; reg_of_pc ]; + read_locs = [ reg_of_pc ]; + is_control = true; + } + (* XXX not sure about X30 *) + | Pbs (id, sg) -> + { + inst = bs_real; + write_locs = [ reg_of_pc ]; + read_locs = []; + is_control = true; + } + | Pblr (r, sg) -> + { + inst = blr_real; + write_locs = [ reg_of_ireg Asm.X30; reg_of_pc ]; + read_locs = [ reg_of_ireg r ]; + is_control = true; + } + | Pbr (r, sg) -> + { + inst = br_real; + write_locs = [ reg_of_pc ]; + read_locs = [ reg_of_ireg r ]; + is_control = true; + } + | Pret r -> + { + inst = ret_real; + write_locs = [ reg_of_pc ]; + read_locs = [ reg_of_ireg r ]; + is_control = true; + } + | Pcbnz (sz, r, lbl) -> + { + inst = cbnz_real; + write_locs = [ reg_of_pc ]; + read_locs = [ reg_of_ireg r; reg_of_pc ]; + is_control = true; + } + | Pcbz (sz, r, lbl) -> + { + inst = cbz_real; + write_locs = [ reg_of_pc ]; + read_locs = [ reg_of_ireg r; reg_of_pc ]; + is_control = true; + } + | Ptbnz (sz, r, n, lbl) -> + { + inst = tbnz_real; + write_locs = [ reg_of_pc ]; + read_locs = [ reg_of_ireg r; reg_of_pc ]; + is_control = true; + } + | Ptbz (sz, r, n, lbl) -> + { + inst = tbz_real; + write_locs = [ reg_of_pc ]; + read_locs = [ reg_of_ireg r; reg_of_pc ]; + is_control = true; + } + | Pbtbl (r1, tbl) -> + { + inst = btbl_real; + write_locs = [ reg_of_ireg Asm.X16; reg_of_ireg Asm.X17; reg_of_pc ]; + read_locs = [ reg_of_ireg r1; reg_of_pc ]; + is_control = true; + } + +(* XXX Verify this (Pbtbl) *) + +let control_rec i = + match i with + | Pbuiltin (ef, args, res) -> builtin_rec ef args res + | PCtlFlow i' -> ctl_flow_rec i' + +let rec basic_recs body = + match body with [] -> [] | bi :: body -> basic_rec bi :: basic_recs body + +let exit_rec exit = match exit with None -> [] | Some ex -> [ control_rec ex ] + +let instruction_recs bb = basic_recs bb.body @ exit_rec bb.exit + +(** + * Providing informations relative to the real instructions + *) + +type inst_info = { + write_locs : location list; + read_locs : location list; + is_control : bool; + usage : int array; + (* resources consumed by the instruction *) + latency : int; +} +(** Abstraction providing all the necessary informations for solving the scheduling problem *) + +(*(** Resources *)*) +(*type rname = Rissue | Rtiny | Rlite | Rfull | Rlsu | Rmau | Rbcu | Rtca | Rauxr | Rauxw | Rcrrp | Rcrwl | Rcrwh | Rnop*) + +(*let resource_names = [Rissue; Rtiny; Rlite; Rfull; Rlsu; Rmau; Rbcu; Rtca; Rauxr; Rauxw; Rcrrp; Rcrwl; Rcrwh; Rnop]*) + +(*let rec find_index elt l =*) +(*match l with*) +(*| [] -> raise Not_found*) +(*| e::l -> if (e == elt) then 0*) +(*else 1 + find_index elt l*) + +(*let resource_id resource : int = find_index resource resource_names*) + +(*let resource_bounds : int array = Array.of_list (List.map resource_bound resource_names)*) + +(*let rec empty_inter la = function*) +(*| [] -> true*) +(*| b::lb -> if (List.mem b la) then false else empty_inter la lb*) + +let rec_to_info (r : ab_inst_rec) : inst_info = + let opweights = OpWeightsAsm.get_opweights () in + let usage = opweights.resources_of_op r.inst 0 + and latency = opweights.latency_of_op r.inst 0 in + { + write_locs = r.write_locs; + read_locs = r.read_locs; + usage; + latency; + is_control = r.is_control; + } + +let instruction_infos bb = List.map rec_to_info (instruction_recs bb) + +(*let instruction_infos bb = instruction_recs bb*) + +let instruction_usages bb = + let usages = List.map (fun info -> info.usage) (instruction_infos bb) in + Array.of_list usages + +(** + * Latency constraints building + *) + +(*(* type access = { inst: int; loc: location } *)*) + +(*let preg2int pr = Camlcoq.P.to_int @@ Asmblockdeps.ppos pr*) + +(*let loc2int = function*) +(*| Mem -> 1*) +(*| Reg pr -> preg2int pr*) + +(*(* module HashedLoc = struct*) + (*type t = { loc: location; key: int }*) + (*let equal l1 l2 = (l1.key = l2.key)*) + (*let hash l = l.key*) + (*let create (l:location) : t = { loc=l; key = loc2int l }*) +(*end *)*) + +(*(* module LocHash = Hashtbl.Make(HashedLoc) *)*) +module LocHash = Hashtbl + +(*(* Hash table : location => list of instruction ids *)*) + +let rec intlist n = + if n < 0 then failwith "intlist: n < 0" + else if n = 0 then [] + else (n - 1) :: intlist (n - 1) + +let find_in_hash hashloc loc = + match LocHash.find_opt hashloc loc with Some idl -> idl | None -> [] + +(* Returns a list of instruction ids *) +let rec get_accesses hashloc (ll : location list) = + match ll with + | [] -> [] + | loc :: llocs -> find_in_hash hashloc loc @ get_accesses hashloc llocs + +let compute_latency (ifrom : inst_info) = ifrom.latency + +(*let dlat = inst_info_to_dlatency ito*) +(*in let lat = ifrom.latency + dlat*) +(*in assert (lat >= 0); if (lat == 0) then 1 else lat*) + +let latency_constraints bb = + let written = LocHash.create 70 + and read = LocHash.create 70 + and count = ref 0 + and constraints = ref [] + and instr_infos = instruction_infos bb in + let step (i : inst_info) = + let raw = get_accesses written i.read_locs + and waw = get_accesses written i.write_locs + and war = get_accesses read i.write_locs in + List.iter + (fun i -> + constraints := + { + instr_from = i; + instr_to = !count; + latency = compute_latency (List.nth instr_infos i); + } + :: !constraints) + raw; + List.iter + (fun i -> + constraints := + { + instr_from = i; + instr_to = !count; + latency = compute_latency (List.nth instr_infos i); + } + :: !constraints) + waw; + List.iter + (fun i -> + constraints := + { instr_from = i; instr_to = !count; latency = 0 } :: !constraints) + war; + if i.is_control then + List.iter + (fun n -> + constraints := + { instr_from = n; instr_to = !count; latency = 0 } :: !constraints) + (intlist !count); + (* Updating "read" and "written" hashmaps *) + List.iter + (fun loc -> + LocHash.replace written loc [ !count ]; + LocHash.replace read loc [] + (* Clearing all the entries of "read" hashmap when a register is written *)) + i.write_locs; + List.iter + (fun loc -> LocHash.replace read loc (!count :: find_in_hash read loc)) + i.read_locs; + count := !count + 1 + in + List.iter step instr_infos; + !constraints + +(** + * Using the InstructionScheduler + *) + +(* TODO RESUME HERE *) + +let opweights = OpWeightsAsm.get_opweights () + +let build_problem bb = + { + max_latency = -1; + resource_bounds = opweights.pipelined_resource_bounds; + instruction_usages = instruction_usages bb; + latency_constraints = latency_constraints bb; + } + +(*let rec find_min_opt (l: int option list) =*) +(*match l with*) +(*| [] -> None *) +(*| e :: l ->*) +(*begin match find_min_opt l with*) +(*| None -> e*) +(*| Some m ->*) +(*begin match e with*) +(*| None -> Some m*) +(*| Some n -> if n < m then Some n else Some m*) +(*end*) +(*end*) + +(*let rec filter_indexes predicate = function*) +(*| [] -> []*) +(*| e :: l -> if (predicate e) then e :: (filter_indexes predicate l) else filter_indexes predicate l*) + +let get_from_indexes indexes l = List.map (List.nth l) indexes + +(*let is_basic = function PBasic _ -> true | _ -> false*) +let is_control = function PControl _ -> true | _ -> false + +(*let to_basic = function*) +(*| PBasic i -> i*) +(*| _ -> failwith "to_basic: control instruction found"*) + +let to_control = function + | PControl i -> i + | _ -> failwith "to_control: basic instruction found" + +let rec body_to_instrs bdy = + match bdy with [] -> [] | i :: l' -> PBasic i :: body_to_instrs l' + +let rec instrs_to_bdy instrs = + match instrs with + | [] -> [] + | PBasic i :: l' -> i :: instrs_to_bdy l' + | PControl _ :: l' -> failwith "instrs_to_bdy: control instruction found" + +let repack li hd = + let last = List.nth li (List.length li - 1) in + if is_control last then + let cut_li = + Array.to_list @@ Array.sub (Array.of_list li) 0 (List.length li - 1) + in + { header = hd; body = instrs_to_bdy cut_li; exit = Some (to_control last) } + else { header = hd; body = instrs_to_bdy li; exit = None } + +(*let extract_some o = match o with Some e -> e | None -> failwith "extract_some: None found"*) + +(*let rec find_min = function*) +(*| [] -> None*) +(*| e :: l ->*) +(*match find_min l with*) +(*| None -> Some e*) +(*| Some m -> if (e < m) then Some e else Some m*) + +(*let rec remove_all m = function*) +(*| [] -> []*) +(*| e :: l -> if m=e then remove_all m l*) +(*else e :: (remove_all m l)*) + +(*let rec find_mins l = match find_min l with*) +(*| None -> []*) +(*| Some m -> m :: find_mins (remove_all m l)*) + +(*let find_all_indices m l = *) +(*let rec find m off = function*) +(*| [] -> []*) +(*| e :: l -> if m=e then off :: find m (off+1) l*) +(*else find m (off+1) l*) +(*in find m 0 l*) + +module TimeHash = Hashtbl + +(*Hash table : time => list of instruction ids *) + +let hashtbl2flatarray h maxint = + let rec f i = + match TimeHash.find_opt h i with + | None -> if i > maxint then [] else f (i + 1) + | Some bund -> bund @ f (i + 1) + in + f 0 + +let find_max l = + let rec f = function + | [] -> None + | e :: l -> ( + match f l with + | None -> Some e + | Some m -> if e > m then Some e else Some m ) + in + match f l with None -> raise Not_found | Some m -> m + +(*(* [0, 2, 3, 1, 1, 2, 4, 5] -> [[0], [3, 4], [1, 5], [2], [6], [7]] *)*) +let minpack_list (l : int list) = + let timehash = TimeHash.create (List.length l) in + let rec f i = function + | [] -> () + | t :: l -> + ( match TimeHash.find_opt timehash t with + | None -> TimeHash.add timehash t [ i ] + | Some bund -> TimeHash.replace timehash t (bund @ [ i ]) ); + f (i + 1) l + in + f 0 l; + hashtbl2flatarray timehash (find_max l) + +(*let minpack_list l =*) +(*let mins = find_mins l*) +(*in List.map (fun m -> find_all_indices m l) mins*) + +let bb_to_instrs bb = + body_to_instrs bb.body + @ match bb.exit with None -> [] | Some e -> [ PControl e ] + +let build_solution bb sol = + (* Remove last element - the total *) + let tmp = Array.to_list @@ Array.sub sol 0 (Array.length sol - 1) in + let pack = minpack_list tmp and instrs = bb_to_instrs bb in + repack (get_from_indexes pack instrs) bb.header + +(*in let rec bund hd = function*) +(*| [] -> []*) +(*| pack :: packs -> repack (get_from_indexes pack instrs) hd :: (bund [] packs)*) +(*in bund bb.header packs*) + +(*let print_inst oc = function i -> TargetPrinter.Target.print_instructions oc i*) +(*| Asm.Pallocframe(sz, ofs) -> Printf.fprintf oc " Pallocframe\n"*) +(*| Asm.Pfreeframe(sz, ofs) -> Printf.fprintf oc " Pfreeframe\n"*) +(*| Asm.Pbuiltin(ef, args, res) -> Printf.fprintf oc " Pbuiltin\n"*) + +(*let print_bb oc bb =*) +(*match Asmgen.Asmblock_TRANSF.unfold_bblock bb with*) +(*| Errors.OK instructions -> List.iter (print_inst oc) instructions*) +(*| Errors.Error _ -> Printf.eprintf "Error in print_bb"*) + +let print_schedule sched = + print_string "[ "; + Array.iter (fun x -> Printf.printf "%d; " x) sched; + print_endline "]" + +let do_schedule bb = + let problem = build_problem bb in + if debug then print_problem stdout problem; + let solution = scheduler_by_name !Clflags.option_fpostpass_sched problem in + match solution with + | None -> failwith "Could not find a valid schedule" + | Some sol -> + if debug then print_schedule sol; + build_solution bb sol + +(** + * Dumb schedule if the above doesn't work + *) + +(* Pack result *) +let pack_result (bb : bblock) = (bb.body, bb.exit) + +(** + * Separates the opaque instructions such as Pfreeframe and Pallocframe + *) + +(*let is_opaque = function*) +(*| Pallocframe _ | Pfreeframe _ -> true*) +(*| _ -> false*) + +(*(* Returns : (accumulated instructions, remaining instructions, opaque instruction if found) *)*) +(*let rec biggest_wo_opaque = function + | [] -> ([], [], None) + | i :: li -> if is_opaque i then ([], li, Some i) + else let big, rem, opaque = biggest_wo_opaque li in (i :: big, rem, opaque);; + +let separate_opaque bb = + let instrs = bb_to_instrs bb + in let rec f hd li = + match li with + | [] -> [] + | li -> let big, rem, opaque = biggest_wo_opaque li in + match opaque with + | Some i -> + (match big with + | [] -> (repack [i] hd) :: (f [] rem) + | big -> (repack big hd) :: (bundlize [i] []) :: (f [] rem) + ) + | None -> (bundlize big hd) :: (f [] rem) + in f bb.header instrs*) + +let smart_schedule bb = + let bb' = + try do_schedule bb with + | OpaqueInstruction -> + if debug then + Printf.eprintf "OpaqueInstruction raised, using identity scheduling\n"; + bb (* Identity in case of failure *) + | e -> + let msg = Printexc.to_string e and stack = Printexc.get_backtrace () in + Printf.eprintf "Postpass scheduling could not complete: %s\n%s" msg + stack; + failwith "Invalid schedule" + in + pack_result bb' + +let bblock_schedule bb = + let identity_mode = not !Clflags.option_fpostpass in + if debug && not identity_mode then ( + Printf.eprintf "###############################\n"; + Printf.eprintf "SCHEDULING\n" ); + if identity_mode then pack_result bb else smart_schedule bb + +(** Called schedule function from Coq *) + +(*let schedule_notime bb = let toto = bblock_schedule in toto*) +let schedule bb = + Timing.time_coq + [ + 'P'; + 'o'; + 's'; + 't'; + 'p'; + 'a'; + 's'; + 's'; + 'S'; + 'c'; + 'h'; + 'e'; + 'd'; + 'u'; + 'l'; + 'i'; + 'n'; + 'g'; + ' '; + 'o'; + 'r'; + 'a'; + 'c'; + 'l'; + 'e'; + ] + bblock_schedule bb diff --git a/aarch64/PostpassSchedulingproof.v b/aarch64/PostpassSchedulingproof.v new file mode 100644 index 00000000..86a160bd --- /dev/null +++ b/aarch64/PostpassSchedulingproof.v @@ -0,0 +1,690 @@ +(* *************************************************************) +(* *) +(* The Compcert verified compiler *) +(* *) +(* Sylvain Boulmé Grenoble-INP, VERIMAG *) +(* David Monniaux CNRS, VERIMAG *) +(* Cyril Six Kalray *) +(* *) +(* Copyright Kalray. Copyright VERIMAG. All rights reserved. *) +(* This file is distributed under the terms of the INRIA *) +(* Non-Commercial License Agreement. *) +(* *) +(* *************************************************************) + +Require Import Coqlib Errors. +Require Import Integers Floats AST Linking. +Require Import Values Memory Events Globalenvs Smallstep. +Require Import Op Locations Machblock Conventions Asmblock. +Require Import Asmblockgenproof0 Asmblockprops. +Require Import PostpassScheduling. +Require Import Asmblockgenproof. +Require Import Axioms. + +Local Open Scope error_monad_scope. + +Definition match_prog (p tp: Asmblock.program) := + match_program (fun _ f tf => transf_fundef f = OK tf) eq p tp. + +Lemma transf_program_match: + forall p tp, transf_program p = OK tp -> match_prog p tp. +Proof. + intros. eapply match_transform_partial_program; eauto. +Qed. + +(* +Lemma regset_double_set_id: + forall r (rs: regset) v1 v2, + (rs # r <- v1 # r <- v2) = (rs # r <- v2). +Proof. + intros. apply functional_extensionality. intros. destruct (preg_eq r x). + - subst r. repeat (rewrite Pregmap.gss; auto). + - repeat (rewrite Pregmap.gso); auto. +Qed. + +Lemma exec_body_pc_var: + forall l ge rs m rs' m' v, + exec_body ge l rs m = Next rs' m' -> + exec_body ge l (rs # PC <- v) m = Next (rs' # PC <- v) m'. +Proof. + induction l. + - intros. simpl. simpl in H. inv H. auto. + - intros. simpl in *. + destruct (exec_basic_instr ge a rs m) eqn:EXEBI; try discriminate. + erewrite exec_basic_instr_pc_var; eauto. +Qed. + +Lemma pc_set_add: + forall rs v r x y, + 0 <= x <= Ptrofs.max_unsigned -> + 0 <= y <= Ptrofs.max_unsigned -> + rs # r <- (Val.offset_ptr v (Ptrofs.repr (x + y))) = rs # r <- (Val.offset_ptr (rs # r <- (Val.offset_ptr v (Ptrofs.repr x)) r) (Ptrofs.repr y)). +Proof. + intros. apply functional_extensionality. intros r0. destruct (preg_eq r r0). + - subst. repeat (rewrite Pregmap.gss); auto. + destruct v; simpl; auto. + rewrite Ptrofs.add_assoc. + enough (Ptrofs.repr (x + y) = Ptrofs.add (Ptrofs.repr x) (Ptrofs.repr y)) as ->; auto. + unfold Ptrofs.add. + enough (x + y = Ptrofs.unsigned (Ptrofs.repr x) + Ptrofs.unsigned (Ptrofs.repr y)) as ->; auto. + repeat (rewrite Ptrofs.unsigned_repr); auto. + - repeat (rewrite Pregmap.gso; auto). +Qed. + +Lemma concat2_straight: + forall a b bb rs m rs'' m'' f ge, + concat2 a b = OK bb -> + exec_bblock ge f bb rs m = Next rs'' m'' -> + exists rs' m', + exec_bblock ge f a rs m = Next rs' m' + /\ rs' PC = Val.offset_ptr (rs PC) (Ptrofs.repr (size a)) + /\ exec_bblock ge f b rs' m' = Next rs'' m''. +Proof. + intros until ge. intros CONC2 EXEB. + exploit concat2_zlt_size; eauto. intros (LTA & LTB). + exploit concat2_noexit; eauto. intros EXA. + exploit concat2_decomp; eauto. intros. inv H. + unfold exec_bblock in EXEB. destruct (exec_body ge (body bb) rs m) eqn:EXEB'; try discriminate. + rewrite H0 in EXEB'. apply exec_body_app in EXEB'. destruct EXEB' as (rs1 & m1 & EXEB1 & EXEB2). + eexists; eexists. split. + unfold exec_bblock. rewrite EXEB1. rewrite EXA. simpl. eauto. + split. + exploit exec_body_pc. eapply EXEB1. intros. rewrite <- H. auto. + unfold exec_bblock. unfold nextblock, incrPC. rewrite regset_same_assign. erewrite exec_body_pc_var; eauto. + rewrite <- H1. unfold nextblock in EXEB. rewrite regset_double_set_id. + assert (size bb = size a + size b). + { unfold size. rewrite H0. rewrite H1. rewrite app_length. rewrite EXA. simpl. rewrite Nat.add_0_r. + repeat (rewrite Nat2Z.inj_add). omega. } + clear EXA H0 H1. rewrite H in EXEB. + assert (rs1 PC = rs0 PC). { apply exec_body_pc in EXEB2. auto. } + rewrite H0. rewrite <- pc_set_add; auto. + exploit size_positive. instantiate (1 := a). intro. omega. + exploit size_positive. instantiate (1 := b). intro. omega. +Qed. + +Lemma concat_all_exec_bblock (ge: Genv.t fundef unit) (f: function) : + forall a bb rs m lbb rs'' m'', + lbb <> nil -> + concat_all (a :: lbb) = OK bb -> + exec_bblock ge f bb rs m = Next rs'' m'' -> + exists bb' rs' m', + concat_all lbb = OK bb' + /\ exec_bblock ge f a rs m = Next rs' m' + /\ rs' PC = Val.offset_ptr (rs PC) (Ptrofs.repr (size a)) + /\ exec_bblock ge f bb' rs' m' = Next rs'' m''. +Proof. + intros until m''. intros Hnonil CONC EXEB. + simpl in CONC. + destruct lbb as [|b lbb]; try contradiction. clear Hnonil. + monadInv CONC. exploit concat2_straight; eauto. intros (rs' & m' & EXEB1 & PCeq & EXEB2). + exists x. repeat econstructor. all: eauto. +Qed. + +Lemma ptrofs_add_repr : + forall a b, + Ptrofs.unsigned (Ptrofs.add (Ptrofs.repr a) (Ptrofs.repr b)) = Ptrofs.unsigned (Ptrofs.repr (a + b)). +Proof. + intros a b. + rewrite Ptrofs.add_unsigned. repeat (rewrite Ptrofs.unsigned_repr_eq). + rewrite <- Zplus_mod. auto. +Qed. + +Section PRESERVATION_ASMBLOCK. + +Variables prog tprog: program. +Hypothesis TRANSL: match_prog prog tprog. +Let ge := Genv.globalenv prog. +Let tge := Genv.globalenv tprog. + +Lemma transf_function_no_overflow: + forall f tf, + transf_function f = OK tf -> size_blocks tf.(fn_blocks) <= Ptrofs.max_unsigned. +Proof. + intros. monadInv H. destruct (zlt Ptrofs.max_unsigned (size_blocks x.(fn_blocks))); inv EQ0. + omega. +Qed. + +Lemma symbols_preserved: + forall id, + Genv.find_symbol tge id = Genv.find_symbol ge id. +Proof (Genv.find_symbol_match TRANSL). + +Lemma senv_preserved: + Senv.equiv ge tge. +Proof (Genv.senv_match TRANSL). + +Lemma functions_translated: + forall v f, + Genv.find_funct ge v = Some f -> + exists tf, + Genv.find_funct tge v = Some tf /\ transf_fundef f = OK tf. +Proof (Genv.find_funct_transf_partial TRANSL). + +Lemma function_ptr_translated: + forall v f, + Genv.find_funct_ptr ge v = Some f -> + exists tf, + Genv.find_funct_ptr tge v = Some tf /\ transf_fundef f = OK tf. +Proof (Genv.find_funct_ptr_transf_partial TRANSL). + +Lemma functions_transl: + forall fb f tf, + Genv.find_funct_ptr ge fb = Some (Internal f) -> + transf_function f = OK tf -> + Genv.find_funct_ptr tge fb = Some (Internal tf). +Proof. + intros. exploit function_ptr_translated; eauto. + intros (tf' & A & B). monadInv B. rewrite H0 in EQ. inv EQ. auto. +Qed. + +Inductive match_states: state -> state -> Prop := + | match_states_intro: + forall s1 s2, s1 = s2 -> match_states s1 s2. + +Lemma prog_main_preserved: + prog_main tprog = prog_main prog. +Proof (match_program_main TRANSL). + +Lemma prog_main_address_preserved: + (Genv.symbol_address (Genv.globalenv prog) (prog_main prog) Ptrofs.zero) = + (Genv.symbol_address (Genv.globalenv tprog) (prog_main tprog) Ptrofs.zero). +Proof. + unfold Genv.symbol_address. rewrite symbols_preserved. + rewrite prog_main_preserved. auto. +Qed. + +Lemma transf_initial_states: + forall st1, initial_state prog st1 -> + exists st2, initial_state tprog st2 /\ match_states st1 st2. +Proof. + intros. inv H. + econstructor; split. + - eapply initial_state_intro. + eapply (Genv.init_mem_transf_partial TRANSL); eauto. + - econstructor; eauto. subst ge0. subst rs0. rewrite prog_main_address_preserved. auto. +Qed. + +Lemma transf_final_states: + forall st1 st2 r, + match_states st1 st2 -> final_state st1 r -> final_state st2 r. +Proof. + intros. inv H0. inv H. econstructor; eauto. +Qed. + +Lemma tail_find_bblock: + forall lbb pos bb, + find_bblock pos lbb = Some bb -> + exists c, code_tail pos lbb (bb::c). +Proof. + induction lbb. + - intros. simpl in H. inv H. + - intros. simpl in H. + destruct (zlt pos 0); try (inv H; fail). + destruct (zeq pos 0). + + inv H. exists lbb. constructor; auto. + + apply IHlbb in H. destruct H as (c & TAIL). exists c. + enough (pos = pos - size a + size a) as ->. + apply code_tail_S; auto. + omega. +Qed. + +Lemma code_tail_head_app: + forall l pos c1 c2, + code_tail pos c1 c2 -> + code_tail (pos + size_blocks l) (l++c1) c2. +Proof. + induction l. + - intros. simpl. rewrite Z.add_0_r. auto. + - intros. apply IHl in H. simpl. rewrite (Z.add_comm (size a)). rewrite Z.add_assoc. apply code_tail_S. assumption. +Qed. + +Lemma transf_blocks_verified: + forall c tc pos bb c', + transf_blocks c = OK tc -> + code_tail pos c (bb::c') -> + exists lbb, + verified_schedule bb = OK lbb + /\ exists tc', code_tail pos tc (lbb ++ tc'). +Proof. + induction c; intros. + - simpl in H. inv H. inv H0. + - inv H0. + + monadInv H. exists x0. + split; simpl; auto. eexists; eauto. econstructor; eauto. + + unfold transf_blocks in H. fold transf_blocks in H. monadInv H. + exploit IHc; eauto. + intros (lbb & TRANS & tc' & TAIL). +(* monadInv TRANS. *) + repeat eexists; eauto. + erewrite verified_schedule_size; eauto. + apply code_tail_head_app. + eauto. +Qed. + +Lemma transf_find_bblock: + forall ofs f bb tf, + find_bblock (Ptrofs.unsigned ofs) (fn_blocks f) = Some bb -> + transf_function f = OK tf -> + exists lbb, + verified_schedule bb = OK lbb + /\ exists c, code_tail (Ptrofs.unsigned ofs) (fn_blocks tf) (lbb ++ c). +Proof. + intros. + monadInv H0. destruct (zlt Ptrofs.max_unsigned (size_blocks (fn_blocks x))); try (inv EQ0; fail). inv EQ0. + monadInv EQ. apply tail_find_bblock in H. destruct H as (c & TAIL). + eapply transf_blocks_verified; eauto. +Qed. + +Lemma symbol_address_preserved: + forall l ofs, Genv.symbol_address ge l ofs = Genv.symbol_address tge l ofs. +Proof. + intros. unfold Genv.symbol_address. repeat (rewrite symbols_preserved). reflexivity. +Qed. + +Lemma head_tail {A: Type}: + forall (l: list A) hd, hd::l = hd :: (tail (hd::l)). +Proof. + intros. simpl. auto. +Qed. + +Lemma verified_schedule_not_empty: + forall bb lbb, + verified_schedule bb = OK lbb -> lbb <> nil. +Proof. + intros. apply verified_schedule_size in H. + pose (size_positive bb). assert (size_blocks lbb > 0) by omega. clear H g. + destruct lbb; simpl in *; discriminate. +Qed. + +Lemma header_nil_label_pos_none: + forall lbb l p, + Forall (fun b => header b = nil) lbb -> label_pos l p lbb = None. +Proof. + induction lbb. + - intros. simpl. auto. + - intros. inv H. simpl. unfold is_label. rewrite H2. destruct (in_dec l nil). { inv i. } + auto. +Qed. + +Lemma verified_schedule_label: + forall bb tbb lbb l, + verified_schedule bb = OK (tbb :: lbb) -> + is_label l bb = is_label l tbb + /\ label_pos l 0 lbb = None. +Proof. + intros. exploit verified_schedule_header; eauto. + intros (HdrEq & HdrNil). + split. + - unfold is_label. rewrite HdrEq. reflexivity. + - apply header_nil_label_pos_none. assumption. +Qed. + +Lemma label_pos_app_none: + forall c c' l p p', + label_pos l p c = None -> + label_pos l (p' + size_blocks c) c' = label_pos l p' (c ++ c'). +Proof. + induction c. + - intros. simpl in *. rewrite Z.add_0_r. reflexivity. + - intros. simpl in *. destruct (is_label _ _) eqn:ISLABEL. + + discriminate. + + eapply IHc in H. rewrite Z.add_assoc. eauto. +Qed. + +Remark label_pos_pvar_none_add: + forall tc l p p' k, + label_pos l (p+k) tc = None -> label_pos l (p'+k) tc = None. +Proof. + induction tc. + - intros. simpl. auto. + - intros. simpl in *. destruct (is_label _ _) eqn:ISLBL. + + discriminate. + + pose (IHtc l p p' (k + size a)). repeat (rewrite Z.add_assoc in e). auto. +Qed. + +Lemma label_pos_pvar_none: + forall tc l p p', + label_pos l p tc = None -> label_pos l p' tc = None. +Proof. + intros. rewrite (Zplus_0_r_reverse p') at 1. rewrite (Zplus_0_r_reverse p) in H at 1. + eapply label_pos_pvar_none_add; eauto. +Qed. + +Remark label_pos_pvar_some_add_add: + forall tc l p p' k k', + label_pos l (p+k') tc = Some (p+k) -> label_pos l (p'+k') tc = Some (p'+k). +Proof. + induction tc. + - intros. simpl in H. discriminate. + - intros. simpl in *. destruct (is_label _ _) eqn:ISLBL. + + inv H. assert (k = k') by omega. subst. reflexivity. + + pose (IHtc l p p' k (k' + size a)). repeat (rewrite Z.add_assoc in e). auto. +Qed. + +Lemma label_pos_pvar_some_add: + forall tc l p p' k, + label_pos l p tc = Some (p+k) -> label_pos l p' tc = Some (p'+k). +Proof. + intros. rewrite (Zplus_0_r_reverse p') at 1. rewrite (Zplus_0_r_reverse p) in H at 1. + eapply label_pos_pvar_some_add_add; eauto. +Qed. + +Remark label_pos_pvar_add: + forall c tc l p p' k, + label_pos l (p+k) c = label_pos l p tc -> + label_pos l (p'+k) c = label_pos l p' tc. +Proof. + induction c. + - intros. simpl in *. + exploit label_pos_pvar_none; eauto. + - intros. simpl in *. destruct (is_label _ _) eqn:ISLBL. + + exploit label_pos_pvar_some_add; eauto. + + pose (IHc tc l p p' (k+size a)). repeat (rewrite Z.add_assoc in e). auto. +Qed. + +Lemma label_pos_pvar: + forall c tc l p p', + label_pos l p c = label_pos l p tc -> + label_pos l p' c = label_pos l p' tc. +Proof. + intros. rewrite (Zplus_0_r_reverse p') at 1. rewrite (Zplus_0_r_reverse p) in H at 1. + eapply label_pos_pvar_add; eauto. +Qed. + +Lemma label_pos_head_app: + forall c bb lbb l tc p, + verified_schedule bb = OK lbb -> + label_pos l p c = label_pos l p tc -> + label_pos l p (bb :: c) = label_pos l p (lbb ++ tc). +Proof. + intros. simpl. destruct lbb as [|tbb lbb]. + - apply verified_schedule_not_empty in H. contradiction. + - simpl. exploit verified_schedule_label; eauto. intros (ISLBL & LBLPOS). + rewrite ISLBL. + destruct (is_label l tbb) eqn:ISLBL'; simpl; auto. + eapply label_pos_pvar in H0. erewrite H0. + erewrite verified_schedule_size; eauto. simpl size_blocks. rewrite Z.add_assoc. + erewrite label_pos_app_none; eauto. +Qed. + +Lemma label_pos_preserved: + forall c tc l, + transf_blocks c = OK tc -> label_pos l 0 c = label_pos l 0 tc. +Proof. + induction c. + - intros. simpl in *. inv H. reflexivity. + - intros. unfold transf_blocks in H; fold transf_blocks in H. monadInv H. eapply IHc in EQ. + eapply label_pos_head_app; eauto. +Qed. + +Lemma label_pos_preserved_blocks: + forall l f tf, + transf_function f = OK tf -> + label_pos l 0 (fn_blocks f) = label_pos l 0 (fn_blocks tf). +Proof. + intros. monadInv H. monadInv EQ. + destruct (zlt Ptrofs.max_unsigned _); try discriminate. + monadInv EQ0. simpl. eapply label_pos_preserved; eauto. +Qed. + +Lemma transf_exec_control: + forall f tf ex rs m, + transf_function f = OK tf -> + exec_control ge f ex rs m = exec_control tge tf ex rs m. +Proof. + intros. destruct ex; simpl; auto. + assert (ge = Genv.globalenv prog). auto. + assert (tge = Genv.globalenv tprog). auto. + pose symbol_address_preserved. + exploreInst; simpl; auto; try congruence; + unfold par_goto_label; unfold par_eval_branch; unfold par_goto_label; erewrite label_pos_preserved_blocks; eauto. +Qed. + +Lemma transf_exec_basic_instr: + forall i rs m, exec_basic_instr ge i rs m = exec_basic_instr tge i rs m. +Proof. + intros. pose symbol_address_preserved. + unfold exec_basic_instr. unfold bstep. exploreInst; simpl; auto; try congruence. + unfold parexec_arith_instr; unfold arith_eval_r; exploreInst; simpl; auto; try congruence. +Qed. + +Lemma transf_exec_body: + forall bdy rs m, exec_body ge bdy rs m = exec_body tge bdy rs m. +Proof. + induction bdy; intros. + - simpl. reflexivity. + - simpl. rewrite transf_exec_basic_instr. + destruct (exec_basic_instr _ _ _); auto. +Qed. + +Lemma transf_exec_bblock: + forall f tf bb rs m, + transf_function f = OK tf -> + exec_bblock ge f bb rs m = exec_bblock tge tf bb rs m. +Proof. + intros. unfold exec_bblock. rewrite transf_exec_body. destruct (exec_body _ _ _ _); auto. + eapply transf_exec_control; eauto. +Qed. + +Lemma transf_step_simu: + forall tf b lbb ofs c tbb rs m rs' m', + Genv.find_funct_ptr tge b = Some (Internal tf) -> + size_blocks (fn_blocks tf) <= Ptrofs.max_unsigned -> + rs PC = Vptr b ofs -> + code_tail (Ptrofs.unsigned ofs) (fn_blocks tf) (lbb ++ c) -> + concat_all lbb = OK tbb -> + exec_bblock tge tf tbb rs m = Next rs' m' -> + plus step tge (State rs m) E0 (State rs' m'). +Proof. + induction lbb. + - intros until m'. simpl. intros. discriminate. + - intros until m'. intros GFIND SIZE PCeq TAIL CONC EXEB. + destruct lbb. + + simpl in *. clear IHlbb. inv CONC. eapply plus_one. econstructor; eauto. eapply find_bblock_tail; eauto. + + exploit concat_all_exec_bblock; eauto; try discriminate. + intros (tbb0 & rs0 & m0 & CONC0 & EXEB0 & PCeq' & EXEB1). + eapply plus_left. + econstructor. + 3: eapply find_bblock_tail. rewrite <- app_comm_cons in TAIL. 3: eauto. + all: eauto. + eapply plus_star. eapply IHlbb; eauto. rewrite PCeq in PCeq'. simpl in PCeq'. all: eauto. + eapply code_tail_next_int; eauto. +Qed. + +Theorem transf_step_correct: + forall s1 t s2, step ge s1 t s2 -> + forall s1' (MS: match_states s1 s1'), + (exists s2', plus step tge s1' t s2' /\ match_states s2 s2'). +Proof. + induction 1; intros; inv MS. + - exploit function_ptr_translated; eauto. intros (tf & FFP & TRANSF). monadInv TRANSF. + exploit transf_find_bblock; eauto. intros (lbb & VES & c & TAIL). + exploit verified_schedule_correct; eauto. intros (tbb & CONC & BBEQ). inv CONC. rename H3 into CONC. + assert (NOOV: size_blocks x.(fn_blocks) <= Ptrofs.max_unsigned). + eapply transf_function_no_overflow; eauto. + + erewrite transf_exec_bblock in H2; eauto. + unfold bblock_simu in BBEQ. rewrite BBEQ in H2; try congruence. + exists (State rs' m'). split; try (constructor; auto). + eapply transf_step_simu; eauto. + + - exploit function_ptr_translated; eauto. intros (tf & FFP & TRANSF). monadInv TRANSF. + exploit transf_find_bblock; eauto. intros (lbb & VES & c & TAIL). + exploit verified_schedule_builtin_idem; eauto. intros. subst lbb. + + remember (State (nextblock _ _) _) as s'. exists s'. + split; try constructor; auto. + eapply plus_one. subst s'. + eapply exec_step_builtin. + 3: eapply find_bblock_tail. simpl in TAIL. 3: eauto. + all: eauto. + eapply eval_builtin_args_preserved with (ge1 := ge). exact symbols_preserved. eauto. + eapply external_call_symbols_preserved; eauto. apply senv_preserved. + + - exploit function_ptr_translated; eauto. intros (tf & FFP & TRANSF). monadInv TRANSF. + remember (State _ m') as s'. exists s'. split; try constructor; auto. + subst s'. eapply plus_one. eapply exec_step_external; eauto. + eapply external_call_symbols_preserved; eauto. apply senv_preserved. +Qed. + +Theorem transf_program_correct_Asmblock: + forward_simulation (Asmblock.semantics prog) (Asmblock.semantics tprog). +Proof. + eapply forward_simulation_plus. + - apply senv_preserved. + - apply transf_initial_states. + - apply transf_final_states. + - apply transf_step_correct. +Qed. + +End PRESERVATION_ASMBLOCK. + +Require Import Asmvliw. + +Lemma verified_par_checks_alls_bundles lb x: forall bundle, + verify_par lb = OK x -> + List.In bundle lb -> verify_par_bblock bundle = OK tt. +Proof. + induction lb; simpl; try tauto. + intros bundle H; monadInv H. + destruct 1; subst; eauto. + destruct x0; auto. +Qed. + +Lemma verified_schedule_nob_checks_alls_bundles bb lb bundle: + verified_schedule_nob bb = OK lb -> + List.In bundle lb -> verify_par_bblock bundle = OK tt. +Proof. + unfold verified_schedule_nob. intros H; + monadInv H. destruct x4. + intros; eapply verified_par_checks_alls_bundles; eauto. +Qed. + +Lemma verify_par_bblock_PExpand bb i: + exit bb = Some (PExpand i) -> verify_par_bblock bb = OK tt. +Proof. + destruct bb as [h bdy ext H]; simpl. + intros; subst. destruct i. + generalize H. + rewrite <- wf_bblock_refl in H. + destruct H as [H H0]. + unfold builtin_alone in H0. erewrite H0; eauto. +Qed. + +Local Hint Resolve verified_schedule_nob_checks_alls_bundles: core. + +Lemma verified_schedule_checks_alls_bundles bb lb bundle: + verified_schedule bb = OK lb -> + List.In bundle lb -> verify_par_bblock bundle = OK tt. +Proof. + unfold verified_schedule. remember (exit bb) as exb. + destruct exb as [c|]; eauto. + destruct c as [i|]; eauto. + destruct i; intros H. inversion_clear H; simpl. + intuition subst. + intros; eapply verify_par_bblock_PExpand; eauto. +Qed. + +Lemma transf_blocks_checks_all_bundles lbb: forall lb bundle, + transf_blocks lbb = OK lb -> + List.In bundle lb -> verify_par_bblock bundle = OK tt. +Proof. + induction lbb; simpl. + - intros lb bundle H; inversion_clear H. simpl; try tauto. + - intros lb bundle H0. + monadInv H0. + rewrite in_app. destruct 1; eauto. + eapply verified_schedule_checks_alls_bundles; eauto. +Qed. + +Lemma find_bblock_Some_in lb: + forall ofs b, find_bblock ofs lb = Some b -> List.In b lb. +Proof. + induction lb; simpl; try congruence. + intros ofs b. + destruct (zlt ofs 0); try congruence. + destruct (zeq ofs 0); eauto. + intros X; inversion X; eauto. +Qed. + +Section PRESERVATION_ASMVLIW. + +Variables prog tprog: program. +Hypothesis TRANSL: match_prog prog tprog. +Let ge := Genv.globalenv prog. +Let tge := Genv.globalenv tprog. + +Lemma all_bundles_are_checked b ofs f bundle: + Genv.find_funct_ptr (globalenv (Asmblock.semantics tprog)) b = Some (Internal f) -> + find_bblock ofs (fn_blocks f) = Some bundle -> + verify_par_bblock bundle = OK tt. +Proof. + unfold match_prog, match_program in TRANSL. + unfold Genv.find_funct_ptr; simpl; intros X. + destruct (Genv.find_def_match_2 TRANSL b) as [|f0 y H]; try congruence. + destruct y as [tf0|]; try congruence. + inversion X as [H1]. subst. clear X. + remember (@Gfun fundef unit (Internal f)) as f2. + destruct H as [ctx' f1 f2 H0|]; try congruence. + inversion Heqf2 as [H2]. subst; clear Heqf2. + unfold transf_fundef, transf_partial_fundef in H. + destruct f1 as [f1|f1]; try congruence. + unfold transf_function, transl_function in H. + monadInv H. monadInv EQ. + destruct (zlt Ptrofs.max_unsigned (size_blocks (fn_blocks _))); simpl in *|-; try congruence. + injection EQ1; intros; subst. + monadInv EQ0. simpl in * |-. + intros; exploit transf_blocks_checks_all_bundles; eauto. + intros; eapply find_bblock_Some_in; eauto. +Qed. + +Lemma checked_bundles_are_parexec_equiv f bundle rs rs' m m': + exec_bblock (globalenv (Asmblock.semantics tprog)) f bundle rs m = Next rs' m' -> + verify_par_bblock bundle = OK tt -> + det_parexec (globalenv (semantics tprog)) f bundle rs m rs' m'. +Proof. + intros. unfold verify_par_bblock in H0. destruct (Asmblockdeps.bblock_para_check _) eqn:BPC; try discriminate. clear H0. + simpl in H. + eapply Asmblockdeps.bblock_para_check_correct; eauto. +Qed. + +Lemma seqexec_parexec_equiv b ofs f bundle rs rs' m m': + Genv.find_funct_ptr (globalenv (Asmblock.semantics tprog)) b = Some (Internal f) -> + find_bblock (Ptrofs.unsigned ofs) (fn_blocks f) = Some bundle -> + exec_bblock (globalenv (Asmblock.semantics tprog)) f bundle rs m = Next rs' m' -> + det_parexec (globalenv (semantics tprog)) f bundle rs m rs' m'. +Proof. + intros; eapply checked_bundles_are_parexec_equiv; eauto. + eapply all_bundles_are_checked; eauto. +Qed. + +Theorem transf_program_correct_Asmvliw: + forward_simulation (Asmblock.semantics tprog) (Asmvliw.semantics tprog). +Proof. + eapply forward_simulation_step with (match_states:=fun (s1:Asmvliw.state) s2 => s1=s2); eauto. + - intros; subst; auto. + - intros s1 t s1' H s2 H0; subst; inversion H; clear H; subst; eexists; split; eauto. + + eapply exec_step_internal; eauto. + intros; eapply seqexec_parexec_equiv; eauto. + + eapply exec_step_builtin; eauto. + + eapply exec_step_external; eauto. +Qed. + +End PRESERVATION_ASMVLIW. + +Section PRESERVATION. + +Variables prog tprog: program. +Hypothesis TRANSL: match_prog prog tprog. +Let ge := Genv.globalenv prog. +Let tge := Genv.globalenv tprog. + +Theorem transf_program_correct: + forward_simulation (Asmblock.semantics prog) (Asmvliw.semantics tprog). +Proof. + eapply compose_forward_simulations. + eapply transf_program_correct_Asmblock; eauto. + eapply transf_program_correct_Asmvliw; eauto. +Qed. + +End PRESERVATION.*) diff --git a/aarch64/TargetPrinter.ml b/aarch64/TargetPrinter.ml index 8d74daf4..324bd727 100644 --- a/aarch64/TargetPrinter.ml +++ b/aarch64/TargetPrinter.ml @@ -38,7 +38,7 @@ let is_immediate_float32 bits = (* Module containing the printing functions *) -module Target : TARGET = +module Target (*: TARGET*) = struct (* Basic printing functions *) @@ -120,13 +120,13 @@ module Target : TARGET = output_string oc (match sz with D -> dreg_name r | S -> sreg_name r) let preg_asm oc ty = function - | IR r -> if ty = Tint then wreg oc r else xreg oc r - | FR r -> if ty = Tsingle then sreg oc r else dreg oc r + | DR (IR (RR1 r)) -> if ty = Tint then wreg oc r else xreg oc r + | DR (FR r) -> if ty = Tsingle then sreg oc r else dreg oc r | _ -> assert false let preg_annot = function - | IR r -> xreg_name r - | FR r -> dreg_name r + | DR (IR (RR1 r)) -> xreg_name r + | DR (FR r) -> dreg_name r | _ -> assert false (* Names of sections *) diff --git a/aarch64/extractionMachdep.v b/aarch64/extractionMachdep.v index e82056e2..6815bc59 100644 --- a/aarch64/extractionMachdep.v +++ b/aarch64/extractionMachdep.v @@ -21,4 +21,4 @@ Extract Constant Archi.pic_code => "fun () -> false". (* for the time being *) (* Asm *) Extract Constant Asm.symbol_low => "fun _ _ _ -> assert false". Extract Constant Asm.symbol_high => "fun _ _ _ -> assert false". -Extract Constant Asmgen.symbol_is_aligned => "C2C.atom_is_aligned". +Extract Constant Asmblockgen.symbol_is_aligned => "C2C.atom_is_aligned". @@ -696,6 +696,9 @@ echo "-R lib compcert.lib \ -R cparser compcert.cparser \ -R MenhirLib compcert.MenhirLib" > _CoqProject case $arch in + aarch64) + echo "-R kvx/lib compcert.kvx.lib -R kvx/abstractbb compcert.kvx.abstractbb" >> _CoqProject # import KVX libraries for aarch64 + ;; x86) echo "-R x86_${bitsize} compcert.x86_${bitsize}" >> _CoqProject ;; @@ -838,13 +841,27 @@ RESPONSEFILE="none" EOF fi +if [ "$arch" = "aarch64" ]; then # for aarch64 scheduling +cat >> Makefile.config <<EOF +ARCHDIRS=$arch kvx/lib kvx/abstractbb kvx/abstractbb/Impure +BACKENDLIB=Machblock.v Machblockgen.v Machblockgenproof.v OptionMonad.v IterList.v PseudoAsmblock.v PseudoAsmblockproof.v\\ + Asmblock.v Asmblockgen.v Asmblockgenproof0.v Asmblockgenproof1.v Asmblockgenproof.v Asm.v Asmblockprops.v\\ + ForwardSimulationBlock.v PostpassScheduling.v PostpassSchedulingproof.v\\ + Asmblockdeps.v\\ + AbstractBasicBlocksDef.v SeqSimuTheory.v ImpSimuTest.v Parallelizability.v\\ + ImpConfig.v ImpCore.v ImpExtern.v ImpHCons.v ImpIO.v ImpLoops.v ImpMonads.v ImpPrelude.v + # TODO: UPDATE THIS + # DecBoolOps.v Chunks.v Peephole.v ExtValues.v ExtFloats.v +EOF +fi + if [ "$arch" = "kvx" ]; then cat >> Makefile.config <<EOF ARCHDIRS=$arch $arch/lib $arch/abstractbb $arch/abstractbb/Impure EXECUTE=kvx-cluster --syscall=libstd_scalls.so -- CFLAGS= -D __KVX_COS__ SIMU=kvx-cluster -- -BACKENDLIB=Machblock.v Machblockgen.v Machblockgenproof.v\\ +BACKENDLIB=Machblock.v Machblockgen.v Machblockgenproof.v OptionMonad.v IterList.v PseudoAsmblock.v PseudoAsmblockproof.v\\ Asmblock.v Asmblockgen.v Asmblockgenproof0.v Asmblockgenproof1.v Asmblockgenproof.v Asmvliw.v Asmblockprops.v\\ ForwardSimulationBlock.v PostpassScheduling.v PostpassSchedulingproof.v\\ Asmblockdeps.v DecBoolOps.v Chunks.v Peephole.v ExtValues.v ExtFloats.v\\ diff --git a/extraction/extraction.v b/extraction/extraction.v index c5fa7a62..f5b8291b 100644 --- a/extraction/extraction.v +++ b/extraction/extraction.v @@ -13,6 +13,7 @@ (* *) (* *********************************************************************) +Require Import ZArith PeanoNat. Require Coqlib. Require Wfsimpl. Require DecidableClass Decidableplus. @@ -220,7 +221,8 @@ Set Extraction AccessOpaque. Cd "extraction". -Separate Extraction +Separate Extraction + Z.ldiff Z.lnot Nat.leb CSE3analysis.internal_analysis CSE3analysis.eq_depends_on_mem Compiler.transf_c_program Compiler.transf_cminor_program Cexec.do_initial_state Cexec.do_step Cexec.at_final_state diff --git a/kvx/lib/Asmblockgenproof0.v b/kvx/Asmblockgenproof0.v index 1af59238..1af59238 100644 --- a/kvx/lib/Asmblockgenproof0.v +++ b/kvx/Asmblockgenproof0.v diff --git a/kvx/abstractbb/ImpSimuTest.v b/kvx/abstractbb/ImpSimuTest.v index b1a3b985..6b64e1d8 100644 --- a/kvx/abstractbb/ImpSimuTest.v +++ b/kvx/abstractbb/ImpSimuTest.v @@ -23,9 +23,8 @@ Require Export Impure.ImpHCons. (**r Import the Impure library. See https://gith Export Notations. Import HConsing. - +Require Import Coq.Bool.Bool. Require Export SeqSimuTheory. - Require Import PArith. @@ -35,6 +34,8 @@ Import ListNotations. Local Open Scope list_scope. +Definition FULL_DEBUG_DUMP : bool := false. (* print debug traces, even if the verifier succeeds. *) + (** * Interface of (impure) equality tests for operators *) Module Type ImpParam. @@ -673,8 +674,8 @@ Hypothesis hco_term_correct: forall t, WHEN hco_term.(hC) t ~> t' THEN forall ge Variable hco_list: hashConsing list_term. Hypothesis hco_list_correct: forall t, WHEN hco_list.(hC) t ~> t' THEN forall ge m, list_term_eval ge (hdata t) m = list_term_eval ge t' m. -Variable print_error_end: hsmem -> hsmem -> ?? unit. -Variable print_error: pstring -> ?? unit. +Variable print_end_error: hsmem -> hsmem -> ?? unit. +Variable print_dump: (option pstring) -> ?? unit. Variable check_failpreserv: bool. Variable dbg_failpreserv: term -> ?? unit. (* info of additional failure of the output bbloc p2 wrt the input bbloc p1 *) @@ -687,20 +688,23 @@ Program Definition g_bblock_simu_test (p1 p2: bblock): ?? bool := DO d2 <~ bblock_hsmem hco_term.(hC) hco_list.(hC) no_log_assign log_new_term log_inst2 p2;; DO b <~ Dict.eq_test d1 d2 ;; if b then ( - if check_failpreserv then ( + (if check_failpreserv then let hp := mk_hash_params dbg_failpreserv in failure_in_failpreserv.(set)(true);; - Sets.assert_list_incl hp d2.(hpre) d1.(hpre);; - RET true - ) else RET false + Sets.assert_list_incl hp d2.(hpre) d1.(hpre) + else RET tt);; + (if FULL_DEBUG_DUMP then + print_dump None (* not an error... *) + else RET tt);; + RET check_failpreserv ) else ( - print_error_end d1 d2 ;; + print_end_error d1 d2 ;; RET false ) CATCH_FAIL s, _ => DO b <~ failure_in_failpreserv.(get)();; if b then RET false - else print_error s;; RET false + else print_dump (Some s);; RET false ENSURE (fun b => b=true -> forall ge, bblock_simu ge p1 p2));; RET (`r). Obligation 1. @@ -773,12 +777,16 @@ Definition msg_unknow_term: pstring := "unknown term". Definition msg_number: pstring := "on 2nd bblock -- on inst num ". Definition msg_notfailpreserv: pstring := "a possible failure of 2nd bblock is absent in 1st bblock (INTERNAL ERROR: this error is expected to be detected before!!!)". -Definition print_error_end (_ _: hsmem): ?? unit +Definition print_end_error (_ _: hsmem): ?? unit := println (msg_prefix +; msg_error_on_end). -Definition print_error (log: logger unit) (s:pstring): ?? unit - := DO n <~ log_info log ();; - println (msg_prefix +; msg_number +; n +; " -- " +; s). +Definition print_error (log: logger unit) (os: option pstring): ?? unit + := match os with + | Some s => + DO n <~ log_info log ();; + println (msg_prefix +; msg_number +; n +; " -- " +; s) + | None => RET tt + end. Definition failpreserv_error (_: term): ?? unit := println (msg_prefix +; msg_notfailpreserv). @@ -808,7 +816,7 @@ Program Definition bblock_simu_test (p1 p2: bblock): ?? bool := (log_insert log) hco_term _ hco_list _ - print_error_end + print_end_error (print_error log) true (* check_failpreserv *) failpreserv_error @@ -905,7 +913,6 @@ with string_of_list_term (l: list_term): ?? pstring := RET (st +; ";" +; sl) end. - End PrettryPrint. @@ -948,7 +955,7 @@ Definition print_tables gdi ext exl: ?? unit := iterall exl (fun head _ pl => print_list gdi head pl.(hdata));; println "----------------". -Definition print_final_debug gdi (d1 d2: hsmem): ?? unit +Definition print_final_debug gdi (d1 d2: hsmem): ?? unit := DO b <~ Dict.not_eq_witness d1 d2 ;; match b with | Some x => @@ -986,39 +993,44 @@ Definition print_witness gdi cr (*msg*) := | None => println "Unexpected failure: no witness info (hint: hash-consing bug ?)" end. - -Definition print_error_end1 gdi hct hcl (d1 d2:hsmem): ?? unit +Definition print_end_error1 gdi hct hcl (d1 d2:hsmem): ?? unit := println "- GRAPH of 1st bblock";; DO ext <~ export hct ();; DO exl <~ export hcl ();; print_tables gdi ext exl;; - print_error_end d1 d2;; + print_end_error d1 d2;; print_final_debug gdi d1 d2. -Definition print_error1 gdi hct hcl cr log s : ?? unit +Definition print_dump1 gdi hct hcl cr log os : ?? unit := println "- GRAPH of 1st bblock";; DO ext <~ export hct ();; DO exl <~ export hcl ();; print_tables gdi ext exl;; - print_error log s;; - print_witness gdi cr (*"1st"*). - + print_error log os;; + match os with + | Some _ => print_witness gdi cr (*"1st"*) + | None => RET tt + end. Definition xmsg_number: pstring := "on 1st bblock -- on inst num ". -Definition print_error_end2 gdi hct hcl (d1 d2:hsmem): ?? unit +Definition print_end_error2 gdi hct hcl (d1 d2:hsmem): ?? unit := println (msg_prefix +; msg_error_on_end);; println "- GRAPH of 2nd bblock";; DO ext <~ export hct ();; DO exl <~ export hcl ();; print_tables gdi ext exl. -Definition print_error2 gdi hct hcl cr (log: logger unit) (s:pstring): ?? unit +Definition print_dump2 gdi hct hcl cr (log: logger unit) (os:option pstring): ?? unit := DO n <~ log_info log ();; DO ext <~ export hct ();; DO exl <~ export hcl ();; - println (msg_prefix +; xmsg_number +; n +; " -- " +; s);; - print_witness gdi cr (*"2nd"*);; + match os with + | Some s => + println (msg_prefix +; xmsg_number +; n +; " -- " +; s);; + print_witness gdi cr (*"2nd"*) + | None => RET tt + end;; println "- GRAPH of 2nd bblock";; print_tables gdi ext exl. @@ -1051,21 +1063,25 @@ Program Definition verb_bblock_simu_test (p1 p2: bblock): ?? bool := DO cr <~ make_cref None;; DO hco_term <~ mk_annot (hCons hpt);; DO hco_list <~ mk_annot (hCons hplt);; - DO result1 <~ g_bblock_simu_test + (if FULL_DEBUG_DUMP then + println("");; + println("-- START simu checker --") + else RET tt);; + DO result1 <~ (g_bblock_simu_test (log_assign dict_info log1) (log_new_term (msg_term cr)) (hlog log1 hco_term hco_list) (log_insert log2) hco_term _ hco_list _ - (print_error_end1 dict_info.(D.get) hco_term hco_list) - (print_error1 dict_info.(D.get) hco_term hco_list cr log2) + (print_end_error1 dict_info.(D.get) hco_term hco_list) + (print_dump1 dict_info.(D.get) hco_term hco_list cr log2) true failpreserv_error - p1 p2;; - if result1 - then RET true - else + p1 p2);; + if (if FULL_DEBUG_DUMP then false else result1) + then RET true + else ( DO dict_info <~ make_dict (mk_hash_params (fun _ => RET tt));; DO log1 <~ count_logger ();; DO log2 <~ count_logger ();; @@ -1080,31 +1096,35 @@ Program Definition verb_bblock_simu_test (p1 p2: bblock): ?? bool := (log_insert log2) hco_term _ hco_list _ - (print_error_end2 dict_info.(D.get) hco_term hco_list) - (print_error2 dict_info.(D.get) hco_term hco_list cr log2) + (print_end_error2 dict_info.(D.get) hco_term hco_list) + (print_dump2 dict_info.(D.get) hco_term hco_list cr log2) false (fun _ => RET tt) p2 p1;; - if result2 - then ( - println (msg_prefix +; " OOops - symmetry violation in bblock_simu_test => this is a bug of bblock_simu_test ??");; - RET false - ) else RET false - . + if FULL_DEBUG_DUMP then + println("-- END simu checker --");; + println("");; + RET result1 + else if result2 + then ( + println (msg_prefix +; " OOops - symmetry violation in bblock_simu_test => this is a bug of bblock_simu_test ??");; + RET false + ) else RET false + ). Obligation 1. - generalize (hCons_correct _ _ _ H0); clear H0. + generalize (hCons_correct _ _ _ H1); clear H1. wlp_simplify. Qed. Obligation 2. - generalize (hCons_correct _ _ _ H); clear H. + generalize (hCons_correct _ _ _ H0); clear H0. wlp_simplify. Qed. Obligation 3. - generalize (hCons_correct _ _ _ H0); clear H0. + generalize (hCons_correct _ _ _ H1); clear H1. wlp_simplify. Qed. Obligation 4. - generalize (hCons_correct _ _ _ H); clear H. + generalize (hCons_correct _ _ _ H0); clear H0. wlp_simplify. Qed. diff --git a/kvx/lib/IterList.v b/kvx/lib/IterList.v new file mode 100644 index 00000000..49beb1c5 --- /dev/null +++ b/kvx/lib/IterList.v @@ -0,0 +1,96 @@ +Require Import Coqlib. + +(** TODO: are these def and lemma already defined in the standard library ? + +In this case, it should be better to reuse those of the standard library ! + +*) + +Fixpoint iter {A} (n:nat) (f: A -> A) (x: A) {struct n}: A := + match n with + | O => x + | S n0 => iter n0 f (f x) + end. + +Lemma iter_S A (n:nat) (f: A -> A): forall x, iter (S n) f x = f (iter n f x). +Proof. + induction n; simpl; auto. + intros; erewrite <- IHn; simpl; auto. +Qed. + +Lemma iter_plus A (n m:nat) (f: A -> A): forall x, iter (n+m) f x = iter m f (iter n f x). +Proof. + induction n; simpl; auto. +Qed. + +Definition iter_tail {A} (n:nat) (l: list A) := iter n (@tl A) l. + +Lemma iter_tail_S {A} (n:nat) (l: list A): iter_tail (S n) l = tl (iter_tail n l). +Proof. + apply iter_S. +Qed. + +Lemma iter_tail_plus A (n m:nat) (l: list A): iter_tail (n+m) l = iter_tail m (iter_tail n l). +Proof. + apply iter_plus. +Qed. + +Lemma iter_tail_length A l1: forall (l2: list A), iter_tail (length l1) (l1 ++ l2) = l2. +Proof. + induction l1; auto. +Qed. + +Lemma iter_tail_nil A n: @iter_tail A n nil = nil. +Proof. + unfold iter_tail; induction n; simpl; auto. +Qed. + +Lemma iter_tail_reach_nil A (l: list A): iter_tail (length l) l = nil. +Proof. + rewrite (app_nil_end l) at 2. + rewrite iter_tail_length. + auto. +Qed. + +Lemma length_iter_tail {A} (n:nat): forall (l: list A), (n <= List.length l)%nat -> (List.length l = n + List.length (iter_tail n l))%nat. +Proof. + unfold iter_tail; induction n; auto. + intros l; destruct l. { simpl; omega. } + intros; simpl. erewrite IHn; eauto. + simpl in *; omega. +Qed. + +Lemma iter_tail_S_ex {A} (n:nat): forall (l: list A), (n < length l)%nat -> exists x, iter_tail n l = x::(iter_tail (S n) l). +Proof. + unfold iter_tail; induction n; simpl. + - intros l; destruct l; simpl; omega || eauto. + - intros l H; destruct (IHn (tl l)) as (x & H1). + + destruct l; simpl in *; try omega. + + rewrite H1; eauto. +Qed. + +Lemma iter_tail_inject1 {A} (n1 n2:nat) (l: list A): (n1 <= List.length l)%nat -> (n2 <= List.length l)%nat -> iter_tail n1 l = iter_tail n2 l -> n1=n2. +Proof. + intros H1 H2 EQ; exploit (length_iter_tail n1 l); eauto. + rewrite EQ. + rewrite (length_iter_tail n2 l); eauto. + omega. +Qed. + +Lemma iter_tail_nil_inject {A} (n:nat) (l: list A): iter_tail n l = nil -> (List.length l <= n)%nat. +Proof. + destruct (le_lt_dec n (List.length l)); try omega. + intros; exploit (iter_tail_inject1 n (length l) l); try omega. + rewrite iter_tail_reach_nil. auto. +Qed. + +Lemma list_length_z_nat (A: Type) (l: list A): list_length_z l = Z.of_nat (length l). +Proof. + induction l; auto. + rewrite list_length_z_cons. simpl. rewrite Zpos_P_of_succ_nat. omega. +Qed. + +Lemma list_length_nat_z (A: Type) (l: list A): length l = Z.to_nat (list_length_z l). +Proof. + intros; rewrite list_length_z_nat, Nat2Z.id. auto. +Qed. diff --git a/kvx/lib/OptionMonad.v b/kvx/lib/OptionMonad.v new file mode 100644 index 00000000..824a9c2f --- /dev/null +++ b/kvx/lib/OptionMonad.v @@ -0,0 +1,49 @@ +(* Declare Scope option_monad_scope. *) + +Notation "'SOME' X <- A 'IN' 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 "'ASSERT' A 'IN' B" := (if A then B else None) + (at level 200, A at level 100, B at level 200) + : option_monad_scope. + +Local Open Scope option_monad_scope. + + +(** Simple tactics for option-monad *) + +Lemma destruct_SOME A B (P: option B -> Prop) (e: option A) (f: A -> option B): + (forall x, e = Some x -> P (f x)) -> (e = None -> P None) -> (P (SOME x <- e IN f x)). +Proof. + intros; destruct e; simpl; auto. +Qed. + +Lemma destruct_ASSERT B (P: option B -> Prop) (e: bool) (x: option B): + (e = true -> P x) -> (e = false -> P None) -> (P (ASSERT e IN x)). +Proof. + intros; destruct e; simpl; auto. +Qed. + +Ltac inversion_SOME x := + try (eapply destruct_SOME; [ let x := fresh x in intro x | simpl; try congruence ]). + +Ltac inversion_ASSERT := + try (eapply destruct_ASSERT; [ idtac | simpl; try congruence ]). + +Ltac simplify_someHyp := + match goal with + | H: None = Some _ |- _ => inversion H; clear H; subst + | H: Some _ = None |- _ => inversion H; clear H; subst + | H: ?t = ?t |- _ => clear H + | H: Some _ = Some _ |- _ => inversion H; clear H; subst + | H: Some _ <> None |- _ => clear H + | H: None <> Some _ |- _ => clear H + | H: _ = Some _ |- _ => (try rewrite !H in * |- *); generalize H; clear H + end. + +Ltac simplify_someHyps := + repeat (simplify_someHyp; simpl in * |- *). + +Ltac try_simplify_someHyps := + try (intros; simplify_someHyps; eauto). diff --git a/kvx/lib/PseudoAsmblock.v b/kvx/lib/PseudoAsmblock.v new file mode 100644 index 00000000..b33ea1bd --- /dev/null +++ b/kvx/lib/PseudoAsmblock.v @@ -0,0 +1,267 @@ +Require Import Coqlib Maps AST Integers Values Memory Events Globalenvs Smallstep. +Require Import Op Machregs Locations Stacklayout Conventions. +Require Import Mach Machblock OptionMonad. + + +(** Registers and States *) + +Inductive preg: Type := + | PC: preg (* program counter *) + | RA: preg (* return-address *) + | SP: preg (* stack-pointer *) + | preg_of: mreg -> preg. +Coercion preg_of: mreg >-> preg. + +Lemma preg_eq: forall (x y: preg), {x=y} + {x<>y}. +Proof. + decide equality. + apply mreg_eq. +Defined. + +Module PregEq. + Definition t := preg. + Definition eq := preg_eq. +End PregEq. + +Module Pregmap := EMap(PregEq). + +Definition regset := Pregmap.t val. + +Module AsmNotations. + +(* Declare Scope asm. *) +Notation "a # b" := (a b) (at level 1, only parsing) : asm. +Notation "a # b <- c" := (Pregmap.set b c a) (at level 1, b at next level) : asm. +Open Scope asm. + +End AsmNotations. + +Import AsmNotations. + +Definition to_Machrs (rs: regset): Mach.regset := + fun (r:mreg) => rs r. +Coercion to_Machrs: regset >-> Mach.regset. + +Definition set_from_Machrs (mrs: Mach.regset) (rs: regset): regset := + fun (r:preg) => + match r with + | preg_of mr => mrs mr + | _ => rs r + end. + +Local Open Scope option_monad_scope. + +Record state: Type := State { _rs: regset; _m: mem }. +Definition outcome := option state. +Definition Next rs m: outcome := Some (State rs m). +Definition Stuck: outcome := None. + +(* Asm semantic on Mach *) + +Section RELSEM. + +(** "oracle" stating the successive position (ie offset) of each block in the final assembly function *) +Variable next: function -> Z -> Z. + +Inductive is_pos (f: function): Z -> code -> Prop := + | First_pos: is_pos f 0 (fn_code f) + | Next_pos pos b c: is_pos f pos (b::c) -> is_pos f (next f pos) c. + +Fixpoint label_pos (f: function) (lbl: label) (pos: Z) (c: code) {struct c} : option Z := + match c with + | nil => None + | b :: c' => + if is_label lbl b then Some pos else label_pos f lbl (next f pos) c' + end. + +Definition goto_label (f: function) (lbl: label) (rs: regset) : option val := + SOME pos <- label_pos f lbl 0 (fn_code f) IN + match rs#PC with + | Vptr b _ => Some (Vptr b (Ptrofs.repr pos)) + | _ => None + end. + +Definition next_addr (f: function) (rs: regset): option val := + match rs#PC with + | Vptr b ofs => Some (Vptr b (Ptrofs.repr (next f (Ptrofs.unsigned ofs)))) + | _ => None + end. + +Variable ge:genv. + +Inductive basic_step (f: function) (rs: regset) (m:mem): basic_inst -> regset -> mem -> Prop := + | exec_MBgetstack: + forall ofs ty dst v, + load_stack m (rs#SP) ty ofs = Some v -> + basic_step f rs m (MBgetstack ofs ty dst) (rs#dst <- v) m + | exec_MBsetstack: + forall (src: mreg) ofs ty m' rs', + store_stack m (rs#SP) ty ofs (rs src) = Some m' -> + rs' = set_from_Machrs (undef_regs (destroyed_by_setstack ty) rs) rs -> + basic_step f rs m (MBsetstack src ofs ty) rs' m' + | exec_MBgetparam: + forall ofs ty (dst: mreg) v rs' psp, + load_stack m (rs#SP) Tptr f.(fn_link_ofs) = Some psp -> + load_stack m psp ty ofs = Some v -> + rs' = (rs # temp_for_parent_frame <- Vundef # dst <- v) -> + basic_step f rs m (MBgetparam ofs ty dst) rs' m + | exec_MBop: + forall op args v rs' (res: mreg), + eval_operation ge (rs#SP) op (to_Machrs rs)##args m = Some v -> + rs' = (set_from_Machrs (undef_regs (destroyed_by_op op) rs) rs)#res <- v -> + basic_step f rs m (MBop op args res) rs' m + | exec_MBload: + forall addr args a v rs' trap chunk (dst: mreg), + eval_addressing ge (rs#SP) addr (to_Machrs rs)##args = Some a -> + Mem.loadv chunk m a = Some v -> + rs' = (set_from_Machrs (undef_regs (destroyed_by_load chunk addr) rs) rs)#dst <- v -> + basic_step f rs m (MBload trap chunk addr args dst) rs' m + | exec_MBload_notrap1: + forall addr args rs' chunk (dst: mreg), + eval_addressing ge (rs#SP) addr (to_Machrs rs)##args = None -> + rs' = (set_from_Machrs (undef_regs (destroyed_by_load chunk addr) rs) rs)#dst <- (default_notrap_load_value chunk) -> + basic_step f rs m (MBload NOTRAP chunk addr args dst) rs' m + | exec_MBload_notrap2: + forall addr args a rs' chunk (dst: mreg), + eval_addressing ge (rs#SP) addr (to_Machrs rs)##args = Some a -> + Mem.loadv chunk m a = None -> + rs' = (set_from_Machrs (undef_regs (destroyed_by_load chunk addr) rs) rs)#dst <- (default_notrap_load_value chunk) -> + basic_step f rs m (MBload NOTRAP chunk addr args dst) rs' m + | exec_MBstore: + forall chunk addr args (src: mreg) m' a rs', + eval_addressing ge (rs#SP) addr (to_Machrs rs)##args = Some a -> + Mem.storev chunk m a (rs src) = Some m' -> + rs' = set_from_Machrs (undef_regs (destroyed_by_store chunk addr) rs) rs -> + basic_step f rs m (MBstore chunk addr args src) rs' m' + . + + +Inductive body_step (f: function) : bblock_body -> regset -> mem -> regset -> mem -> Prop := + | exec_nil_body rs m: + body_step f nil rs m rs m + | exec_cons_body rs m bi p rs' m' rs'' m'': + basic_step f rs m bi rs' m' -> + body_step f p rs' m' rs'' m'' -> + body_step f (bi::p) rs m rs'' m'' + . + + +Definition find_function_ptr (ros: mreg + ident) (rs: regset) : option val := + match ros with + | inl r => Some (rs#r) + | inr symb => + SOME b <- Genv.find_symbol ge symb IN + Some (Vptr b Ptrofs.zero) + end. + +Definition exec_epilogue (f: function) (rs: regset) (m: mem) : outcome := + SOME sp <- load_stack m rs#SP Tptr f.(fn_link_ofs) IN + SOME ra <- load_stack m rs#SP Tptr f.(fn_retaddr_ofs) IN + match rs#SP with + | Vptr stk ofs => + SOME m' <- Mem.free m stk 0 f.(fn_stacksize) IN + Next (rs#SP <- sp #RA <- ra) m' + | _ => Stuck + end. + +Inductive cfi_step (f: function): control_flow_inst -> regset -> mem -> trace -> regset -> mem -> Prop := + | exec_MBcall sig ros rs m pc: + find_function_ptr ros rs = Some pc -> + cfi_step f (MBcall sig ros) rs m E0 ((rs#RA <- (rs#PC))#PC <- pc) m + | exec_MBtailcall sig ros rs m rs' m' pc: + find_function_ptr ros rs = Some pc -> + exec_epilogue f rs m = Next rs' m' -> + cfi_step f (MBtailcall sig ros) rs m E0 (rs'#PC <- pc) m' + | exec_MBreturn rs m rs' m': + exec_epilogue f rs m = Next rs' m' -> + cfi_step f MBreturn rs m E0 (rs'#PC <- (rs'#RA)) m' + | exec_MBgoto lbl rs m pc: + goto_label f lbl rs = Some pc -> + cfi_step f (MBgoto lbl) rs m E0 (rs#PC <- pc) m + | exec_MBcond_true cond args lbl rs m pc rs': + eval_condition cond (to_Machrs rs)##args m = Some true -> + goto_label f lbl rs = Some pc -> + rs' = set_from_Machrs (undef_regs (destroyed_by_cond cond) rs) rs -> + cfi_step f (MBcond cond args lbl) rs m E0 (rs'#PC <- pc) m + | exec_MBcond_false cond args lbl rs m rs': + eval_condition cond (to_Machrs rs)##args m = Some false -> + rs' = set_from_Machrs (undef_regs (destroyed_by_cond cond) rs) rs -> + cfi_step f (MBcond cond args lbl) rs m E0 rs' m + | exec_MBjumptable arg tbl rs m index lbl pc rs': + to_Machrs rs arg = Vint index -> + list_nth_z tbl (Int.unsigned index) = Some lbl -> + goto_label f lbl rs = Some pc -> + rs' = set_from_Machrs (undef_regs destroyed_by_jumptable rs) rs -> + cfi_step f (MBjumptable arg tbl) rs m E0 (rs'#PC <- pc) m + | exec_MBbuiltin rs m ef args res vargs t vres rs' m': + eval_builtin_args ge (to_Machrs rs) (rs#SP) m args vargs -> + external_call ef ge vargs m t vres m' -> + rs' = set_from_Machrs (set_res res vres (undef_regs (destroyed_by_builtin ef) rs)) rs -> + cfi_step f (MBbuiltin ef args res) rs m t rs' m' + . + +Inductive exit_step f : option control_flow_inst -> regset -> mem -> trace -> regset -> mem -> Prop := + | exec_Some_exit ctl rs m t rs' m': + cfi_step f ctl rs m t rs' m' -> + exit_step f (Some ctl) rs m t rs' m' + | exec_None_exit rs m: + exit_step f None rs m E0 rs m + . + +Inductive exec_bblock f: bblock -> regset -> mem -> trace -> regset -> mem -> Prop := + | exec_bblock_all (bb: bblock) rs0 m0 rs1 m1 pc t rs2 m2: + body_step f (body bb) rs0 m0 rs1 m1 -> + next_addr f rs1 = Some pc -> + exit_step f (exit bb) (rs1#PC <- pc) m1 t rs2 m2 -> + exec_bblock f bb rs0 m0 t rs2 m2. + +Definition exec_prologue f (pos:Z) (rs: regset) (m:mem) : option state := + if Z.eq_dec pos 0 then + let (m1, stk) := Mem.alloc m 0 f.(fn_stacksize) in + let sp := Vptr stk Ptrofs.zero in + SOME m2 <- store_stack m1 sp Tptr f.(fn_link_ofs) rs#SP IN + SOME m3 <- store_stack m2 sp Tptr f.(fn_retaddr_ofs) rs#RA IN + Next ((set_from_Machrs (undef_regs destroyed_at_function_entry rs) rs)#SP <- sp) m3 + else + Next rs m. + + +Inductive step: state -> trace -> state -> Prop := + | exec_step_internal b ofs f bb c rs0 m0 rs1 m1 t rs2 m2: + rs0 PC = Vptr b ofs -> + Genv.find_funct_ptr ge b = Some (Internal f) -> + is_pos f (Ptrofs.unsigned ofs) (bb::c) -> + exec_prologue f (Ptrofs.unsigned ofs) rs0 m0 = Next rs1 m1 -> + exec_bblock f bb rs1 m1 t rs2 m2 -> + step (State rs0 m0) t (State rs2 m2) + | exec_step_external: + forall b ef args res rs m t rs' m', + rs PC = Vptr b Ptrofs.zero -> + Genv.find_funct_ptr ge b = Some (External ef) -> + extcall_arguments (to_Machrs rs) m (rs#SP) (ef_sig ef) args -> + external_call ef ge args m t res m' -> + rs' = (set_from_Machrs (set_pair (loc_result (ef_sig ef)) res (undef_caller_save_regs rs)) rs) #PC <- (rs RA) -> + step (State rs m) t (State rs' m'). + +End RELSEM. + +Inductive initial_state (p: program): state -> Prop := + | initial_state_intro: forall m0, + let ge := Genv.globalenv p in + Genv.init_mem p = Some m0 -> + let rs0 := + (Pregmap.init Vundef) + # PC <- (Genv.symbol_address ge p.(prog_main) Ptrofs.zero) + # SP <- Vnullptr + # RA <- Vnullptr in + initial_state p (State rs0 m0). + +Inductive final_state: state -> int -> Prop := + | final_state_intro: forall rs m r retcode, + loc_result signature_main = One r -> + rs PC = Vnullptr -> + rs r = Vint retcode -> + final_state (State rs m) retcode. + +Definition semantics (next: function -> Z -> Z) (p: program) := + Semantics (step next) (initial_state p) final_state (Genv.globalenv p). diff --git a/kvx/lib/PseudoAsmblockproof.v b/kvx/lib/PseudoAsmblockproof.v new file mode 100644 index 00000000..67308278 --- /dev/null +++ b/kvx/lib/PseudoAsmblockproof.v @@ -0,0 +1,1173 @@ +Require Import Coqlib Maps AST Integers Values Memory Events Globalenvs Smallstep. +Require Import Op Machregs Locations Stacklayout Conventions. +Require Import Mach Machblock OptionMonad. +Require Import Errors Datatypes PseudoAsmblock IterList. + +(** Tiny translation from Machblock semantics to PseudoAsmblock semantics (needs additional checks) +*) + +Section TRANSLATION. + +(* In the actual Asmblock code, the prologue will be inserted in the first block of the function. + But, this block should have an empty header. +*) + +Definition has_header (c: code) : bool := + match c with + | nil => false + | bb::_ => match header bb with + | nil => false + | _ => true + end + end. + +Definition insert_implicit_prologue c := + if has_header c then {| header := nil; body := nil; exit := None |}::c else c. + +Definition transl_function (f: function) : function := + {| fn_sig:=fn_sig f; + fn_code:=insert_implicit_prologue (fn_code f); + fn_stacksize := fn_stacksize f; + fn_link_ofs := fn_link_ofs f; + fn_retaddr_ofs := fn_retaddr_ofs f + |}. + +Definition transf_function (f: function) : res function := + let tf := transl_function f in + (* removed because it is simpler or/and more efficient to perform this test in Asmblockgen ! + if zlt Ptrofs.max_unsigned (max_pos tf) + then Error (msg "code size exceeded") + else *) + OK tf. + +Definition transf_fundef (f: fundef) : res fundef := + transf_partial_fundef transf_function f. + +Definition transf_program (p: program) : res program := + transform_partial_program transf_fundef p. + +End TRANSLATION. + +(** Proof of the translation +*) + +Require Import Linking. +Import PseudoAsmblock.AsmNotations. + +Section PRESERVATION. + +Definition match_prog (p: program) (tp: program) := + match_program (fun _ f tf => transf_fundef f = OK tf) eq p tp. + +Lemma transf_program_match: + forall p tp, transf_program p = OK tp -> match_prog p tp. +Proof. + intros. eapply match_transform_partial_program; eauto. +Qed. + +Local Open Scope Z_scope. +Local Open Scope option_monad_scope. + +Variable prog: program. +Variable tprog: program. + +Hypothesis TRANSF: match_prog prog tprog. +Let ge := Genv.globalenv prog. +Let tge := Genv.globalenv tprog. + +Variable next: function -> Z -> Z. + +Hypothesis next_progress: forall (f:function) (pos:Z), (pos < (next f pos))%Z. + +Definition max_pos (f:function) := iter (S (length f.(fn_code))) (next f) 0. + +(* This hypothesis expresses that Asmgen checks for each tf + that (max_pos tf) represents a valid address +*) +Hypothesis functions_bound_max_pos: forall fb tf, + Genv.find_funct_ptr tge fb = Some (Internal tf) -> + (max_pos tf) <= Ptrofs.max_unsigned. + +(** * Agreement between Mach registers and PseudoAsm registers *) +Record agree (ms: Mach.regset) (sp: val) (rs: regset) : Prop := mkagree { + agree_sp: rs#SP = sp; + agree_sp_def: sp <> Vundef; + agree_mregs: forall r: mreg, (ms r)=(rs#r) +}. + +(** [transl_code_at_pc pc fb f tf c] holds if the code pointer [pc] points + within the code generated by Machblock function (originally [f] -- but translated as [tf]), + and [c] is the tail of the code at the position corresponding to the code pointer [pc]. +*) +Inductive transl_code_at_pc (b:block) (f:function) (tf:function) (c:code): val -> Prop := + transl_code_at_pc_intro ofs: + Genv.find_funct_ptr ge b = Some (Internal f) -> + transf_function f = OK tf -> + (* we have passed the first block containing the prologue *) + (0 < (Ptrofs.unsigned ofs))%Z -> + (* the code is identical in the two functions *) + is_pos next tf (Ptrofs.unsigned ofs) c -> + transl_code_at_pc b f tf c (Vptr b ofs). + +Inductive match_stack: list stackframe -> Prop := + | match_stack_nil: + match_stack nil + | match_stack_cons: forall fb sp ra c s f tf, + Genv.find_funct_ptr ge fb = Some (Internal f) -> + transl_code_at_pc fb f tf c ra -> + sp <> Vundef -> + match_stack s -> + match_stack (Stackframe fb sp ra c :: s). + +(** Semantic preservation is proved using simulation diagrams + of the following form. +<< + s1 ---------------- s2 + | | + t| *|t + | | + v v + s1'---------------- s2' +>> + The invariant is the [match_states] predicate below... + +*) + +Inductive match_states: Machblock.state -> state -> Prop := + | match_states_internal s fb sp c ms m rs f tf + (STACKS: match_stack s) + (FIND: Genv.find_funct_ptr ge fb = Some (Internal f)) + (AT: transl_code_at_pc fb f tf c (rs PC)) + (AG: agree ms sp rs): + match_states (Machblock.State s fb sp c ms m) + (State rs m) + | match_states_prologue s sp fb ms rs0 m0 f rs1 m1 + (STACKS: match_stack s) + (AG: agree ms sp rs1) + (ATPC: rs0 PC = Vptr fb Ptrofs.zero) + (ATLR: rs0 RA = parent_ra s) + (FIND: Genv.find_funct_ptr ge fb = Some (Internal f)) + (PROL: exec_prologue f 0 rs0 m0 = Next rs1 m1): + match_states (Machblock.State s fb sp (fn_code f) ms m1) + (State rs0 m0) + | match_states_call s fb ms m rs + (STACKS: match_stack s) + (AG: agree ms (parent_sp s) rs) + (ATPC: rs PC = Vptr fb Ptrofs.zero) + (ATLR: rs RA = parent_ra s): + match_states (Machblock.Callstate s fb ms m) + (State rs m) + | match_states_return s ms m rs + (STACKS: match_stack s) + (AG: agree ms (parent_sp s) rs) + (ATPC: rs PC = parent_ra s): + match_states (Machblock.Returnstate s ms m) + (State rs m). + +Definition measure (s: Machblock.state) : nat := + match s with + | Machblock.State _ _ _ _ _ _ => 0%nat + | Machblock.Callstate _ _ _ _ => 1%nat + | Machblock.Returnstate _ _ _ => 1%nat + end. + +Definition rao (f: function) (c: code) (ofs: ptrofs) : Prop := + forall tf, + transf_function f = OK tf -> + is_pos next tf (Ptrofs.unsigned ofs) c. + +Lemma symbols_preserved: + forall (s: ident), Genv.find_symbol tge s = Genv.find_symbol ge s. +Proof (Genv.find_symbol_match TRANSF). + +Lemma senv_preserved: + Senv.equiv ge tge. +Proof (Genv.senv_match TRANSF). + +Lemma functions_translated: + forall b f, + Genv.find_funct_ptr ge b = Some f -> + exists tf, + Genv.find_funct_ptr tge b = Some tf /\ transf_fundef f = OK tf. +Proof (Genv.find_funct_ptr_transf_partial TRANSF). + +Lemma functions_transl fb f tf: + Genv.find_funct_ptr ge fb = Some (Internal f) -> + transf_function f = OK tf -> + Genv.find_funct_ptr tge fb = Some (Internal tf). +Proof. + intros. exploit functions_translated; eauto. intros [tf' [A B]]. + monadInv B. inv H0; auto. +Qed. + +Lemma function_bound fb f tf: + Genv.find_funct_ptr ge fb = Some (Internal f) -> transf_function f = OK tf -> (max_pos tf) <= Ptrofs.max_unsigned. +Proof. + intros; eapply functions_bound_max_pos; eauto. + eapply functions_transl; eauto. +Qed. + +Lemma transf_function_def f tf: + transf_function f = OK tf -> tf.(fn_code) = insert_implicit_prologue f.(fn_code). +Proof. + unfold transf_function. + intros EQ; inv EQ. + auto. +Qed. + +Lemma stackinfo_preserved f tf: + transf_function f = OK tf -> + tf.(fn_stacksize) = f.(fn_stacksize) + /\ tf.(fn_retaddr_ofs) = f.(fn_retaddr_ofs) + /\ tf.(fn_link_ofs) = f.(fn_link_ofs). +Proof. + unfold transf_function. + intros EQ0; inv EQ0. simpl; intuition. +Qed. + +Lemma transf_initial_states st1: Machblock.initial_state prog st1 -> + exists st2, initial_state tprog st2 /\ match_states st1 st2. +Proof. + intro H. inversion H. unfold ge0 in *. + econstructor; split. + - econstructor. + eapply (Genv.init_mem_transf_partial TRANSF); eauto. + - replace (Genv.symbol_address (Genv.globalenv tprog) (prog_main tprog) Ptrofs.zero) + with (Vptr fb Ptrofs.zero). + + econstructor; eauto. + * constructor. + * split; auto; simpl; unfold Vnullptr; destruct Archi.ptr64; congruence. + + unfold Genv.symbol_address. + rewrite (match_program_main TRANSF). + rewrite symbols_preserved. + unfold ge. simplify_someHyp. auto. +Qed. + +Lemma transf_final_states st1 st2 r: + match_states st1 st2 -> Machblock.final_state st1 r -> final_state st2 r. +Proof. + intros H H0. inv H0. inv H. + econstructor; eauto. + exploit agree_mregs; eauto. + erewrite H2. intro H3; inversion H3. + auto. +Qed. + +(** Lemma on [is_pos]. *) + +Lemma is_pos_alt_def f pos code: is_pos next f pos code -> + exists n, (n <= List.length (fn_code f))%nat /\ pos = (iter n (next f) 0) /\ code = iter_tail n (fn_code f). +Proof. + induction 1. + - unfold iter_tail; exists O; simpl; intuition. + - destruct IHis_pos as (n & H0 & H1 & H2). + exists (S n). repeat split. + + rewrite (length_iter_tail n); eauto. + rewrite <- H2; simpl; omega. + + rewrite iter_S; congruence. + + unfold iter_tail in *; rewrite iter_S, <- H2; auto. +Qed. + +Local Hint Resolve First_pos Next_pos: core. + +Lemma is_pos_alt_def_recip f n: (n <= List.length (fn_code f))%nat -> + is_pos next f (iter n (next f) 0) (iter_tail n (fn_code f)). +Proof. + induction n. + - unfold iter_tail; simpl; eauto. + - intros H; destruct (iter_tail_S_ex n (fn_code f)) as (x & H1); try omega. + rewrite iter_S; lapply IHn; try omega. + rewrite H1; eauto. +Qed. + +Lemma is_pos_inject1 f pos1 pos2 code: + is_pos next f pos1 code -> is_pos next f pos2 code -> pos1=pos2. +Proof. + intros H1 H2. + destruct (is_pos_alt_def f pos1 code) as (n1 & B1 & POS1 & CODE1); eauto. + destruct (is_pos_alt_def f pos2 code) as (n2 & B2 & POS2 & CODE2); eauto. + clear H1 H2; subst. + erewrite (iter_tail_inject1 n1 n2); eauto. +Qed. + +Lemma iter_next_strict_monotonic f n m x: (n < m)%nat -> iter n (next f) x < iter m (next f) x. +Proof. + induction 1; rewrite iter_S; auto. + generalize (next_progress f (iter m (next f) x)). + omega. +Qed. + +Lemma iter_next_monotonic f n m x: (n <= m)%nat -> iter n (next f) x <= iter m (next f) x. +Proof. + destruct 1. + - omega. + - generalize (iter_next_strict_monotonic f n (S m) x). omega. +Qed. + +Lemma is_pos_bound_pos f pos code: + is_pos next f pos code -> 0 <= pos <= max_pos f. +Proof. + intros H; exploit is_pos_alt_def; eauto. + intros (n & H1 & H2 & H3). + rewrite H2. unfold max_pos. split. + - cutrewrite (0 = iter O (next f) 0); auto. + apply iter_next_monotonic; omega. + - apply iter_next_monotonic; omega. +Qed. + +Lemma is_pos_unsigned_repr f pos code: + is_pos next f pos code -> + max_pos f <= Ptrofs.max_unsigned -> + Ptrofs.unsigned (Ptrofs.repr pos) = pos. +Proof. + intros; eapply Ptrofs.unsigned_repr. + exploit is_pos_bound_pos; eauto. + omega. +Qed. + +Lemma is_pos_simplify f pos code: + is_pos next f pos code -> + max_pos f <= Ptrofs.max_unsigned -> + is_pos next f (Ptrofs.unsigned (Ptrofs.repr pos)) code. +Proof. + intros; erewrite is_pos_unsigned_repr; eauto. +Qed. + +Lemma find_label_label_pos f lbl c: forall pos c', + find_label lbl c = Some c' -> + exists n, + label_pos next f lbl pos c = Some (iter n (next f) pos) + /\ c' = iter_tail n c + /\ (n <= List.length c)%nat. +Proof. + induction c. + - simpl; intros. discriminate. + - simpl; intros pos c'. + destruct (is_label lbl a). + + intro EQ; injection EQ; intro; subst c'. + exists O; simpl; intuition. + + intros. generalize (IHc (next f pos) c' H). intros (n' & A & B & C). + exists (S n'). intuition. +Qed. + +Lemma find_label_insert_implicit_prologue lbl c: + find_label lbl c = find_label lbl (insert_implicit_prologue c). +Proof. + unfold insert_implicit_prologue. + destruct (has_header c); simpl; auto. + unfold is_label; simpl. + destruct (in_dec lbl nil); auto. + simpl in *. tauto. +Qed. + +Lemma no_header_insert_implicit_prologue c: + has_header (insert_implicit_prologue c) = false. +Proof. + unfold insert_implicit_prologue. + destruct (has_header c) eqn: H; simpl; auto. +Qed. + +Lemma find_label_has_header lbl c c': + find_label lbl c = Some c' -> + has_header c' = true. +Proof. + induction c; simpl; try congruence. + destruct (is_label lbl a) eqn:LAB; auto. + intros X; inv X; simpl. + unfold is_label in LAB. + destruct (in_dec lbl (header a)); try congruence. + destruct (header a); try congruence. + simpl in *; tauto. +Qed. + +Lemma find_label_label_pos_no_header f lbl c pos c': + (has_header c) = false -> + find_label lbl c = Some c' -> + exists n, + label_pos next f lbl pos c = Some (iter (S n) (next f) pos) + /\ c' = iter_tail (S n) c + /\ ((S n) <= List.length c)%nat. +Proof. + intros H H0; exploit find_label_label_pos; eauto. + intros ([|n] & H1 & H2 & H3); try (exists n; intuition eauto). + unfold iter_tail in *; simpl in *; subst. + erewrite find_label_has_header in H; eauto. + congruence. +Qed. + +Hint Resolve is_pos_simplify is_pos_alt_def_recip function_bound: core. + +Lemma find_label_goto_label f tf lbl rs c' b ofs: + Genv.find_funct_ptr ge b = Some (Internal f) -> + transf_function f = OK tf -> + Vptr b ofs = rs PC -> + find_label lbl f.(fn_code) = Some c' -> + exists pc, + goto_label next tf lbl rs = Some pc + /\ transl_code_at_pc b f tf c' pc. +Proof. + intros FINDF T HPC FINDL. + erewrite find_label_insert_implicit_prologue, <- transf_function_def in FINDL; eauto. + exploit find_label_label_pos_no_header; eauto. + { erewrite transf_function_def; eauto. + apply no_header_insert_implicit_prologue. + } + intros (n & LAB & CODE & BOUND); subst. + exists (Vptr b (Ptrofs.repr (iter (S n) (next tf) 0))). + unfold goto_label; intuition. + - simplify_someHyps; rewrite <- HPC. auto. + - econstructor; eauto. + erewrite is_pos_unsigned_repr; eauto. + generalize (iter_next_strict_monotonic tf O (S n) 0); simpl. + omega. +Qed. + +(** Preservation of register agreement under various assignments. *) + +Lemma agree_mregs_list ms sp rs: + agree ms sp rs -> + forall l, (ms##l)=(to_Machrs rs)##l. +Proof. + unfold to_Machrs. intros AG; induction l; simpl; eauto. + erewrite agree_mregs; eauto. + congruence. +Qed. + +Lemma agree_set_mreg ms sp rs r v rs': + agree ms sp rs -> + v=(rs'#(preg_of r)) -> + (forall r', r' <> preg_of r -> rs'#r' = rs#r') -> + agree (Regmap.set r v ms) sp rs'. +Proof. + intros H H0 H1. destruct H. split; auto. + - rewrite H1; auto. destruct r; simpl; congruence. + - intros. unfold Regmap.set. destruct (RegEq.eq r0 r). congruence. + rewrite H1; auto. destruct r; simpl; congruence. +Qed. + +Corollary agree_set_mreg_parallel: + forall ms sp rs r v, + agree ms sp rs -> + agree (Regmap.set r v ms) sp (Pregmap.set (preg_of r) v rs). +Proof. + intros. eapply agree_set_mreg; eauto. + - rewrite Pregmap.gss; auto. + - intros; apply Pregmap.gso; auto. +Qed. + +Corollary agree_set_mreg_parallel2: + forall ms sp rs r v ms', + agree ms sp (set_from_Machrs ms' rs)-> + agree (Regmap.set r v ms) sp (set_from_Machrs (Regmap.set r v ms') rs). +Proof. + intros. unfold set_from_Machrs in *. eapply agree_set_mreg; eauto. + - rewrite Regmap.gss; auto. + - intros r' X. destruct r'; try congruence. rewrite Regmap.gso; try congruence. +Qed. + +Definition data_preg (r: preg) : bool := + match r with + | preg_of _ | SP => true + | _ => false + end. + +Lemma agree_exten ms sp rs rs': + agree ms sp rs -> + (forall r, data_preg r = true -> rs'#r = rs#r) -> + agree ms sp rs'. +Proof. + intros H H0. destruct H. split; intros; try rewrite H0; auto. +Qed. + +Lemma agree_set_from_Machrs ms sp ms' rs: + agree ms sp rs -> + (forall (r:mreg), (ms' r) = rs#r) -> + agree ms sp (set_from_Machrs ms' rs). +Proof. + unfold set_from_Machrs; intros. + eapply agree_exten; eauto. + intros r; destruct r; simpl; try congruence. +Qed. + +Lemma agree_set_other ms sp rs r v: + agree ms sp rs -> + data_preg r = false -> + agree ms sp (rs#r <- v). +Proof. + intros; apply agree_exten with rs; auto. + intros. apply Pregmap.gso. congruence. +Qed. + + +Lemma agree_next_addr f ms sp b pos rs: + agree ms sp rs -> + agree ms sp (rs#PC <- (Vptr b (Ptrofs.repr (next f pos)))). +Proof. + intros. apply agree_set_other; auto. +Qed. + +Local Hint Resolve agree_set_mreg_parallel2: core. + +Lemma agree_set_pair sp p v ms ms' rs: + agree ms sp (set_from_Machrs ms' rs) -> + agree (set_pair p v ms) sp (set_from_Machrs (set_pair p v ms') rs). +Proof. + intros H; destruct p; simpl; auto. +Qed. + +Lemma agree_undef_caller_save_regs: + forall ms sp ms' rs, + agree ms sp (set_from_Machrs ms' rs) -> + agree (undef_caller_save_regs ms) sp (set_from_Machrs (undef_caller_save_regs ms') rs). +Proof. + intros. destruct H as [H0 H1 H2]. unfold undef_caller_save_regs. split; auto. + intros. + unfold set_from_Machrs in * |- *. + rewrite H2. auto. +Qed. + +Lemma agree_change_sp ms sp rs sp': + agree ms sp rs -> sp' <> Vundef -> + agree ms sp' (rs#SP <- sp'). +Proof. + intros H H0. inv H. split; auto. +Qed. + +Lemma agree_undef_regs ms sp rl ms' rs: + agree ms sp (set_from_Machrs ms' rs) -> + agree (Mach.undef_regs rl ms) sp (set_from_Machrs (Mach.undef_regs rl ms') rs). +Proof. + unfold set_from_Machrs; intros H. destruct H; subst. split; auto. + intros. destruct (In_dec mreg_eq r rl). + + rewrite! undef_regs_same; auto. + + rewrite! undef_regs_other; auto. +Qed. + +(** Translation of arguments and results to builtins. *) + +Remark builtin_arg_match: + forall ms rs sp m a v, + agree ms sp rs -> + eval_builtin_arg ge ms sp m a v -> + eval_builtin_arg ge (to_Machrs rs) sp m a v. +Proof. + induction 2; simpl; eauto with barg. + unfold to_Machrs; erewrite agree_mregs; eauto. + econstructor. +Qed. + +Lemma builtin_args_match: + forall ms sp rs m, + agree ms sp rs -> + forall al vl, eval_builtin_args ge ms sp m al vl -> + eval_builtin_args ge (to_Machrs rs) sp m al vl. +Proof. + induction 2; intros; simpl; try (constructor; auto). + eapply eval_builtin_arg_preserved; eauto. + eapply builtin_arg_match; eauto. +Qed. + +Lemma agree_set_res res: forall ms sp rs v ms', + agree ms sp (set_from_Machrs ms' rs) -> + agree (set_res res v ms) sp (set_from_Machrs (set_res res v ms') rs). +Proof. + induction res; simpl; auto. +Qed. + +Lemma find_function_ptr_agree ros ms rs sp b: + agree ms sp rs -> + Machblock.find_function_ptr ge ros ms = Some b -> + find_function_ptr tge ros rs = Some (Vptr b Ptrofs.zero). +Proof. + intros AG; unfold Mach.find_function_ptr; destruct ros as [r|s]; simpl; auto. + - generalize (agree_mregs _ _ _ AG r). destruct (ms r); simpl; try congruence. + intros H; inv H; try congruence. + inversion_ASSERT. intros H; rewrite (Ptrofs.same_if_eq _ _ H); eauto. + try_simplify_someHyps. + - intros H; rewrite symbols_preserved, H. auto. +Qed. + +Lemma parent_sp_def: forall s, match_stack s -> parent_sp s <> Vundef. +Proof. + induction 1; simpl. + unfold Vnullptr; destruct Archi.ptr64; congruence. + auto. +Qed. + +Lemma extcall_arg_match ms sp rs m l v: + agree ms sp rs -> + extcall_arg ms m sp l v -> + extcall_arg rs m (rs#SP) l v. +Proof. + destruct 2. + - erewrite agree_mregs; eauto. constructor. + - unfold load_stack in *. econstructor; eauto. + erewrite agree_sp; eauto. +Qed. + +Local Hint Resolve extcall_arg_match: core. + +Lemma extcall_arg_pair_match: + forall ms sp rs m p v, + agree ms sp rs -> + extcall_arg_pair ms m sp p v -> + extcall_arg_pair rs m (rs#SP) p v. +Proof. + destruct 2; constructor; eauto. +Qed. + +Local Hint Resolve extcall_arg_pair_match: core. + +Lemma extcall_args_match: + forall ms sp rs m, agree ms sp rs -> + forall ll vl, + list_forall2 (extcall_arg_pair ms m sp) ll vl -> + list_forall2 (extcall_arg_pair rs m rs#SP) ll vl. +Proof. + induction 2; constructor; eauto. +Qed. + +Lemma extcall_arguments_match: + forall ms m sp rs sg args, + agree ms sp rs -> + extcall_arguments ms m sp sg args -> + extcall_arguments rs m (rs#SP) sg args. +Proof. + unfold extcall_arguments, extcall_arguments; intros. + eapply extcall_args_match; eauto. +Qed. + +(** A few tactics *) + +Local Hint Resolve functions_transl symbols_preserved + agree_next_addr agree_mregs agree_set_mreg_parallel agree_undef_regs agree_set_other agree_change_sp + agree_sp_def agree_set_from_Machrs agree_set_pair agree_undef_caller_save_regs agree_set_res f_equal Ptrofs.repr_unsigned parent_sp_def + builtin_args_match external_call_symbols_preserved: core. + +Ltac simplify_regmap := + repeat (rewrite ?Pregmap.gss; try (rewrite Pregmap.gso; try congruence)). + +Ltac simplify_next_addr := + match goal with + | [ HPC: Vptr _ _ = _ PC |- _ ] => try (unfold next_addr, Val.offset_ptr); simplify_regmap; try (rewrite <- HPC) + end. + +Ltac discharge_match_states := + econstructor; eauto; try ( simplify_next_addr; econstructor; eauto ). + + +(** Instruction step simulation lemma: the simulation lemma for stepping one instruction + +<< + s1 ---------------- s2 + | | + t| +|t + | | + v v + s1'---------------- s2' +>> + +*) + +Lemma trivial_exec_prologue: + forall tf ofs rs m, + 0 < Ptrofs.unsigned ofs -> + exec_prologue tf (Ptrofs.unsigned ofs) rs m = Next rs m. +Proof. + unfold exec_prologue. intros. + destruct (Z.eq_dec); eauto. omega. +Qed. + +Lemma basic_step_simulation: forall ms sp rs s f tf fb ms' bi m m', + agree ms sp rs -> + match_stack s -> + transf_function f = OK tf -> + Genv.find_funct_ptr ge fb = Some (Internal f) -> + Machblock.basic_step ge s fb sp ms m bi ms' m' -> + exists rs', basic_step tge tf rs m bi rs' m' /\ agree ms' sp rs' /\ rs' PC = rs PC. +Proof. + destruct 5. + (* MBgetstack *) + - eexists; split. + + econstructor; eauto. erewrite agree_sp; eauto. + + eauto. + (* MBsetstack *) + - eexists; split. + + econstructor; eauto. + erewrite agree_sp; eauto. + erewrite <- agree_mregs; eauto. + + rewrite H4; split; eauto. + (* MBgetparam *) + - eexists; split. + + econstructor; eauto. + erewrite agree_sp; eauto. + assert (f = f0). { rewrite H2 in H3. inversion H3. reflexivity. } + assert (fn_link_ofs tf = fn_link_ofs f0). { + rewrite <- H7. + eapply stackinfo_preserved. eauto. + } + rewrite H8. eauto. + + rewrite H6; split; eauto. + (* MBop *) + - eexists; split. + + econstructor; eauto. + erewrite agree_sp; eauto. + erewrite agree_mregs_list in H3. + * erewrite <- H3. + eapply eval_operation_preserved; trivial. + * eauto. + + rewrite H4; split; eauto. + (* MBload *) + - eexists; split. + + econstructor; eauto. + erewrite agree_sp; eauto. erewrite <- agree_mregs_list; eauto. + erewrite <- H3. + eapply eval_addressing_preserved; trivial. + + rewrite H5; split; eauto. + (* MBload notrap1 *) + - eexists; split. + + eapply exec_MBload_notrap1; eauto. + erewrite agree_sp; eauto. + erewrite agree_mregs_list in H3; eauto. + * erewrite eval_addressing_preserved; eauto. + + rewrite H4; eauto. + (* MBload notrap2 *) + - eexists; split. + + eapply exec_MBload_notrap2; eauto. + erewrite agree_sp; eauto. + erewrite agree_mregs_list in H3; eauto. + * erewrite eval_addressing_preserved; eauto. + + rewrite H5; eauto. + (* MBstore *) + - eexists; split. + + econstructor; eauto. + * erewrite agree_sp; eauto. + erewrite agree_mregs_list in H3. + erewrite eval_addressing_preserved; eauto. + eauto. + * erewrite <- agree_mregs; eauto. + + rewrite H5; eauto. +Qed. + +Lemma body_step_simulation: forall ms sp s f tf fb ms' bb m m', + match_stack s -> + transf_function f = OK tf -> + Genv.find_funct_ptr ge fb = Some (Internal f) -> + Machblock.body_step ge s fb sp bb ms m ms' m' -> + forall rs, agree ms sp rs -> + exists rs', body_step tge tf bb rs m rs' m' /\ agree ms' sp rs' /\ rs' PC = rs PC. +Proof. + induction 4. + - repeat (econstructor; eauto). + - intros. exploit basic_step_simulation; eauto. + intros (rs'0 & BASIC & AG1' & AGPC1). + exploit IHbody_step; eauto. + intros (rs'1 & BODY & AG2' & AGPC2). + repeat (econstructor; eauto). + congruence. +Qed. + +Local Hint Resolve trivial_exec_prologue: core. + +Lemma exit_step_simulation s fb f sp c t bb ms m s1' tf rs pc + (STEP: Machblock.exit_step rao ge (exit bb) (Machblock.State s fb sp (bb :: c) ms m) t s1') + (STACKS: match_stack s) + (AG: agree ms sp rs) + (NXT: next_addr next tf rs = Some pc) + (AT: transl_code_at_pc fb f tf c pc): + exists rs' m', exit_step next tge tf (exit bb) (rs#PC <- pc) m t rs' m' /\ match_states s1' (State rs' m'). +Proof. + inv AT. + inv STEP. + (* cfi_step currently only defined for exec_MBcall, exec_MBreturn, and exec_MBgoto *) + - inversion H4; subst. clear H4. (* inversion_clear H4 does not work so well: it clears an important hypothesis about "sp" in the Mreturn case *) + (* MBcall *) + + eexists. eexists. split. + * apply exec_Some_exit. + apply exec_MBcall. + eapply find_function_ptr_agree; eauto. + * assert (f0 = f). { congruence. } subst. + assert (Ptrofs.unsigned ra = Ptrofs.unsigned ofs). { + eapply is_pos_inject1; eauto. + } + assert (ofs = ra). { + apply Ptrofs.same_if_eq. unfold Ptrofs.eq. + rewrite H4. rewrite zeq_true. reflexivity. + } + repeat econstructor; eauto. + -- unfold rao in *. congruence. + -- simpl. simplify_regmap. + erewrite agree_sp; eauto. + -- simpl. simplify_regmap. auto. + (* MBtailcall *) + + assert (f0 = f). { congruence. } subst. + eexists. eexists. split. + * repeat econstructor. + -- eapply find_function_ptr_agree; eauto. + -- unfold exec_epilogue. erewrite agree_sp; eauto. + apply stackinfo_preserved in H0 as ( SS & RA & LO ). + rewrite SS, RA, LO. + try_simplify_someHyps. + * repeat econstructor; eauto. + intros r. + eapply agree_mregs; eapply agree_set_other; eauto. + (* MBbuiltin *) + +eexists. eexists. split. + * repeat econstructor. + -- simplify_regmap. erewrite agree_sp; eauto. + eapply eval_builtin_args_preserved; eauto. + -- eapply external_call_symbols_preserved; eauto. + exact senv_preserved. + * repeat econstructor; eauto. + -- assert (transl_function f = tf). { + unfold transf_function in *. congruence. + } + erewrite H5. assumption. + -- eapply agree_sp. eapply agree_set_res. eapply agree_undef_regs. + eapply agree_set_from_Machrs; eauto. + -- intros; simpl. + eapply agree_set_res. eapply agree_undef_regs. + eapply agree_set_from_Machrs; eauto. + (* MBgoto *) + + simplify_someHyps. intros. + assert ((rs # PC <- (Vptr fb ofs)) PC = Vptr fb ofs). { + rewrite Pregmap.gss. reflexivity. + } + eassert (exists pc, goto_label next tf lbl rs # PC <- (Vptr fb ofs) = Some pc + /\ transl_code_at_pc fb f tf c' pc) as (pc & GOTO_LABEL & _). { + eapply find_label_goto_label; eauto. + } + eexists. eexists. split. + * apply exec_Some_exit. + apply exec_MBgoto. + rewrite GOTO_LABEL. trivial. + * repeat econstructor; eauto. + -- simplify_regmap. + exploit find_label_goto_label; eauto. intros (pc' & GOTO_LABEL' & TRANSL). + assert(pc' = pc). { congruence. } subst. eauto. + -- simplify_regmap. erewrite agree_sp; eauto. + (* MBcond true *) + (* Mostly copy and paste from MBgoto *) + + simplify_someHyps. intros. + assert ((rs # PC <- (Vptr fb ofs)) PC = Vptr fb ofs). { + rewrite Pregmap.gss. reflexivity. + } + eassert (exists pc, goto_label next tf lbl rs # PC <- (Vptr fb ofs) = Some pc + /\ transl_code_at_pc fb f tf c' pc) as (pc & GOTO_LABEL & _). { + eapply find_label_goto_label; eauto. + } + eexists. eexists. split. + * apply exec_Some_exit. eapply exec_MBcond_true; eauto. + erewrite agree_mregs_list in H14; eauto. + * repeat econstructor; eauto. + -- simplify_regmap. + exploit find_label_goto_label; eauto. intros (pc' & GOTO_LABEL' & TRANSL). + assert(pc' = pc). { congruence. } subst. eauto. + -- simplify_regmap. erewrite agree_sp; eauto. + (* MBcond false *) + + inv H0. eexists. eexists. split. + * apply exec_Some_exit. apply exec_MBcond_false. + -- erewrite agree_mregs_list in H15; eauto. + -- trivial. + * repeat econstructor; eauto. erewrite agree_sp; eauto. + (* MBjumptable *) + + simplify_someHyps. intros. + assert ((rs # PC <- (Vptr fb ofs)) PC = Vptr fb ofs). { + rewrite Pregmap.gss. reflexivity. + } + eassert (exists pc, goto_label next tf lbl rs # PC <- (Vptr fb ofs) = Some pc + /\ transl_code_at_pc fb f tf c' pc) as (pc & GOTO_LABEL & _). { + eapply find_label_goto_label; eauto. + } + eexists. eexists. split. + * repeat econstructor; eauto. + rewrite <- H14. + symmetry. eapply agree_mregs. eapply agree_set_other; eauto. + * repeat econstructor; eauto. + (* copy paste from MBgoto *) + -- simplify_regmap. + exploit find_label_goto_label; eauto. intros (pc' & GOTO_LABEL' & TRANSL). + assert(pc' = pc). { congruence. } subst. eauto. + -- simplify_regmap. erewrite agree_sp; eauto. + -- intros; simplify_regmap. eauto. + + (* MBreturn *) + try_simplify_someHyps. + eexists. eexists. split. + * apply exec_Some_exit. + apply exec_MBreturn. + unfold exec_epilogue. + erewrite agree_sp; eauto. + apply stackinfo_preserved in H0 as ( SS & RA & LO ). + rewrite SS, RA, LO. + try_simplify_someHyps. + * repeat econstructor; eauto. intros r. + simplify_regmap. eapply agree_mregs; eauto. + - inv H0; repeat econstructor; eauto. + erewrite agree_sp; eauto. +Qed. + +Lemma inst_step_simulation s fb f sp c t ms m s1' tf rs + (STEP: Machblock.step rao ge (Machblock.State s fb sp c ms m) t s1') + (STACKS: match_stack s) + (AT: transl_code_at_pc fb f tf c (rs PC)) + (AG: agree ms sp rs): + exists s2' : state, plus (step next) tge (State rs m) t s2' /\ match_states s1' s2'. +Proof. + inv STEP. + inv AT. + exploit body_step_simulation; eauto. intros (rs0' & BODY & AG0 & AGPC). + assert (NXT: next_addr next tf rs0' = Some (Vptr fb (Ptrofs.repr (next tf (Ptrofs.unsigned ofs))))). + { unfold next_addr; rewrite AGPC, <- H; simpl; eauto. } + exploit exit_step_simulation; eauto. + { econstructor; eauto. + erewrite is_pos_unsigned_repr; eauto. + generalize (next_progress tf (Ptrofs.unsigned ofs)); omega. } + intros (rs2 & m2 & STEP & MS). + eexists. + split; eauto. + eapply plus_one. + eapply exec_step_internal; eauto. + econstructor; eauto. +Qed. + +Lemma prologue_preserves_pc: forall f rs0 m0 rs1 m1, + exec_prologue f 0 rs0 m0 = Next rs1 m1 -> + rs1 PC = rs0 PC. +Proof. + unfold exec_prologue; simpl; + intros f rs0 m0 rs1 m1 H. + destruct (Mem.alloc m0 0 (fn_stacksize f)) in H; unfold Next in H. + simplify_someHyps; inversion_SOME ignored; inversion_SOME ignored'; + intros ? ? H'; inversion H'; trivial. +Qed. + +Lemma is_pos_next_zero bb c fb f + (FIND : Genv.find_funct_ptr ge fb = Some (Internal f)) + (FN_HEAD : bb :: c = fn_code f): + is_pos next (transl_function f) (next (transl_function f) (Ptrofs.unsigned Ptrofs.zero)) (if has_header (fn_code f) then bb::c else c). +Proof. + exploit (transf_function_def f). unfold transf_function; auto. + unfold insert_implicit_prologue. + intros fn_code_tf; destruct (has_header (fn_code f)); + eapply Next_pos; rewrite Ptrofs.unsigned_zero; + rewrite FN_HEAD; rewrite <- fn_code_tf; apply First_pos. +Qed. + +Lemma prologue_simulation_no_header_step t s1' s sp fb ms f m1 rs0 m0 rs1 + (STACKS : match_stack s) + (AG : agree ms sp rs1) + (ATPC : rs0 PC = Vptr fb Ptrofs.zero) + (ATLR : rs0 RA = parent_ra s) + (FIND : Genv.find_funct_ptr ge fb = Some (Internal f)) + (PROL : exec_prologue f 0 rs0 m0 = Next rs1 m1) + (STEP : Machblock.step rao ge (Machblock.State s fb sp (fn_code f) ms m1) t s1') + (NO_HEADER: has_header (fn_code f) = false): + exists s2' : state, step next tge {| _rs := rs0; _m := m0 |} t s2' /\ match_states s1' s2'. +Proof. + inv STEP. + + exploit functions_translated; eauto; + intros (tf & FINDtf & TRANSf); monadInv TRANSf. + assert (fn_code f = fn_code (transl_function f)) as TF_CODE. { + unfold transl_function; simpl; unfold insert_implicit_prologue; + rewrite NO_HEADER; trivial. + } + + exploit body_step_simulation; eauto; unfold transf_function; auto. + intros (rs0' & BODY & AG0 & AGPC). + + exploit prologue_preserves_pc; eauto. + intros AGPC'. + + exploit is_pos_next_zero; eauto; rewrite NO_HEADER. + intros IS_POS. + + exploit transl_code_at_pc_intro; eauto; unfold transf_function; auto. { + rewrite Ptrofs.unsigned_zero; erewrite is_pos_unsigned_repr; eauto. + } intros TRANSL_CODE. + + assert (next_addr next (transl_function f) rs0' = + Some (Vptr fb (Ptrofs.repr (next (transl_function f) + (Ptrofs.unsigned Ptrofs.zero))))) as NEXT_ADDR. { + unfold next_addr; rewrite AGPC; rewrite AGPC'; rewrite ATPC; reflexivity. + } + + exploit exit_step_simulation; eauto. + intros (? & ? & EXIT_STEP & MATCH_EXIT). + + exploit exec_bblock_all; eauto. + intros EXEC_BBLOCK. + + exploit exec_step_internal; eauto. + apply is_pos_simplify; eauto. rewrite H3; rewrite TF_CODE; apply First_pos. +Qed. + +Lemma prologue_simulation_header_step t s1' s sp fb ms f m1 rs0 m0 rs1 + (STACKS : match_stack s) + (AG : agree ms sp rs1) + (ATPC : rs0 PC = Vptr fb Ptrofs.zero) + (ATLR : rs0 RA = parent_ra s) + (FIND : Genv.find_funct_ptr ge fb = Some (Internal f)) + (PROL : exec_prologue f 0 rs0 m0 = Next rs1 m1) + (STEP : Machblock.step rao ge (Machblock.State s fb sp (fn_code f) ms m1) t s1') + (HEADER: has_header (fn_code f) = true): + exists s2' : state, plus (step next) tge {| _rs := rs0; _m := m0 |} t s2' /\ match_states s1' s2'. +Proof. + inv STEP. + + (* FIRST STEP *) + exploit functions_translated; eauto; + intros (tf & FINDtf & TRANSf); monadInv TRANSf. + exploit transf_function_def; eauto; unfold transf_function; auto; + unfold insert_implicit_prologue; rewrite HEADER; intros TF_CODE. + + exploit is_pos_next_zero; eauto; rewrite HEADER; rewrite H3; + intros IS_POS. + + exploit prologue_preserves_pc; eauto. + intros AGPC'. + + assert ( next_addr next (transl_function f) rs1 + = Some (Vptr fb (Ptrofs.repr (next (transl_function f) (Ptrofs.unsigned Ptrofs.zero)))) + ) as NEXT_ADDR0. { unfold next_addr; rewrite AGPC'; rewrite ATPC; trivial. } + + exploit exec_nil_body; intros BODY0. + assert ((body {| header := nil; body := nil; exit := None |}) = nil) as NIL; auto. + rewrite <- NIL in BODY0. + + exploit exec_None_exit; intros EXIT0. + assert ((exit {| header := nil; body := nil; exit := None |}) = None) as NONE; auto. + rewrite <- NONE in EXIT0. + + exploit exec_bblock_all; eauto; + intros BBLOCK0. + + exploit exec_step_internal; eauto. rewrite <- TF_CODE; apply First_pos. + intros STEP0. + + clear BODY0 BBLOCK0 EXIT0. + + (* SECOND step *) + + exploit (mkagree ms sp + (rs1 # PC <- (Vptr fb (Ptrofs.repr (next (transl_function f) + (Ptrofs.unsigned Ptrofs.zero)))))); eauto. + apply (agree_sp ms); apply agree_set_other; eauto. + intros AG'. + + exploit body_step_simulation; eauto; unfold transf_function; auto. + intros (rs1' & BODY1 & AGRS1' & AGPC). + + assert ( next_addr next (transl_function f) rs1' + = Some (Vptr fb (Ptrofs.repr (next (transl_function f) (Ptrofs.unsigned + (Ptrofs.repr (next (transl_function f) (Ptrofs.unsigned Ptrofs.zero))))))) + ) as NEXT_ADDR1. { unfold next_addr; rewrite AGPC; reflexivity. } + + assert (IS_POS' := IS_POS). + rewrite <- H3 in IS_POS'; apply Next_pos in IS_POS'. + exploit transl_code_at_pc_intro; eauto; unfold transf_function; auto. { + rewrite Ptrofs.unsigned_zero; erewrite is_pos_unsigned_repr; eauto. + assert (0 < next (transl_function f) 0) as Z0. { apply next_progress. } + assert ( next (transl_function f) 0 + < next (transl_function f) (next (transl_function f) 0) + ) as Z1. { apply next_progress. } + rewrite <- Z1. exact Z0. + } intros TRANSL_CODE1. + + exploit exit_step_simulation; eauto. + rewrite Ptrofs.unsigned_repr. + 2: { + assert(max_pos (transl_function f) <= Ptrofs.max_unsigned) as MAX_POS. { + eapply functions_bound_max_pos; eauto. + } + rewrite <- MAX_POS. + eapply is_pos_bound_pos; eauto. + } + exact TRANSL_CODE1. + intros (? & ? & EXIT_STEP & MATCH_EXIT). + + exploit (trivial_exec_prologue (transl_function f) (Ptrofs.repr (next (transl_function f) (Ptrofs.unsigned Ptrofs.zero)))). { + rewrite Ptrofs.unsigned_zero; erewrite is_pos_unsigned_repr; eauto. + } intros NO_PROL. + + exploit exec_bblock_all; eauto; intros BBLOCK1. + + clear AGPC. + rewrite <- H3 in IS_POS. + exploit (exec_step_internal next tge fb + (Ptrofs.repr (next (transl_function f) (Ptrofs.unsigned Ptrofs.zero))) + (transl_function f) + bb c); simplify_regmap; eauto. + + intros STEP1. + + eexists; split. + + eapply plus_two. + * exact STEP0. + * exact STEP1. + * trivial. + + assumption. +Qed. + +Lemma step_simulation s1 t s1': + Machblock.step rao ge s1 t s1' -> + forall s2, match_states s1 s2 -> + (exists s2', plus (step next) tge s2 t s2' /\ match_states s1' s2') \/ ((measure s1' < measure s1)%nat /\ t = E0 /\ match_states s1' s2). +Proof. + intros STEP s2 MATCH; destruct MATCH. + - exploit inst_step_simulation; eauto. + - left. + destruct (has_header (fn_code f)) eqn:NO_HEADER. + + eapply prologue_simulation_header_step; eauto. + + exploit prologue_simulation_no_header_step; eauto; + intros (s2' & NO_HEADER_STEP & MATCH_STATES). + eexists; split; eauto. + apply plus_one; eauto. + - inv STEP; simpl; exploit functions_translated; eauto; + intros (tf0 & FINDtf & TRANSf); + monadInv TRANSf. + * (* internal calls *) + right. + intuition. + econstructor; eauto. + -- exploit + (mkagree (undef_regs destroyed_at_function_entry ms) + sp + (set_from_Machrs (undef_regs destroyed_at_function_entry rs) rs) # SP <- sp + ); eauto. + ++ unfold sp; discriminate. + ++ intros mr; unfold undef_regs; + induction destroyed_at_function_entry as [ | ? ? IH]. + ** inversion AG as [_ _ AG_MREGS]; apply AG_MREGS. + ** fold undef_regs in *; + unfold Regmap.set; simpl; rewrite IH; reflexivity. + -- unfold exec_prologue; + inversion AG as (RS_SP & ?); rewrite RS_SP; fold sp; + rewrite H4; fold sp; rewrite H7; rewrite ATLR; rewrite H8; eauto. + * (* external calls *) + left. + exploit extcall_arguments_match; eauto. + eexists; split. + + eapply plus_one. + eapply exec_step_external; eauto. + eapply external_call_symbols_preserved; eauto. apply senv_preserved. + + econstructor; eauto. + - (* Returnstate *) + inv STEP; simpl; right. + inv STACKS; simpl in *; subst. + repeat (econstructor; eauto). +Qed. + +(** * The main simulation theorem *) + +Theorem transf_program_correct: + forward_simulation (Machblock.semantics rao prog) (semantics next tprog). +Proof. + eapply forward_simulation_star with (measure := measure). + apply senv_preserved. + - eexact transf_initial_states. + - eexact transf_final_states. + - eexact step_simulation. +Qed. + +End PRESERVATION. diff --git a/multiple_labels_crash_test/check.c b/multiple_labels_crash_test/check.c new file mode 100644 index 00000000..3c2ff89d --- /dev/null +++ b/multiple_labels_crash_test/check.c @@ -0,0 +1,120 @@ +#include "init.h" + +unsigned long long int checksum () { + unsigned long long int seed = 0ULL; + hash(&seed, var_36); + hash(&seed, var_37); + hash(&seed, var_38); + hash(&seed, var_39); + hash(&seed, var_40); + hash(&seed, var_41); + hash(&seed, var_42); + hash(&seed, var_43); + hash(&seed, var_44); + hash(&seed, var_45); + hash(&seed, var_46); + hash(&seed, var_47); + hash(&seed, var_48); + hash(&seed, var_49); + hash(&seed, var_50); + hash(&seed, var_51); + hash(&seed, var_52); + hash(&seed, var_53); + hash(&seed, var_54); + hash(&seed, var_55); + hash(&seed, var_56); + hash(&seed, var_57); + hash(&seed, var_58); + hash(&seed, var_59); + hash(&seed, var_60); + hash(&seed, var_61); + hash(&seed, var_62); + hash(&seed, var_63); + hash(&seed, var_64); + hash(&seed, var_65); + hash(&seed, var_70); + hash(&seed, var_78); + hash(&seed, var_82); + hash(&seed, var_90); + hash(&seed, var_94); + hash(&seed, var_100); + hash(&seed, var_106); + hash(&seed, var_123); + hash(&seed, var_129); + hash(&seed, var_143); + hash(&seed, var_152); + hash(&seed, var_156); + hash(&seed, var_162); + hash(&seed, var_178); + hash(&seed, var_217); + hash(&seed, var_234); + hash(&seed, var_240); + hash(&seed, var_241); + hash(&seed, var_260); + hash(&seed, var_268); + hash(&seed, var_284); + hash(&seed, var_297); + hash(&seed, var_314); + hash(&seed, var_358); + hash(&seed, var_359); + hash(&seed, var_367); + hash(&seed, var_392); + hash(&seed, var_468); + hash(&seed, var_500); + hash(&seed, var_514); + hash(&seed, var_522); + hash(&seed, var_543); + hash(&seed, var_544); + hash(&seed, var_547); + hash(&seed, var_549); + hash(&seed, var_558); + hash(&seed, var_591); + hash(&seed, struct_obj_5.member_1_0); + hash(&seed, struct_obj_5.member_1_1); + hash(&seed, struct_obj_5.member_1_2); + hash(&seed, struct_obj_5.member_1_3); + hash(&seed, struct_obj_6.member_5_0); + hash(&seed, struct_obj_6.member_5_1); + hash(&seed, struct_obj_6.member_5_2); + hash(&seed, struct_obj_6.member_5_3); + hash(&seed, struct_obj_7.member_1_0); + hash(&seed, struct_obj_7.member_1_1); + hash(&seed, struct_obj_7.member_1_2); + hash(&seed, struct_obj_7.member_1_3); + hash(&seed, struct_obj_8.member_4_0); + hash(&seed, struct_obj_8.member_4_1.member_3_0); + hash(&seed, struct_obj_8.member_4_1.member_3_1.member_1_0); + hash(&seed, struct_obj_8.member_4_1.member_3_1.member_1_1); + hash(&seed, struct_obj_8.member_4_1.member_3_1.member_1_2); + hash(&seed, struct_obj_8.member_4_1.member_3_1.member_1_3); + hash(&seed, struct_obj_8.member_4_2); + hash(&seed, struct_obj_8.member_4_3); + hash(&seed, struct_obj_8.member_4_4); + hash(&seed, struct_obj_8.member_4_5); + hash(&seed, struct_obj_8.member_4_6); + hash(&seed, struct_obj_8.member_4_7); + hash(&seed, struct_obj_8.member_4_8); + hash(&seed, struct_obj_8.member_4_9.member_1_0); + hash(&seed, struct_obj_8.member_4_9.member_1_1); + hash(&seed, struct_obj_8.member_4_9.member_1_2); + hash(&seed, struct_obj_8.member_4_9.member_1_3); + hash(&seed, struct_obj_9.member_2_0); + hash(&seed, struct_obj_9.member_2_1.member_1_0); + hash(&seed, struct_obj_9.member_2_1.member_1_1); + hash(&seed, struct_obj_9.member_2_1.member_1_2); + hash(&seed, struct_obj_9.member_2_1.member_1_3); + hash(&seed, struct_obj_9.member_2_2); + hash(&seed, struct_obj_9.member_2_3.member_1_0); + hash(&seed, struct_obj_9.member_2_3.member_1_1); + hash(&seed, struct_obj_9.member_2_3.member_1_2); + hash(&seed, struct_obj_9.member_2_3.member_1_3); + hash(&seed, struct_obj_9.member_2_4); + hash(&seed, struct_obj_9.member_2_5); + hash(&seed, struct_obj_9.member_2_6); + hash(&seed, struct_obj_9.member_2_7); + hash(&seed, struct_obj_10.member_1_0); + hash(&seed, struct_obj_10.member_1_1); + hash(&seed, struct_obj_10.member_1_2); + hash(&seed, struct_obj_10.member_1_3); + return seed; +}
\ No newline at end of file diff --git a/multiple_labels_crash_test/driver.c b/multiple_labels_crash_test/driver.c new file mode 100644 index 00000000..3084e131 --- /dev/null +++ b/multiple_labels_crash_test/driver.c @@ -0,0 +1,12 @@ +#include <stdio.h> +#include "init.h" + +extern void init (); +extern void foo (); +extern unsigned long long int checksum (); + +int main () { + init (); + foo (); + printf("%llu\n", checksum ()); return 0; +}
\ No newline at end of file diff --git a/multiple_labels_crash_test/func.c b/multiple_labels_crash_test/func.c new file mode 100644 index 00000000..cc9d3653 --- /dev/null +++ b/multiple_labels_crash_test/func.c @@ -0,0 +1,915 @@ +#include "init.h" + +void foo () +{ + unsigned short var_66 = ~((int) ((((int) (((int) (((int) (-27782)) > ((int) (5913)))) <= ((int) ((signed char) (11720))))) | ((int) (30935))) <= (((~((int) (-17))) * (((int) (92)) * ((int) (7)))) * ((int) (56914))))); + if ((unsigned short) ((short) (((int) ((unsigned short) (((int) (-5211)) & ((int) (var_47))))) <= (((int) ((short) (15973))) & ((int) (17901)))))) + { + var_58 = (signed char) (((int) ((((int) (-104)) | ((((int) (-16858)) ^ ((int) (var_24))) ^ ((int) ((signed char) (-45))))) <= ((int) ((signed char) (+((int) (struct_obj_4.member_2_5))))))) != (((int) (4536)) || ((int) (50251)))); + if ((((((int) (63229)) && ((int) ((signed char) (115)))) - ((int) (struct_obj_4.member_2_3.member_1_0))) - (((!((int) (-7155))) || ((int) (-7))) << (((int) ((signed char) (-((int) (var_15))))) - (43)))) || (-((((int) ((signed char) (struct_obj_10.member_1_3))) - (((int) (-24985)) + ((int) (var_31)))) - ((+((int) (253))) + (((int) (-26639)) + ((int) (24190))))))) + { + short var_67 = (!((int) (((!((int) (6))) && (!((int) (21935)))) != ((int) ((unsigned short) (((int) (51591)) & ((int) (-41)))))))) << ((int) (((~((int) (-29500))) & (~(((int) (var_27)) & ((int) (struct_obj_6.member_5_2))))) <= ((int) (var_23)))); + signed char var_68 = (short) ((~((int) ((unsigned short) (~((int) (var_28)))))) | (~((int) ((short) (~((int) (var_6))))))); + if (((((int) (struct_obj_7.member_1_1)) ^ ((((((int) (-12017)) + (2147483647)) >> (((int) (-5)) + (5))) >> ((((int) (struct_obj_4.member_2_7)) ^ ((int) (var_34))) - (9570))) >> ((int) ((~((int) ((short) (struct_obj_4.member_2_1.member_1_0)))) != (((int) ((signed char) (var_1))) | ((int) ((unsigned short) ((((int) (var_19)) & ((int) (struct_obj_1.member_5_2))) & (~((int) (-114))))))))))) + (2147483647)) >> ((((((int) (var_29)) & ((int) (var_8))) | ((int) ((unsigned short) (var_48)))) & ((~((int) (struct_obj_8.member_4_5))) << (((int) ((unsigned short) (struct_obj_8.member_4_6))) - (51692)))) << ((((((int) (49144)) << (((int) (struct_obj_5.member_1_1)) - (28946))) << (((-((int) ((signed char) ((((int) ((short) (-246))) ^ (((int) (var_30)) << (((int) (var_3)) - (49)))) || ((+((int) (var_9))) >> ((((int) (struct_obj_4.member_2_1.member_1_0)) | ((int) (53547))) - (53607))))))) + (20)) - (15))) ^ ((((int) (27896)) ^ ((int) (struct_obj_2.member_5_1))) << ((~((int) (var_56))) + (20190)))) - (100631155)))) + { + unsigned short var_69 = ((int) (((int) (((int) ((((int) (struct_obj_3.member_5_1)) && ((int) (var_18))) < ((int) (((int) (14551)) <= ((int) (-206)))))) >= ((int) ((~((int) ((short) (struct_obj_4.member_2_1.member_1_0)))) != (((int) ((signed char) (var_1))) | ((int) ((unsigned short) ((((int) (var_19)) & ((int) (struct_obj_1.member_5_2))) & (~((int) (-114))))))))))) != (!(((((int) (-2718)) * ((int) (struct_obj_9.member_2_7))) + (2147483647)) >> (((int) ((unsigned short) (-122))) - (65411)))))) >> ((!((!((int) (-34))) && (!((int) (11439))))) || (((((int) (10371)) || ((int) (18010))) || (((int) (52917)) && ((int) (-118)))) || ((((int) (23)) || ((int) (15037))) && (((int) (93)) && ((int) (-12489)))))); + var_70 = (signed char) (((((((int) (34812)) * ((int) (var_13))) / (((int) (struct_obj_1.member_5_1)) * ((int) (var_65)))) * (!(((int) (var_35)) * ((int) (62))))) * (-((int) ((~((int) ((short) (struct_obj_4.member_2_1.member_1_0)))) != (((int) ((signed char) (var_1))) | ((int) ((unsigned short) ((((int) (var_19)) & ((int) (struct_obj_1.member_5_2))) & (~((int) (-114))))))))))) ^ (-((int) ((signed char) ((((int) ((short) (-246))) ^ (((int) (var_30)) << (((int) (var_3)) - (49)))) || ((+((int) (var_9))) >> ((((int) (struct_obj_4.member_2_1.member_1_0)) | ((int) (53547))) - (53607)))))))); + struct_obj_9.member_2_5 = (unsigned short) (((((-((int) ((signed char) ((((int) ((short) (-246))) ^ (((int) (var_30)) << (((int) (var_3)) - (49)))) || ((+((int) (var_9))) >> ((((int) (struct_obj_4.member_2_1.member_1_0)) | ((int) (53547))) - (53607))))))) ^ (((~((int) (44847))) + (2147483647)) >> (((int) ((short) (var_4))) - (3630)))) + (2147483647)) << (((int) ((unsigned short) ((~((int) (struct_obj_2.member_5_1))) | (~((int) (struct_obj_4.member_2_3.member_1_0)))))) - (65535))) ^ (~(~(((int) ((unsigned short) (var_41))) ^ (((int) (struct_obj_9.member_2_5)) << (((int) (struct_obj_9.member_2_4)) - (13536))))))); + unsigned short var_71 = (unsigned short) (~((int) ((signed char) ((((int) (15546)) << (((int) (58115)) - (58101))) >> ((~((int) (-17858))) - (17855)))))); + unsigned short var_72 = ((int) ((((int) ((signed char) (((int) (var_53)) > ((int) (struct_obj_7.member_1_0))))) * ((int) (((int) (((int) (struct_obj_1.member_5_2)) <= ((int) (4016)))) > (((int) (23666)) % ((int) (-117)))))) <= (((int) ((((int) (struct_obj_4.member_2_6)) ^ ((int) (struct_obj_1.member_5_3))) <= ((int) (var_52)))) && (~((int) (58979)))))) * ((int) (struct_obj_1.member_5_0)); + short var_73 = ((int) ((((~((int) (var_46))) | (((int) (struct_obj_9.member_2_1.member_1_1)) | ((int) (42879)))) | ((~((int) (var_55))) & (((int) (var_66)) & ((int) (struct_obj_10.member_1_3))))) <= ((int) ((~(!((int) (64290)))) > ((int) ((signed char) (((int) (struct_obj_1.member_5_3)) * ((int) (10324))))))))) >> (!((~(~((int) (var_30)))) >> (((((int) (struct_obj_9.member_2_4)) | ((int) (struct_obj_3.member_5_2))) & ((int) (struct_obj_9.member_2_0))) - (41371)))); + unsigned short var_74 = (((int) (struct_obj_8.member_4_5)) + (2147483647)) << ((((((((int) ((short) (~((((int) ((short) ((short) (~(((int) (65)) << (((int) (-26039)) + (26049))))))) + (2147483647)) >> ((~((int) ((unsigned short) ((((int) (40110)) | ((int) (85))) << ((((int) ((short) (-45))) + (61)) - (14)))))) + (29723)))))) + (29)) - (26)) - (0)) - (0)) - (0)) - (1)); + unsigned short var_75 = ((int) ((short) (23390))) + (((int) (((int) (((int) ((signed char) (struct_obj_10.member_1_3))) <= ((((int) ((short) ((short) (~(((int) (65)) << (((int) (-26039)) + (26049))))))) + (2147483647)) >> ((~((int) ((unsigned short) ((((int) (40110)) | ((int) (85))) << ((((int) ((short) (-45))) + (61)) - (14)))))) + (29723))))) < ((((int) (-41)) && ((int) (var_71))) && (!((int) (5)))))) ^ (((((int) (35578)) * ((int) (struct_obj_5.member_1_0))) * (((int) (var_69)) * ((int) (103)))) || ((int) (struct_obj_8.member_4_7)))); + short var_76 = ((int) (-63)) + ((int) ((short) ((((int) (((int) (46788)) != ((int) (struct_obj_4.member_2_1.member_1_3)))) || (!((int) (-115)))) << (((((int) (struct_obj_4.member_2_1.member_1_1)) * ((int) (var_1))) - (((int) (20657)) + ((int) (struct_obj_9.member_2_0)))) + (1945793196))))); + short var_77 = +(((+(((int) (117)) * ((int) (-115)))) * ((((int) (57)) * ((int) (-8289))) / ((-((((int) (var_26)) || (((int) (1474)) && ((int) (var_34)))) || ((!((int) (95))) && (((int) (var_26)) || ((int) (7528)))))) - ((int) (struct_obj_4.member_2_0))))) * ((int) ((signed char) (var_65)))); + } + + var_78 = (short) (((((((int) (var_61)) | ((int) (var_15))) | (((int) (var_52)) & ((int) (5914)))) & (~((int) (struct_obj_2.member_5_0)))) | (~(~(((int) (31461)) | ((int) (var_24)))))) != ((int) ((signed char) ((~((int) (((int) (struct_obj_6.member_5_0)) < ((int) (struct_obj_9.member_2_6))))) * ((+((int) (21135))) && (!((int) (100)))))))); + if (-((int) (struct_obj_8.member_4_0))) + { + signed char var_79 = var_12; + unsigned short var_80 = var_56; + short var_81 = !(((((int) (struct_obj_4.member_2_0)) || (((int) (struct_obj_8.member_4_1.member_3_1.member_1_0)) && ((int) (45)))) || ((int) ((short) (((int) (struct_obj_1.member_5_1)) || ((int) (var_67)))))) || ((int) (var_31))); + var_54 = (short) ((((int) (var_54)) + (2147483647)) >> (((int) ((short) (((int) (var_62)) ^ ((int) (struct_obj_2.member_5_2))))) - (25016))); + var_82 = (unsigned short) ((~((int) (((~((int) (var_47))) * ((((int) (struct_obj_7.member_1_1)) + (2147483647)) >> (((int) (var_18)) - (75)))) <= ((!((int) (var_66))) % ((int) ((unsigned short) (8))))))) > (+((~((((int) (-22)) * ((int) (struct_obj_4.member_2_3.member_1_3))) / (((int) (-32289)) * ((int) (var_6))))) * (~((((int) (struct_obj_2.member_5_1)) * ((int) (var_4))) * (!((int) (var_7)))))))); + short var_83 = (-(-((int) ((~((int) (struct_obj_10.member_1_3))) <= (((int) (struct_obj_8.member_4_2)) * ((int) (29850))))))) >> (((int) (((int) ((~((int) ((short) (struct_obj_4.member_2_1.member_1_0)))) != (((int) ((signed char) (var_1))) | ((int) ((unsigned short) ((((int) (var_19)) & ((int) (struct_obj_1.member_5_2))) & (~((int) (-114))))))))) <= (((int) (struct_obj_5.member_1_1)) * ((int) (var_51))))) & (((int) ((+((int) (struct_obj_9.member_2_1.member_1_0))) <= ((int) ((signed char) (21412))))) >> (((int) (var_13)) + (23934)))); + signed char var_84 = !(-((int) (struct_obj_5.member_1_0))); + signed char var_85 = ((int) ((~((int) ((short) (struct_obj_4.member_2_1.member_1_0)))) != (((int) ((signed char) (var_1))) | ((int) ((unsigned short) ((((int) (var_19)) & ((int) (struct_obj_1.member_5_2))) & (~((int) (-114))))))))) * (((int) ((unsigned short) ((~((int) (var_15))) / (((int) (var_23)) * ((int) (var_15)))))) * (((int) ((short) (((int) (struct_obj_1.member_5_2)) * ((int) (struct_obj_3.member_5_0))))) * ((((int) (struct_obj_1.member_5_1)) * ((int) (struct_obj_4.member_2_6))) / (((int) (var_26)) * ((int) (60852)))))); + short var_86 = -((int) (struct_obj_9.member_2_6)); + } + + short var_87 = ((int) ((short) ((((int) (((int) (-4380)) > ((int) (var_20)))) || (((int) (struct_obj_2.member_5_1)) >> (((int) (var_56)) - (20160)))) <= ((((int) (struct_obj_4.member_2_3.member_1_3)) && ((int) (struct_obj_2.member_5_2))) || (!((int) (struct_obj_6.member_5_2))))))) < (~(((int) (33)) || ((int) ((short) (((int) (var_12)) * ((int) (var_40))))))); + } + + if ((~(((int) (((int) ((unsigned short) (83))) >= ((int) ((unsigned short) (29637))))) || ((((int) (10308)) && ((int) (struct_obj_3.member_5_0))) || (((int) (var_33)) || ((int) (var_28)))))) < ((int) ((signed char) (+((int) ((signed char) (((int) (var_2)) - ((int) (struct_obj_4.member_2_7))))))))) + { + signed char var_88 = (short) (!((int) ((unsigned short) (!(((int) (var_17)) || ((int) (struct_obj_8.member_4_7))))))); + if (((int) (((int) (((int) ((((int) (59)) && ((int) (var_47))) <= (((int) (17266)) - ((int) (3015))))) != ((int) (var_17)))) >= ((int) ((unsigned short) (struct_obj_4.member_2_7))))) ^ ((~((((int) (80)) >> (((int) (91)) - (69))) | ((int) ((unsigned short) (struct_obj_1.member_5_0))))) ^ (((~((int) (39542))) & ((int) (60573))) ^ ((((int) (-21393)) ^ ((int) (-10090))) << (((int) (-10709)) + (10717)))))) + { + short var_89 = ~(!(((((int) (64831)) && ((int) (-102))) && (!((int) (-122)))) && (((int) ((signed char) (-26762))) && (((int) (92)) && ((int) (-82)))))); + var_90 = (short) ((signed char) (((((int) ((short) (struct_obj_5.member_1_0))) ^ (((int) (11026)) | ((int) (1914)))) ^ (((int) (var_1)) ^ (((int) (struct_obj_10.member_1_3)) | ((int) (-10))))) & (((int) (struct_obj_8.member_4_9.member_1_0)) | ((int) (var_88))))); + signed char var_91 = ~(!(~(((int) ((signed char) (struct_obj_9.member_2_1.member_1_3))) & ((int) (var_9))))); + signed char var_92 = ~(~((~((((int) (63094)) | ((int) (struct_obj_4.member_2_2))) >> ((((int) (23595)) >> (((int) (struct_obj_4.member_2_0)) - (7603))) - (171)))) & ((int) ((unsigned short) (45532))))); + signed char var_93 = (signed char) (~(~((int) ((signed char) (struct_obj_3.member_5_3))))); + var_94 = (unsigned short) (((int) ((short) (((((int) (var_16)) ^ ((int) (56567))) & ((int) ((unsigned short) (struct_obj_7.member_1_0)))) | ((int) (var_8))))) & (~((((int) ((short) (var_5))) ^ (~((int) (var_32)))) | ((int) ((signed char) (((int) (var_34)) & ((int) (44163)))))))); + unsigned short var_95 = ~((int) (var_52)); + signed char var_96 = (~(!((int) ((!((int) (struct_obj_4.member_2_3.member_1_0))) > ((int) ((signed char) (19985))))))) <= ((int) ((unsigned short) (((-((int) (14064))) / (((int) (13781)) * ((int) (struct_obj_4.member_2_4)))) * ((((int) (-8630)) * ((int) (var_33))) / ((int) ((short) (struct_obj_2.member_5_2))))))); + unsigned short var_97 = ~(~(((int) (-7658)) | (!(((int) (-28143)) || ((int) (-16555)))))); + } + else + { + short var_98 = (signed char) (~((int) ((signed char) ((((int) (-8)) * ((int) (38))) * (((int) (44)) * ((int) (-25899))))))); + short var_99 = ~((!((((int) (45811)) * ((int) (18866))) / (((int) (36128)) * ((int) (57))))) * ((int) (-15867))); + var_100 = (short) (struct_obj_6.member_5_3); + unsigned short var_101 = (short) (~(-((((int) (var_12)) * ((int) (struct_obj_4.member_2_4))) / (((int) (63446)) * ((int) (var_5)))))); + unsigned short var_102 = ~(~(-(+((int) ((unsigned short) ((((int) (var_27)) + (((int) (struct_obj_4.member_2_7)) + ((int) (struct_obj_2.member_5_1)))) - (+((int) (22407))))))))); + unsigned short var_103 = ((int) (((((((int) (-103)) + (2147483647)) >> (((int) (struct_obj_8.member_4_1.member_3_1.member_1_0)) + (103))) ^ ((int) ((unsigned short) (var_42)))) >> (((int) (struct_obj_7.member_1_0)) + (87))) < (+((int) ((unsigned short) ((((int) (var_27)) + (((int) (struct_obj_4.member_2_7)) + ((int) (struct_obj_2.member_5_1)))) - (+((int) (22407))))))))) | ((int) ((signed char) ((!(((int) (var_32)) * ((int) (struct_obj_8.member_4_9.member_1_2)))) << ((~((int) ((unsigned short) (121)))) + (152))))); + signed char var_104 = +(-((int) ((signed char) ((unsigned short) (((int) (-127)) > ((int) (-91))))))); + signed char var_105 = ((((-((int) (30661))) * ((int) ((unsigned short) (var_5)))) / ((int) ((signed char) (-((int) (struct_obj_2.member_5_3)))))) / (~(~(-(+((int) ((unsigned short) ((((int) (var_27)) + (((int) (struct_obj_4.member_2_7)) + ((int) (struct_obj_2.member_5_1)))) - (+((int) (22407))))))))))) * ((+((int) ((unsigned short) ((((int) (var_27)) + (((int) (struct_obj_4.member_2_7)) + ((int) (struct_obj_2.member_5_1)))) - (+((int) (22407))))))) * ((+(((int) (var_11)) * ((int) (struct_obj_8.member_4_3)))) * (((int) ((unsigned short) (struct_obj_1.member_5_2))) / (((int) (-95)) * ((int) (var_50)))))); + } + + var_106 = (short) ((signed char) (struct_obj_8.member_4_8)); + unsigned short var_107 = ((((int) ((((int) (struct_obj_4.member_2_3.member_1_3)) % ((int) (43869))) < ((((int) (var_55)) + (2147483647)) >> (((int) (var_3)) - (28))))) / (((int) ((unsigned short) (var_29))) - ((int) ((signed char) (var_26))))) * ((int) ((signed char) ((short) (((int) (-65)) * ((int) (struct_obj_3.member_5_0))))))) != (+(~((int) ((signed char) ((((int) ((short) ((unsigned short) (struct_obj_1.member_5_1)))) / (-(((int) (var_32)) * ((int) (struct_obj_4.member_2_3.member_1_0))))) * ((~(-((int) (struct_obj_1.member_5_0)))) * ((int) (var_27)))))))); + if (32515) + { + var_46 = (unsigned short) (!(((int) ((unsigned short) ((~((int) (var_3))) ^ (((int) (19146)) | ((int) (struct_obj_2.member_5_2)))))) & ((~(((int) (struct_obj_8.member_4_4)) ^ ((int) (var_2)))) & ((((int) (33293)) | ((int) (var_55))) ^ (~((int) (struct_obj_4.member_2_1.member_1_0))))))); + short var_108 = (short) ((((((int) (14)) & ((int) (var_53))) | (((int) (var_53)) & ((int) (var_19)))) | (~(~((int) (var_54))))) ^ (((((int) (-18302)) & ((int) (63))) & ((int) (struct_obj_1.member_5_2))) ^ (~((int) ((unsigned short) (8902)))))); + unsigned short var_109 = (unsigned short) (+((int) ((+((int) ((unsigned short) (61136)))) != (-((int) ((signed char) (var_28))))))); + short var_110 = (signed char) (~(~((int) (struct_obj_4.member_2_5)))); + var_40 = (signed char) ((((~((((int) (31124)) ^ ((int) (32575))) | ((((int) (-25599)) + (2147483647)) << ((((((((int) (43839)) - (43838)) - (0)) - (0)) - (0)) - (0)) - (1))))) + (2147483647)) << ((((~(((int) (56)) | ((int) (42861)))) + (2147483647)) << ((((((~((int) ((unsigned short) (29861)))) + (29886)) - (23)) - (0)) - (0)) - (1))) - (2147440759))) || ((int) ((short) (-(~((int) (((int) (struct_obj_9.member_2_2)) > ((int) (-28602))))))))); + unsigned short var_111 = ((int) ((signed char) (((int) ((((int) (var_14)) << (((int) (5053)) - (5042))) >= (~((int) ((unsigned short) (-(((int) (var_31)) * (!((int) (struct_obj_4.member_2_3.member_1_2)))))))))) & ((int) ((unsigned short) (4610)))))) << (((int) (var_20)) - (49510)); + unsigned short var_112 = (unsigned short) (((((int) ((unsigned short) (var_7))) && (((int) (struct_obj_8.member_4_9.member_1_1)) && ((int) (var_11)))) && ((((int) (struct_obj_7.member_1_1)) || ((int) (var_17))) || (((int) (var_10)) || ((int) (24048))))) % (((int) ((unsigned short) (((int) (12332)) * ((int) (59))))) * (~(-((int) (var_17)))))); + signed char var_113 = ~((((int) ((short) ((signed char) (44957)))) | ((~((int) (15636))) | (((int) (var_59)) ^ ((int) (var_109))))) & ((int) (13))); + short var_114 = ~((((~((int) (var_16))) | (~((int) (var_40)))) & (~(((int) (struct_obj_10.member_1_2)) & ((int) (struct_obj_8.member_4_9.member_1_0))))) ^ ((int) ((short) (((int) ((unsigned short) (struct_obj_8.member_4_2))) & (~((int) (7475))))))); + unsigned short var_115 = (-((int) (28145))) - (((((int) ((unsigned short) (25233))) + ((int) ((signed char) (110)))) - ((((int) (17997)) - ((int) (var_45))) + ((int) ((signed char) (29))))) + (((((int) (26576)) - ((int) (struct_obj_9.member_2_4))) - (((int) (var_47)) + ((int) (118)))) - (+((int) ((signed char) (-101)))))); + } + + } + else + { + unsigned short var_116 = ((((((int) (29480)) * ((int) (47))) * (~((int) (-106)))) * ((((int) (-5906)) * ((int) (var_47))) / (((int) (struct_obj_10.member_1_3)) * ((int) (var_49))))) * ((int) (var_17))) * (!((((int) (var_14)) * (((int) (var_22)) * ((int) (struct_obj_10.member_1_3)))) * ((((int) (9930)) * ((int) (-39))) / (((int) (var_50)) * ((int) (7597)))))); + short var_117 = 23937; + var_37 = (signed char) (((int) ((((int) ((signed char) (((int) (struct_obj_4.member_2_1.member_1_3)) % ((int) (struct_obj_2.member_5_1))))) | ((int) (((int) ((unsigned short) (-10713))) >= (((int) (struct_obj_8.member_4_9.member_1_1)) || ((int) (struct_obj_4.member_2_1.member_1_1)))))) > (((int) ((unsigned short) (((~((((int) (var_15)) ^ ((int) (struct_obj_2.member_5_3))) | (((int) (-117)) & ((int) (struct_obj_4.member_2_0))))) & ((int) (var_9))) | ((int) (struct_obj_4.member_2_1.member_1_0))))) * ((int) (struct_obj_4.member_2_3.member_1_3))))) & ((((~((int) (var_21))) | ((int) ((signed char) (6873)))) | ((((int) (11866)) & ((int) (1866))) & (((int) (120)) | ((int) (51141))))) & ((~(((int) (var_23)) ^ ((int) (var_21)))) ^ (((int) (var_38)) & (~((int) (var_61))))))); + unsigned short var_118 = var_39; + short var_119 = (short) (((((int) ((signed char) (struct_obj_4.member_2_3.member_1_3))) || (!((int) (var_60)))) % ((int) (((int) (var_59)) != (((int) (var_42)) & ((int) (var_5)))))) - ((int) ((unsigned short) (+((int) (41572)))))); + } + + if ((short) ((((int) ((unsigned short) (145))) || (!((int) (struct_obj_8.member_4_8)))) || ((!(!((int) (52600)))) && (!(((int) (struct_obj_1.member_5_1)) || ((int) (-45))))))) + { + if (((int) (struct_obj_7.member_1_1)) || ((int) (var_14))) + { + short var_120 = (((int) (-25025)) * (((int) ((signed char) (((int) (var_41)) || ((int) (-6379))))) * ((int) ((((int) (struct_obj_2.member_5_1)) || ((int) (var_66))) >= ((int) (struct_obj_2.member_5_1)))))) != (((int) ((unsigned short) ((((int) (struct_obj_4.member_2_6)) % ((int) (var_58))) % (~((int) (var_27)))))) && (~((~((int) (14817))) | (((int) (struct_obj_9.member_2_6)) | ((int) (80)))))); + unsigned short var_121 = ~((int) (40954)); + unsigned short var_122 = (short) ((((int) ((signed char) (+((int) (38261))))) * ((int) ((unsigned short) (((int) (struct_obj_1.member_5_3)) * ((int) (var_14)))))) * ((!(-((int) (var_25)))) * ((((int) (var_21)) * ((int) (struct_obj_3.member_5_0))) * (!((int) (struct_obj_8.member_4_6)))))); + var_123 = (unsigned short) (struct_obj_9.member_2_0); + signed char var_124 = ((int) ((+(~(((int) (1985)) * ((int) (104))))) <= ((int) (-17923)))) || ((~((((int) (struct_obj_8.member_4_1.member_3_0)) << (((int) (var_24)) + (4604))) >> (((int) ((signed char) (-29108))) - (70)))) | ((~((int) (46864))) | ((((int) (var_65)) + (2147483647)) >> (((((int) (struct_obj_10.member_1_3)) + (2147483647)) >> (((int) (var_25)) - (111))) - (32745))))); + unsigned short var_125 = ((int) (struct_obj_8.member_4_5)) * (+((+(~((int) (var_21)))) - ((int) ((unsigned short) ((unsigned short) (-12)))))); + short var_126 = ((int) (struct_obj_4.member_2_1.member_1_0)) && ((((!((int) (60288))) || ((int) (96))) && ((((int) (-57)) || ((int) (19530))) || (((int) (17387)) && ((int) (48289))))) || (!((((int) (29335)) && ((int) (-23143))) || (((int) (-16)) && ((int) (9431)))))); + short var_127 = (+((int) (((int) ((short) (((int) (struct_obj_1.member_5_1)) - ((int) (32370))))) < ((int) (60992))))) - ((int) ((((int) ((short) (((int) (var_8)) ^ ((int) (-54))))) & ((~((int) (32))) ^ (((int) (-29031)) | ((int) (126))))) != (((+(((int) (struct_obj_8.member_4_0)) ^ ((int) (struct_obj_5.member_1_0)))) + (2147483647)) >> ((~((int) (18))) || (((int) (struct_obj_4.member_2_2)) && ((int) (-39))))))); + unsigned short var_128 = !((int) ((((int) ((unsigned short) (~((int) (83))))) * ((int) ((((int) (-23)) ^ ((int) (62519))) >= ((int) (((int) (41099)) > ((int) (62255))))))) >= (~((~((int) (81))) * (((int) (-103)) * ((int) (23532))))))); + } + else + { + var_129 = (short) ((unsigned short) (var_20)); + unsigned short var_130 = var_66; + unsigned short var_131 = ((int) ((unsigned short) (((~((int) (-45))) & (~((int) (30782)))) ^ ((((int) (52410)) ^ ((int) (-29797))) ^ (~((int) (23))))))) & ((((int) ((((int) (24037)) % ((int) (struct_obj_8.member_4_4))) <= ((int) ((short) (29870))))) | (((((int) (struct_obj_8.member_4_6)) + (2147483647)) >> (((int) (struct_obj_5.member_1_0)) + (105))) ^ (((int) (var_28)) - ((((+((int) (struct_obj_4.member_2_3.member_1_0))) - (+((int) (17696)))) - ((int) (var_22))) + (((int) ((short) ((unsigned short) (var_27)))) + (((int) (var_23)) + (-((int) (var_1))))))))) || (~((int) ((short) (~((int) (-31180))))))); + short var_132 = (+(((int) (var_58)) * ((((int) (struct_obj_1.member_5_3)) * ((int) (struct_obj_4.member_2_1.member_1_1))) / ((int) ((unsigned short) (struct_obj_8.member_4_1.member_3_1.member_1_2)))))) * ((int) ((signed char) ((!(((int) (var_28)) - ((((+((int) (struct_obj_4.member_2_3.member_1_0))) - (+((int) (17696)))) - ((int) (var_22))) + (((int) ((short) ((unsigned short) (var_27)))) + (((int) (var_23)) + (-((int) (var_1)))))))) * (!(((int) (var_28)) - ((((+((int) (struct_obj_4.member_2_3.member_1_0))) - (+((int) (17696)))) - ((int) (var_22))) + (((int) ((short) ((unsigned short) (var_27)))) + (((int) (var_23)) + (-((int) (var_1))))))))))); + signed char var_133 = ~(~(((((int) (var_31)) & ((int) (-6036))) | (((int) (struct_obj_8.member_4_1.member_3_0)) & ((int) (119)))) & ((int) ((short) (((int) (var_51)) & ((int) (struct_obj_6.member_5_1))))))); + signed char var_134 = ((int) (var_28)) - ((((+((int) (struct_obj_4.member_2_3.member_1_0))) - (+((int) (17696)))) - ((int) (var_22))) + (((int) ((short) ((unsigned short) (var_27)))) + (((int) (var_23)) + (-((int) (var_1)))))); + unsigned short var_135 = (!((!(((int) (41271)) && ((int) (13731)))) || (((int) (25327)) || (!((int) (-8624)))))) && ((!((((int) (6099)) || ((int) (122))) && (((int) (39583)) || ((int) (32873))))) || (!((!((int) (16105))) || (((int) (var_28)) - ((((+((int) (struct_obj_4.member_2_3.member_1_0))) - (+((int) (17696)))) - ((int) (var_22))) + (((int) ((short) ((unsigned short) (var_27)))) + (((int) (var_23)) + (-((int) (var_1)))))))))); + signed char var_136 = (signed char) (((int) (((int) ((((int) (var_35)) % ((int) (struct_obj_6.member_5_1))) <= ((int) ((signed char) (var_20))))) <= (~(((int) (-26722)) ^ ((int) (-5)))))) * ((!(((int) (struct_obj_2.member_5_2)) % ((int) (var_12)))) >> (!(!((int) (10583)))))); + unsigned short var_137 = ~((int) ((signed char) (~(~((int) ((unsigned short) (var_8))))))); + } + + signed char var_138 = ((~((((int) (struct_obj_9.member_2_4)) + ((int) (var_48))) - ((int) (((int) (25852)) > ((int) (32844)))))) || (((int) ((unsigned short) (((int) (12)) < ((int) (35004))))) + ((int) (20954)))) >= ((int) (struct_obj_4.member_2_6)); + if (~(~(((int) (var_9)) ^ (~(((int) (var_56)) & ((int) (-97))))))) + { + unsigned short var_139 = ((int) (struct_obj_4.member_2_3.member_1_1)) < ((((((int) (59174)) ^ ((int) (-69))) & (~((int) (122)))) & ((((int) (24)) & ((int) (61565))) ^ (((int) (54007)) | ((int) (-60))))) & ((~(((int) (-1951)) | ((int) (struct_obj_8.member_4_1.member_3_1.member_1_0)))) & (~(((int) (var_55)) ^ ((int) (54148)))))); + short var_140 = (((int) (struct_obj_3.member_5_1)) && ((int) ((unsigned short) ((((int) (var_18)) || ((int) (struct_obj_8.member_4_1.member_3_1.member_1_0))) > (((int) (23085)) & ((int) (-10998))))))) & (((!(((int) (var_64)) && ((int) (22)))) || ((!((int) (-372))) && (((int) (196)) || ((int) (28127))))) && (!((!((int) (var_28))) || (((int) (-3298)) || ((int) (86)))))); + signed char var_141 = 32; + unsigned short var_142 = (short) (((int) (-91)) || (!(!(((int) (-2370)) || ((int) (-120)))))); + var_143 = (signed char) ((unsigned short) ((~((int) (struct_obj_6.member_5_0))) & ((int) ((signed char) ((short) ((signed char) (struct_obj_4.member_2_6))))))); + short var_144 = 65519; + } + + var_55 = (signed char) (((-((int) ((((int) (struct_obj_10.member_1_3)) - ((int) (struct_obj_8.member_4_9.member_1_1))) < ((((int) (struct_obj_5.member_1_3)) + (2147483647)) >> ((((int) (-2633)) + (2665)) - (21)))))) & (~(((int) (21384)) * (((int) (struct_obj_4.member_2_3.member_1_0)) * ((int) (struct_obj_4.member_2_1.member_1_3)))))) == ((~(~(((int) (var_11)) | ((int) (28869))))) | (((int) (struct_obj_10.member_1_2)) | (~(((int) (struct_obj_7.member_1_2)) & ((int) (var_31))))))); + short var_145 = (((int) (((int) ((unsigned short) (66))) == (~(((int) (-108)) & ((int) (var_50)))))) / (-(+((int) (((int) (var_49)) != ((int) (var_43))))))) == (((int) (var_60)) | (-(-(+((int) (-28574)))))); + short var_146 = (((int) ((signed char) (((int) (((int) (struct_obj_6.member_5_2)) <= ((int) (var_51)))) && ((int) ((unsigned short) (var_23)))))) * ((int) (((int) (struct_obj_1.member_5_2)) == ((((int) (var_66)) & ((int) (37785))) & ((int) ((~((int) (var_15))) != (~((((((int) (struct_obj_4.member_2_7)) + (2147483647)) << ((((int) (var_30)) - (42704)) - (1))) | ((int) (var_18))) << (((int) ((unsigned short) (~((int) (struct_obj_3.member_5_3))))) - (26655)))))))))) % ((int) ((unsigned short) (((+((int) (var_20))) + (((int) (struct_obj_4.member_2_2)) * ((int) (var_52)))) + (+(+((int) (var_58))))))); + if ((signed char) ((((((int) (var_50)) ^ ((int) (58076))) ^ (((int) (struct_obj_2.member_5_1)) << (((int) (struct_obj_8.member_4_0)) - (17338)))) >> ((~(~((int) (var_8)))) - (14640))) << (((int) (((int) (((int) (27168)) < ((int) (var_45)))) < (((int) (41179)) & ((int) (-9862))))) >> (((int) (-56)) + (59))))) + { + unsigned short var_147 = var_7; + unsigned short var_148 = (((int) ((signed char) ((((int) (struct_obj_4.member_2_3.member_1_1)) + ((int) (-42))) - (((int) (struct_obj_8.member_4_9.member_1_2)) + ((int) (var_24)))))) - ((int) ((~((int) (var_15))) != (~((((((int) (struct_obj_4.member_2_7)) + (2147483647)) << ((((int) (var_30)) - (42704)) - (1))) | ((int) (var_18))) << (((int) ((unsigned short) (~((int) (struct_obj_3.member_5_3))))) - (26655))))))) % (((-(+((int) (struct_obj_2.member_5_0)))) >> ((((int) (19611)) << (((int) (7596)) - (7595))) >> (((int) ((short) (struct_obj_8.member_4_1.member_3_1.member_1_2))) + (90)))) % (-((int) (struct_obj_4.member_2_3.member_1_3)))); + signed char var_149 = (signed char) (9177); + signed char var_150 = ~((((((int) (var_32)) >> (((int) (var_63)) - (21651))) >> ((((int) (var_52)) & ((int) (var_28))) - (9212))) << ((((int) ((short) (var_37))) << (((int) (var_59)) >> (((int) (struct_obj_8.member_4_0)) - (17332)))) - (924))) << ((~(~(((int) (struct_obj_1.member_5_1)) & ((int) (var_65))))) - (19726))); + short var_151 = ((int) (((int) ((~(~((int) (var_28)))) >= (((int) ((unsigned short) (45))) % ((int) ((unsigned short) (59243)))))) != ((int) ((unsigned short) (!((int) (2861))))))) && (-(((-((int) (struct_obj_6.member_5_0))) * ((int) (76))) / (~(~((int) (struct_obj_6.member_5_0)))))); + var_152 = (short) ((short) ((!((((int) (-48)) && ((int) (var_29))) && (!((int) (27080))))) | ((int) ((signed char) (+(+((int) (var_47)))))))); + short var_153 = ~(!(((int) ((~((int) (var_15))) != (~((((((int) (struct_obj_4.member_2_7)) + (2147483647)) << ((((int) (var_30)) - (42704)) - (1))) | ((int) (var_18))) << (((int) ((unsigned short) (~((int) (struct_obj_3.member_5_3))))) - (26655)))))) ^ ((int) ((short) (((int) (13313)) >> (((int) (4429)) - (4409))))))); + short var_154 = (signed char) (((int) ((signed char) (((~((int) (38068))) + (2147483647)) >> ((((int) (5010)) << ((((int) (-97)) + (120)) - (9))) - (82083818))))) & (((((int) (var_27)) >> (((int) (var_34)) + (88))) >> ((((int) (var_6)) ^ ((int) (struct_obj_4.member_2_1.member_1_0))) - (40569))) | ((int) (23074)))); + } + + } + + short var_155 = ((~((int) ((signed char) ((short) (struct_obj_4.member_2_3.member_1_2))))) | (~(((((int) (var_8)) | ((int) (struct_obj_1.member_5_0))) + (2147483647)) << ((((int) (var_18)) << (((int) (struct_obj_2.member_5_3)) - (25447))) - (157696))))) > ((int) ((((!((int) (55608))) || (((int) (42069)) && ((int) (struct_obj_4.member_2_0)))) && (!((int) ((signed char) (struct_obj_8.member_4_1.member_3_1.member_1_0))))) == ((((int) (((int) (struct_obj_1.member_5_1)) <= ((int) (var_18)))) & ((int) (((int) (7701)) != ((int) (var_7))))) && ((int) ((((int) (struct_obj_9.member_2_2)) - ((int) (var_1))) <= (((int) (struct_obj_4.member_2_1.member_1_1)) ^ ((int) (struct_obj_10.member_1_3)))))))); + if (((!((((int) (var_1)) || ((int) (struct_obj_8.member_4_1.member_3_1.member_1_2))) || (((int) (struct_obj_8.member_4_6)) || ((int) (var_49))))) && ((!(((int) (var_29)) || ((int) (95)))) && (!((int) ((short) (struct_obj_6.member_5_1)))))) || (!((!(((int) (var_48)) || ((int) (var_31)))) && (((int) ((unsigned short) (struct_obj_8.member_4_5))) && (!((int) (var_25))))))) + { + var_156 = (signed char) (+(((int) (struct_obj_4.member_2_2)) / (~((int) ((unsigned short) (~((int) (struct_obj_8.member_4_6)))))))); + signed char var_157 = (short) (((int) (var_15)) << (((int) ((signed char) (((int) (struct_obj_8.member_4_9.member_1_0)) & ((int) (17017))))) >> ((((((int) (struct_obj_1.member_5_1)) << (((int) (var_39)) - (28162))) & ((int) (struct_obj_1.member_5_2))) - (55360)) - (15)))); + signed char var_158 = ~((int) (struct_obj_9.member_2_7)); + unsigned short var_159 = (((int) (((int) ((unsigned short) (((int) (var_14)) << ((int) (struct_obj_4.member_2_3.member_1_0))))) < (((int) (((int) (struct_obj_8.member_4_9.member_1_2)) > ((int) (5)))) * (((int) (-30137)) * ((int) (49178)))))) && (((int) ((short) (struct_obj_8.member_4_5))) & ((~((int) (var_39))) ^ (((int) (var_48)) & ((int) (struct_obj_1.member_5_0)))))) >> ((int) ((unsigned short) (!(((int) ((signed char) (42511))) & (((int) (struct_obj_8.member_4_2)) >> (((int) (struct_obj_4.member_2_3.member_1_2)) + (83))))))); + short var_160 = ((int) (((int) (30759)) < (~((int) ((short) (((int) (var_34)) ^ ((int) (struct_obj_8.member_4_1.member_3_0)))))))) <= ((-((int) ((((int) (-24352)) && ((int) (struct_obj_8.member_4_9.member_1_0))) < ((int) ((signed char) (struct_obj_3.member_5_2)))))) | (((((int) (struct_obj_8.member_4_6)) && ((int) (struct_obj_9.member_2_1.member_1_0))) ^ (((int) (-3094)) & ((int) (var_1)))) / ((int) ((signed char) (+((int) (var_42))))))); + short var_161 = (short) ((-((int) ((signed char) (((int) (struct_obj_8.member_4_5)) ^ ((int) (var_36)))))) > (((((int) (var_54)) & ((int) (-24453))) | (~((int) (struct_obj_9.member_2_1.member_1_3)))) | ((((int) (struct_obj_8.member_4_7)) | ((int) (var_159))) & (((int) (var_63)) & ((int) (var_13)))))); + if (-((int) ((unsigned short) (!((int) (16141)))))) + { + var_162 = (signed char) ((short) (19938)); + var_38 = (signed char) (((int) ((signed char) ((((int) ((unsigned short) (struct_obj_4.member_2_3.member_1_3))) << ((((int) (var_16)) ^ ((int) (66))) - (7830))) & ((((int) (16)) << (((int) (28592)) - (28568))) ^ (((int) (14689)) ^ ((int) (-24415))))))) & ((int) (struct_obj_4.member_2_3.member_1_2))); + unsigned short var_163 = (signed char) (((~((int) ((unsigned short) (var_50)))) - ((((int) (55181)) >> (((int) (-105)) + (108))) | (((int) (50003)) << ((((int) (var_30)) - (42689)) - (15))))) & ((int) (struct_obj_8.member_4_0))); + unsigned short var_164 = struct_obj_10.member_1_3; + unsigned short var_165 = struct_obj_4.member_2_7; + unsigned short var_166 = ((int) (var_56)) >> ((int) (((~(((int) (var_33)) ^ ((int) (2184)))) & ((int) ((((int) (var_30)) ^ ((int) (13945))) != ((((int) (-25)) + (2147483647)) >> (((int) (struct_obj_1.member_5_1)) - (32568)))))) <= ((int) (struct_obj_4.member_2_7)))); + } + else + { + short var_167 = (short) (~(((((int) (-125)) & ((int) (var_55))) | (((int) (30445)) | ((int) (var_14)))) | ((((int) (struct_obj_4.member_2_6)) | ((int) (struct_obj_3.member_5_1))) | (((int) (struct_obj_4.member_2_1.member_1_3)) ^ ((int) (42952)))))); + unsigned short var_168 = (((int) ((unsigned short) ((~((int) (36216))) | ((int) (-29579))))) >> ((~((((int) (10544)) & ((int) (11868))) << ((((int) (26935)) | ((int) (struct_obj_8.member_4_1.member_3_0))) - (27566)))) + (5251073))) << ((((((~((int) (struct_obj_10.member_1_2))) ^ (((int) (77)) << (((int) (var_66)) - (65517)))) << ((((((int) (-78)) + (2147483647)) << (((int) (var_60)) - (21585))) << ((((int) ((signed char) (struct_obj_4.member_2_4))) + (15)) - (10))) - (2147483563))) | (~((int) ((signed char) (((int) (73)) >> (((int) (6327)) - (6305))))))) + (18)) - (13)); + short var_169 = ((((int) (var_23)) & ((((int) (var_54)) + (2147483647)) << (((((((int) (-6568)) + (2147483647)) >> (((int) (-25044)) + (25060))) - (32766)) - (0)) - (1)))) >> (((int) ((signed char) ((signed char) (~((int) (32011)))))) + (12))) && (((!(((int) (var_11)) || ((int) (struct_obj_9.member_2_6)))) || ((!((int) (struct_obj_9.member_2_0))) || (((int) (struct_obj_4.member_2_3.member_1_2)) || ((int) (struct_obj_2.member_5_2))))) || (!((int) ((short) (((int) (-29488)) && ((int) (struct_obj_4.member_2_3.member_1_2))))))); + signed char var_170 = (unsigned short) (var_26); + signed char var_171 = !(((int) ((signed char) ((((int) (struct_obj_6.member_5_3)) - ((int) (var_65))) - (((int) (struct_obj_8.member_4_9.member_1_0)) << (((int) (struct_obj_4.member_2_2)) - (30774)))))) || (((int) (var_158)) * ((int) ((short) (((int) (var_157)) && ((int) (var_27))))))); + unsigned short var_172 = (~((int) ((signed char) ((((int) (13)) % ((int) (struct_obj_8.member_4_7))) > ((int) ((unsigned short) (-112))))))) >= (~((((int) (struct_obj_8.member_4_3)) ^ (((int) (var_155)) << (((int) (struct_obj_7.member_1_2)) + (146)))) >> ((~(((int) (var_46)) >> (((int) (struct_obj_2.member_5_2)) - (41436)))) + (80)))); + short var_173 = -(-(-(-((int) (struct_obj_1.member_5_2))))); + } + + if (((int) (((int) (((int) (struct_obj_2.member_5_2)) >= ((((int) (var_45)) | ((int) (15962))) | (((int) (struct_obj_9.member_2_6)) ^ ((int) (64811)))))) <= ((int) ((unsigned short) (~(((int) (var_39)) || ((int) (struct_obj_4.member_2_7)))))))) >> ((int) ((signed char) (((int) ((~((int) (struct_obj_8.member_4_8))) <= (((int) (struct_obj_2.member_5_1)) * ((int) (var_43))))) == (-(+((int) (22055)))))))) + { + signed char var_174 = ((int) (var_47)) ^ (((((int) ((signed char) ((((int) (struct_obj_4.member_2_3.member_1_0)) >> (((int) (var_17)) - (32638))) % (((int) (var_3)) && ((int) (var_3)))))) * (((int) ((short) (!((int) (struct_obj_2.member_5_3))))) * ((((int) (var_12)) * ((int) (76))) / (((int) (struct_obj_2.member_5_3)) * ((int) (var_35)))))) + (~((int) (var_33)))) & ((int) (struct_obj_4.member_2_6))); + short var_175 = (~((((int) ((signed char) ((((int) (struct_obj_4.member_2_3.member_1_0)) >> (((int) (var_17)) - (32638))) % (((int) (var_3)) && ((int) (var_3)))))) * (((int) ((short) (!((int) (struct_obj_2.member_5_3))))) * ((((int) (var_12)) * ((int) (76))) / (((int) (struct_obj_2.member_5_3)) * ((int) (var_35)))))) + (~((int) (var_33))))) <= (((((int) (var_31)) & ((int) ((unsigned short) (43682)))) & ((int) ((short) (((int) (var_9)) | ((int) (var_18)))))) ^ (~(((int) (struct_obj_4.member_2_1.member_1_3)) ^ (~((int) (52103)))))); + short var_176 = (((((((int) (-75)) ^ ((int) (31369))) + (2147483647)) >> (((int) ((unsigned short) (-29))) - (65506))) & ((int) (2146))) << (((((int) (var_2)) * ((int) (struct_obj_3.member_5_3))) / ((((int) ((signed char) ((((int) (struct_obj_4.member_2_3.member_1_0)) >> (((int) (var_17)) - (32638))) % (((int) (var_3)) && ((int) (var_3)))))) * (((int) ((short) (!((int) (struct_obj_2.member_5_3))))) * ((((int) (var_12)) * ((int) (76))) / (((int) (struct_obj_2.member_5_3)) * ((int) (var_35)))))) + (~((int) (var_33))))) * ((((int) (var_24)) * ((int) (var_47))) / (((int) (var_5)) * ((int) (struct_obj_8.member_4_1.member_3_1.member_1_0)))))) * ((int) ((unsigned short) ((((int) (27537)) / (((int) (-15573)) * ((int) (struct_obj_9.member_2_0)))) * (!(((int) (12)) * ((int) (struct_obj_8.member_4_0))))))); + unsigned short var_177 = ((((((int) (40535)) * ((int) (var_30))) * (!((int) (struct_obj_6.member_5_1)))) * ((((int) (var_50)) / ((int) (58121))) * (((int) (54878)) * ((int) (struct_obj_8.member_4_0))))) * ((((int) ((short) (53))) * (((int) (32)) * ((int) (var_175)))) * (((int) ((signed char) (19151))) * (~((int) (16207)))))) * ((int) (var_16)); + var_178 = (short) ((~(~((int) ((signed char) (~((int) (4771))))))) >> ((((!(((int) (64904)) && ((int) (-98)))) * ((int) ((signed char) (~((int) (34931)))))) - (((int) (struct_obj_7.member_1_1)) & (((int) (((int) (struct_obj_9.member_2_0)) < ((int) (40)))) || (((int) (struct_obj_6.member_5_0)) % ((int) (struct_obj_5.member_1_1)))))) + (32))); + unsigned short var_179 = ~((int) ((unsigned short) (((((int) (var_174)) | ((int) (struct_obj_2.member_5_0))) | (((int) (struct_obj_8.member_4_1.member_3_1.member_1_2)) ^ ((int) (struct_obj_8.member_4_7)))) ^ (~(~((int) (struct_obj_8.member_4_6))))))); + signed char var_180 = ((int) (((int) ((!((int) ((unsigned short) (47545)))) <= (~(~((int) (2410)))))) >= ((int) (((((int) (1)) ^ ((int) (13528))) | ((int) ((signed char) (var_65)))) == ((+((int) (var_175))) & ((int) ((unsigned short) (14219)))))))) <= (((int) ((signed char) (((int) (((int) (var_6)) <= ((int) (var_23)))) <= ((int) ((signed char) (var_58)))))) + (((((int) (struct_obj_4.member_2_1.member_1_1)) ^ ((int) (var_4))) ^ ((int) (struct_obj_9.member_2_1.member_1_3))) && ((((int) (-3265)) & ((int) (12497))) * ((int) (((int) (struct_obj_9.member_2_0)) == ((int) (struct_obj_9.member_2_1.member_1_1))))))); + signed char var_181 = (+((((int) ((signed char) ((((int) (struct_obj_4.member_2_3.member_1_0)) >> (((int) (var_17)) - (32638))) % (((int) (var_3)) && ((int) (var_3)))))) * (((int) ((short) (!((int) (struct_obj_2.member_5_3))))) * ((((int) (var_12)) * ((int) (76))) / (((int) (struct_obj_2.member_5_3)) * ((int) (var_35)))))) + (~((int) (var_33))))) + ((((~((int) (7403))) & (((int) (struct_obj_4.member_2_0)) ^ ((int) (var_58)))) & (((((int) ((signed char) ((((int) (struct_obj_4.member_2_3.member_1_0)) >> (((int) (var_17)) - (32638))) % (((int) (var_3)) && ((int) (var_3)))))) * (((int) ((short) (!((int) (struct_obj_2.member_5_3))))) * ((((int) (var_12)) * ((int) (76))) / (((int) (struct_obj_2.member_5_3)) * ((int) (var_35)))))) + (~((int) (var_33)))) & (((int) (struct_obj_8.member_4_5)) & ((int) (struct_obj_3.member_5_3))))) * (~((int) ((+((int) (struct_obj_8.member_4_7))) <= (((int) (-24292)) - ((int) (38418))))))); + var_46 = (unsigned short) (~(!((int) ((signed char) (((int) (((int) (55161)) < ((int) (var_36)))) + (+((int) (var_55)))))))); + } + else + { + signed char var_182 = (~(~((~((int) (struct_obj_1.member_5_1))) & (((int) (13831)) | ((int) (struct_obj_4.member_2_1.member_1_0)))))) | (~(((((int) (97)) | ((int) (struct_obj_4.member_2_3.member_1_3))) & ((int) ((signed char) (var_4)))) & ((((int) (119)) ^ ((int) (-1))) | ((int) (struct_obj_9.member_2_0))))); + signed char var_183 = ~(((!(!((int) (var_20)))) | ((int) ((short) (((int) (struct_obj_6.member_5_1)) >> (((int) (12242)) - (12212)))))) || (~((((int) (var_32)) & ((int) (var_63))) ^ (((int) (29262)) & ((int) (var_3)))))); + short var_184 = ((((int) ((signed char) ((unsigned short) (43)))) & (~(((int) (struct_obj_4.member_2_3.member_1_3)) ^ ((int) (52))))) ^ (~((int) (struct_obj_10.member_1_2)))) << (((int) (struct_obj_4.member_2_7)) + (9528)); + unsigned short var_185 = ~((int) (struct_obj_3.member_5_1)); + short var_186 = ((int) ((short) (-((((int) (struct_obj_8.member_4_5)) - ((int) (var_65))) - (((int) (28254)) - ((int) (struct_obj_6.member_5_3))))))) * ((+((-((int) (struct_obj_8.member_4_7))) + ((int) ((signed char) (struct_obj_4.member_2_3.member_1_3))))) + ((int) ((short) (struct_obj_4.member_2_1.member_1_3)))); + short var_187 = struct_obj_5.member_1_3; + } + + if (~((+(!((int) ((signed char) (struct_obj_9.member_2_1.member_1_0))))) * ((int) ((short) ((short) (~((int) (var_19)))))))) + { + unsigned short var_188 = (~(-((int) (((int) ((unsigned short) (-23))) <= (((int) (struct_obj_4.member_2_1.member_1_0)) || ((int) (24497))))))) | ((+(~(((int) (var_43)) * ((int) (struct_obj_4.member_2_1.member_1_1))))) + ((int) (struct_obj_8.member_4_3))); + unsigned short var_189 = (unsigned short) ((~((~((int) (97))) & (+((int) ((unsigned short) (+(((int) (((int) (var_21)) < ((int) (var_19)))) / (+((int) (-23249)))))))))) | (((int) ((short) (-15924))) ^ ((((int) (31)) ^ ((int) (var_7))) ^ (~((int) (struct_obj_6.member_5_1)))))); + signed char var_190 = ((((((int) (14001)) | ((int) (73))) & ((int) ((unsigned short) (12149)))) & ((((int) (-78)) | ((int) (39))) | (+((int) ((unsigned short) (+(((int) (((int) (var_21)) < ((int) (var_19)))) / (+((int) (-23249)))))))))) | ((int) (((int) (24297)) <= (+((int) ((unsigned short) (+(((int) (((int) (var_21)) < ((int) (var_19)))) / (+((int) (-23249))))))))))) != ((int) ((unsigned short) (18898))); + signed char var_191 = (~(((~((int) (-11939))) & (~((int) (var_26)))) >> (((((int) (struct_obj_4.member_2_6)) >> (((int) (10058)) - (10057))) & (((int) (struct_obj_9.member_2_1.member_1_3)) << (((int) (var_10)) - (21745)))) - (10531)))) | ((((~((int) (var_1))) | (((int) (struct_obj_6.member_5_2)) << (((int) (-15680)) + (15686)))) | (((int) ((signed char) (60447))) | (((int) (-11899)) & ((int) (var_15))))) & ((((int) (var_43)) >> ((~((int) (struct_obj_4.member_2_0))) + (7623))) ^ ((~((int) (struct_obj_7.member_1_0))) | (((int) (30163)) & ((int) (var_21)))))); + signed char var_192 = ((!((int) ((unsigned short) (((int) (28)) && ((int) (var_40)))))) || (!((int) ((signed char) (((int) (var_48)) || ((int) (struct_obj_9.member_2_0))))))) ^ ((int) (((int) (((int) (-113)) <= ((((int) (12)) || ((int) (52))) ^ (((int) (2031)) * ((int) (8257)))))) == ((int) ((signed char) ((((int) (struct_obj_3.member_5_1)) & ((int) (var_11))) & (((int) (var_2)) ^ ((int) (struct_obj_8.member_4_4)))))))); + signed char var_193 = 18614; + } + + short var_194 = ~((((int) (47259)) ^ (+((int) ((unsigned short) (+(((int) (((int) (var_21)) < ((int) (var_19)))) / (+((int) (-23249))))))))) & ((((int) (57390)) << ((((int) (25700)) << ((int) (14))) - (421068788))) << (((int) (var_27)) - (15318)))); + } + + signed char var_195 = ((~(~(~((int) (struct_obj_8.member_4_9.member_1_0))))) ^ ((~(((int) (struct_obj_8.member_4_3)) ^ ((int) (8)))) & (((int) (-23)) | ((int) (5564))))) ^ (+(~((int) ((-((int) (118))) != ((int) (((int) (-117)) != ((int) (34786)))))))); + if ((((~((((int) (struct_obj_8.member_4_2)) | ((int) (struct_obj_9.member_2_2))) & ((int) ((unsigned short) (var_11))))) + (2147483647)) >> (((!((int) (struct_obj_7.member_1_1))) && (((int) (-27411)) && ((int) (var_57)))) * (((int) (((int) (var_53)) > ((int) (struct_obj_8.member_4_0)))) * (-((int) (var_11)))))) & (((((int) (120)) & ((int) ((unsigned short) (struct_obj_8.member_4_1.member_3_0)))) & ((int) ((signed char) (-((int) (2523)))))) && (!((int) ((short) (((int) (var_1)) - ((int) (struct_obj_2.member_5_3)))))))) + { + if ((~((int) ((short) ((((int) (-7247)) ^ ((int) (96))) & (((int) (115)) | ((int) (42355))))))) & ((((int) (63543)) & ((int) ((unsigned short) (((int) (17803)) ^ ((int) (11828)))))) | (((int) (-29)) | ((int) ((short) (~((int) (10016)))))))) + { + short var_196 = var_1; + unsigned short var_197 = ((((int) ((unsigned short) (((int) (struct_obj_9.member_2_1.member_1_0)) ^ ((int) (struct_obj_7.member_1_1))))) | (((int) (struct_obj_9.member_2_1.member_1_0)) | (((int) (-51)) ^ ((int) (struct_obj_8.member_4_1.member_3_1.member_1_0))))) & (((((int) (110)) & ((int) (-28957))) | ((int) (struct_obj_9.member_2_1.member_1_0))) & ((~((int) (var_21))) & ((int) ((signed char) (-15740)))))) & ((~((~((int) (struct_obj_8.member_4_9.member_1_1))) & (((int) (var_38)) | ((int) (-4512))))) & (((int) ((signed char) (26344))) ^ (((int) (23010)) | ((int) (21555))))); + short var_198 = ((int) (((int) ((short) (-((int) (21555))))) <= ((int) (((int) ((((int) (59115)) || ((int) (73))) <= ((int) ((short) (var_1))))) <= (~(((int) (struct_obj_7.member_1_1)) * ((int) (var_15)))))))) <= ((int) ((((((int) (struct_obj_4.member_2_7)) || ((int) (var_42))) & ((int) (21555))) + ((int) ((unsigned short) (21555)))) <= ((int) (((int) ((unsigned short) (-((int) (var_57))))) != ((int) ((signed char) (~((int) (struct_obj_5.member_1_3))))))))); + var_39 = (unsigned short) (+((int) (21555))); + short var_199 = ((int) (((int) (struct_obj_6.member_5_3)) > (((((int) (55447)) - ((int) (121))) - (((int) (124)) + ((int) (23562)))) + ((int) (67))))) == ((int) (21555)); + var_46 = (unsigned short) (-((int) (var_196))); + short var_200 = (-((int) (struct_obj_3.member_5_0))) - (~((int) (var_55))); + unsigned short var_201 = ((int) ((((((int) (var_65)) && ((int) (var_7))) && ((int) ((unsigned short) (29456)))) && ((((int) (-11627)) || ((int) (var_62))) || ((int) ((unsigned short) (struct_obj_8.member_4_4))))) <= ((int) ((((int) (((int) (39895)) == ((int) (struct_obj_4.member_2_0)))) - ((int) (((int) (18541)) <= ((int) (var_197))))) == ((((int) (-6609)) | ((int) (-118))) * (((int) (var_195)) >> (((int) (50558)) - (50551)))))))) < (((int) ((short) (((int) ((unsigned short) (var_5))) || (((int) (struct_obj_2.member_5_1)) && ((int) (var_43)))))) || (((!((int) (51194))) && (!((int) (41084)))) && (((int) ((signed char) (struct_obj_4.member_2_0))) || (!((int) (var_42)))))); + signed char var_202 = ((~((int) ((short) (((int) (-6444)) | ((int) (17)))))) | ((int) ((signed char) ((((int) (var_49)) ^ ((int) (120))) | (((int) (struct_obj_2.member_5_2)) | ((int) (-10264))))))) ^ (((((int) ((short) (struct_obj_1.member_5_2))) & (((int) (var_34)) & ((int) (64379)))) | ((((int) (-20555)) & ((int) (struct_obj_8.member_4_3))) & (((int) (struct_obj_8.member_4_4)) & ((int) (20891))))) | (((((int) (struct_obj_2.member_5_3)) & ((int) (30905))) | ((int) (21555))) ^ (~(((int) (struct_obj_4.member_2_3.member_1_3)) & ((int) (var_52)))))); + short var_203 = (!((((int) ((signed char) (~((!(((int) (27437)) && ((int) (-123)))) / (~((int) (((int) (var_31)) <= ((int) (var_26))))))))) * (((int) (23332)) * ((int) (var_23)))) / ((int) ((short) (((int) (43615)) * ((int) (var_56))))))) != (-((int) ((unsigned short) (((int) ((short) (struct_obj_9.member_2_6))) & (((int) (var_36)) ^ ((int) (var_45))))))); + } + + var_49 = (signed char) (~(~(~(((~((int) (var_66))) + (2147483647)) << (((((int) (-6282)) | ((int) (var_4))) + (4231)) - (5)))))); + if (((int) ((signed char) (~((((int) (var_54)) ^ ((int) (struct_obj_8.member_4_0))) ^ (~((int) (var_54))))))) & ((int) ((short) (((~((int) (20559))) | (~((int) (struct_obj_8.member_4_1.member_3_1.member_1_0)))) & ((int) (-27)))))) + { + signed char var_204 = ((~((int) (var_54))) ^ (((((int) (var_32)) & ((int) (var_11))) | (((int) (-113)) ^ ((int) (var_28)))) ^ (~(((int) (struct_obj_8.member_4_1.member_3_0)) & ((int) (var_51)))))) & ((int) ((unsigned short) ((unsigned short) (var_44)))); + short var_205 = (signed char) ((+((int) ((short) (((int) (-7851)) + ((int) (struct_obj_5.member_1_1)))))) + ((int) ((short) ((((int) (5103)) - ((int) (var_22))) - (((int) (var_7)) - ((int) (struct_obj_10.member_1_0))))))); + short var_206 = (~((int) ((unsigned short) (~((int) ((short) (43004))))))) > ((int) ((signed char) (((int) ((short) (((int) (-4829)) | ((int) (struct_obj_9.member_2_5))))) >= ((int) (((int) (struct_obj_10.member_1_3)) <= ((int) ((unsigned short) (-29121)))))))); + unsigned short var_207 = ~((int) (var_49)); + short var_208 = (short) (((int) ((unsigned short) (~((int) ((short) (((int) (struct_obj_3.member_5_2)) ^ ((int) (var_18)))))))) ^ ((((((int) (20589)) >> (((int) (-20937)) + (20947))) ^ ((int) (47282))) | (~(~((int) (23))))) & (((((int) (struct_obj_3.member_5_1)) << (((int) (var_7)) - (42))) << (((int) (var_33)) >> (((int) (struct_obj_2.member_5_1)) - (25738)))) << (((int) ((short) (var_34))) + (89))))); + } + + if (((int) (struct_obj_9.member_2_6)) << ((int) (((int) ((!((int) ((unsigned short) (var_43)))) <= ((int) (var_7)))) > (((int) (72)) ^ ((((int) (var_28)) & ((int) (24924))) | (~((int) (struct_obj_7.member_1_0)))))))) + { + unsigned short var_209 = ~((((~((int) (18314))) | ((int) ((unsigned short) (var_14)))) & ((((int) (struct_obj_9.member_2_2)) & ((int) (struct_obj_8.member_4_9.member_1_0))) ^ (~((int) (-31087))))) ^ (((int) (80)) | ((((int) (struct_obj_8.member_4_9.member_1_0)) & ((int) (struct_obj_4.member_2_5))) ^ (((int) (47697)) | ((int) (53)))))); + signed char var_210 = var_38; + unsigned short var_211 = ((int) ((unsigned short) ((~((int) (-10493))) < (!(-((int) (var_3))))))) <= (!(~((~((int) (var_36))) | (((int) (struct_obj_3.member_5_2)) | ((int) (struct_obj_4.member_2_3.member_1_3)))))); + signed char var_212 = ((((int) ((signed char) (((int) (16621)) ^ ((int) (17647))))) | ((((int) (var_7)) | ((int) (-95))) | (((int) (var_64)) & ((int) (struct_obj_1.member_5_0))))) | (((int) (struct_obj_8.member_4_4)) ^ ((~((int) (-19306))) | (((int) (-8522)) ^ ((int) (7284)))))) ^ ((~(((int) ((short) (struct_obj_10.member_1_3))) ^ (((int) (struct_obj_5.member_1_3)) ^ ((int) (struct_obj_9.member_2_0))))) ^ (((int) (var_5)) | ((~((int) (35989))) | (((int) (125)) ^ ((int) (struct_obj_4.member_2_1.member_1_1)))))); + signed char var_213 = (((int) (var_41)) & (((((int) (struct_obj_1.member_5_3)) ^ ((int) (6820))) ^ (~((int) (var_41)))) ^ (~(((int) (16070)) ^ ((int) (struct_obj_1.member_5_0)))))) ^ (~(((((int) (var_56)) << ((((int) (var_54)) + (24931)) - (19))) | (((int) (9)) & ((int) (46955)))) << (((~((int) ((signed char) (var_12)))) + (63)) - (19)))); + short var_214 = ((!((((int) (var_41)) || ((int) (var_4))) || (!((int) (var_1))))) && (!(((int) (struct_obj_10.member_1_3)) || (((int) (21126)) || ((int) (var_210)))))) && ((((int) ((unsigned short) (var_42))) || ((int) ((short) (struct_obj_4.member_2_1.member_1_1)))) && ((int) (struct_obj_5.member_1_1))); + unsigned short var_215 = (((int) (struct_obj_7.member_1_2)) + (2147483647)) >> ((~(((int) (((int) (-30700)) != ((int) (struct_obj_10.member_1_2)))) - ((int) (var_58)))) || (~(((int) ((short) (4835))) ^ ((int) (struct_obj_9.member_2_1.member_1_0))))); + } + + signed char var_216 = +((int) ((signed char) ((short) ((((int) (29926)) - ((int) (struct_obj_4.member_2_1.member_1_1))) + (-((int) (var_9))))))); + var_217 = (signed char) (~(~(-((~((int) (11848))) & (((int) (-110)) & ((int) (struct_obj_3.member_5_1))))))); + signed char var_218 = (~((~(~((int) (struct_obj_8.member_4_0)))) << ((((int) (5903)) ^ ((int) (var_10))) >> ((((int) (var_4)) & ((int) (-13690))) - (2545))))) > (-(-(~(~((int) (struct_obj_9.member_2_1.member_1_1)))))); + unsigned short var_219 = (~((int) ((short) (((int) (((int) (var_195)) <= ((int) (struct_obj_1.member_5_1)))) | ((int) (-70)))))) <= ((int) ((unsigned short) ((unsigned short) ((((int) (-126)) & ((int) (struct_obj_8.member_4_1.member_3_1.member_1_0))) ^ (((int) (struct_obj_9.member_2_0)) ^ ((int) (var_19))))))); + signed char var_220 = (unsigned short) ((((int) (-23)) ^ (((int) ((unsigned short) (var_42))) | ((int) (-27960)))) & (((~((int) (62588))) ^ (((int) (struct_obj_4.member_2_2)) | ((int) (struct_obj_4.member_2_3.member_1_3)))) & (~((int) (struct_obj_10.member_1_2))))); + if (((((((int) (3)) && ((int) (var_54))) && (((int) (struct_obj_10.member_1_3)) || ((int) (struct_obj_8.member_4_8)))) || (!(((int) (struct_obj_8.member_4_6)) && ((int) (struct_obj_3.member_5_2))))) && (((int) ((signed char) (!((int) (struct_obj_4.member_2_1.member_1_0))))) || ((int) (32382)))) <= (((~(((~((~(((int) (32286)) ^ ((int) (99)))) ^ (~(((int) (6)) ^ ((int) (-93)))))) & ((int) ((short) (((((int) (43755)) ^ ((int) (struct_obj_1.member_5_0))) & (((int) (var_29)) ^ ((int) (124)))) ^ ((int) ((signed char) (~((int) (12159))))))))) ^ ((int) ((signed char) (-21650))))) + (2147483647)) >> ((int) (((int) (((int) (((int) (struct_obj_8.member_4_4)) <= ((int) (-601)))) != (!((int) (struct_obj_8.member_4_0))))) > ((int) (((~((~(((int) (32286)) ^ ((int) (99)))) ^ (~(((int) (6)) ^ ((int) (-93)))))) & ((int) ((short) (((((int) (43755)) ^ ((int) (struct_obj_1.member_5_0))) & (((int) (var_29)) ^ ((int) (124)))) ^ ((int) ((signed char) (~((int) (12159))))))))) < (!((int) (9829))))))))) + { + short var_221 = ((((-((int) (var_17))) - (((int) (var_30)) + ((int) (struct_obj_4.member_2_2)))) / (((int) (struct_obj_8.member_4_3)) - (((int) (var_5)) * ((int) (var_3))))) * (((~((~(((int) (32286)) ^ ((int) (99)))) ^ (~(((int) (6)) ^ ((int) (-93)))))) & ((int) ((short) (((((int) (43755)) ^ ((int) (struct_obj_1.member_5_0))) & (((int) (var_29)) ^ ((int) (124)))) ^ ((int) ((signed char) (~((int) (12159))))))))) + (-(((int) (14421)) + ((int) (23698)))))) + ((((((int) (struct_obj_9.member_2_2)) + ((int) (25482))) - (((int) (-46)) - ((int) (struct_obj_5.member_1_1)))) / ((-((int) (var_216))) + (+((int) (64628))))) - ((((int) ((signed char) (-7))) - (+((int) (var_54)))) - ((int) (struct_obj_8.member_4_1.member_3_1.member_1_1)))); + var_65 = (short) ((~((~(((int) (32286)) ^ ((int) (99)))) ^ (~(((int) (6)) ^ ((int) (-93)))))) & ((int) ((short) (((((int) (43755)) ^ ((int) (struct_obj_1.member_5_0))) & (((int) (var_29)) ^ ((int) (124)))) ^ ((int) ((signed char) (~((int) (12159))))))))); + unsigned short var_222 = ((int) ((unsigned short) (((int) (var_63)) ^ (~((~((~(((int) (32286)) ^ ((int) (99)))) ^ (~(((int) (6)) ^ ((int) (-93)))))) & ((int) ((short) (((((int) (43755)) ^ ((int) (struct_obj_1.member_5_0))) & (((int) (var_29)) ^ ((int) (124)))) ^ ((int) ((signed char) (~((int) (12159))))))))))))) & ((((int) ((signed char) (~(((int) (var_12)) & ((int) (109)))))) + (2147483647)) << (((((int) ((unsigned short) (var_27))) - (15320)) - (0)) - (1))); + unsigned short var_223 = ((((int) (struct_obj_4.member_2_3.member_1_2)) + (2147483647)) >> (((~(~((int) (var_18)))) << (((((int) (68)) | ((int) (struct_obj_4.member_2_1.member_1_3))) & (((int) (struct_obj_1.member_5_2)) ^ ((int) (-16242)))) + (58826))) - (5046248))) || (((int) ((unsigned short) ((-((int) (9390))) / (((int) (31664)) * ((int) (-70)))))) << ((((~((~(((int) (32286)) ^ ((int) (99)))) ^ (~(((int) (6)) ^ ((int) (-93)))))) & ((int) ((short) (((((int) (43755)) ^ ((int) (struct_obj_1.member_5_0))) & (((int) (var_29)) ^ ((int) (124)))) ^ ((int) ((signed char) (~((int) (12159))))))))) | ((int) ((unsigned short) ((~((~(((int) (32286)) ^ ((int) (99)))) ^ (~(((int) (6)) ^ ((int) (-93)))))) & ((int) ((short) (((((int) (43755)) ^ ((int) (struct_obj_1.member_5_0))) & (((int) (var_29)) ^ ((int) (124)))) ^ ((int) ((signed char) (~((int) (12159)))))))))))) - (15329))); + unsigned short var_224 = ((int) (((int) (-11433)) > ((int) (-13855)))) || (~(((int) ((short) (((int) (struct_obj_6.member_5_3)) && ((int) (struct_obj_4.member_2_3.member_1_3))))) ^ (~((int) (((int) (32)) <= ((int) (11233))))))); + signed char var_225 = (((~(((int) (-26)) | ((int) (-117)))) & ((((int) (111)) & ((int) (22599))) ^ (((int) (10345)) << ((((int) (-66)) + (88)) - (12))))) >> (((int) (-3619)) + (3621))) >> ((~((int) (struct_obj_6.member_5_1))) + (44653)); + unsigned short var_226 = ((int) ((((~((int) (struct_obj_9.member_2_5))) | ((int) (22048))) & ((((int) (struct_obj_4.member_2_3.member_1_1)) & ((int) (var_4))) | (((int) (struct_obj_3.member_5_1)) | ((int) (27648))))) <= ((int) (((int) ((signed char) ((((int) (struct_obj_7.member_1_0)) + (2147483647)) >> (((int) (var_15)) - (38610))))) != ((int) ((signed char) ((short) (struct_obj_1.member_5_3)))))))) > (((int) (var_44)) >> ((int) ((unsigned short) (((int) (struct_obj_6.member_5_2)) >> ((~((int) (-18530))) - (18509)))))); + signed char var_227 = ((int) (18755)) * ((int) (((int) ((unsigned short) ((~((~(((int) (32286)) ^ ((int) (99)))) ^ (~(((int) (6)) ^ ((int) (-93)))))) & ((int) ((short) (((((int) (43755)) ^ ((int) (struct_obj_1.member_5_0))) & (((int) (var_29)) ^ ((int) (124)))) ^ ((int) ((signed char) (~((int) (12159))))))))))) > ((~(~((int) (37454)))) & ((~((int) (-7983))) | (((int) (-31547)) & ((int) (22310))))))); + signed char var_228 = !(~((int) ((((int) (((int) (struct_obj_8.member_4_1.member_3_1.member_1_0)) != ((int) (struct_obj_8.member_4_1.member_3_1.member_1_2)))) || (-((int) (42)))) >= ((int) ((short) (((int) (var_195)) ^ ((int) (struct_obj_8.member_4_4)))))))); + unsigned short var_229 = (-(~(~(((int) (var_32)) & ((int) (-23)))))) && ((int) ((signed char) ((~((~(((int) (32286)) ^ ((int) (99)))) ^ (~(((int) (6)) ^ ((int) (-93)))))) & ((int) ((short) (((((int) (43755)) ^ ((int) (struct_obj_1.member_5_0))) & (((int) (var_29)) ^ ((int) (124)))) ^ ((int) ((signed char) (~((int) (12159))))))))))); + } + else + { + short var_230 = (short) (struct_obj_4.member_2_5); + unsigned short var_231 = ((int) ((signed char) (((int) ((short) (((int) (struct_obj_9.member_2_1.member_1_3)) << (((int) (struct_obj_8.member_4_5)) + (1331))))) & ((~((~(((int) (32286)) ^ ((int) (99)))) ^ (~(((int) (6)) ^ ((int) (-93)))))) & ((int) ((short) (((((int) (43755)) ^ ((int) (struct_obj_1.member_5_0))) & (((int) (var_29)) ^ ((int) (124)))) ^ ((int) ((signed char) (~((int) (12159)))))))))))) % ((int) ((short) ((unsigned short) (~((~((~(((int) (32286)) ^ ((int) (99)))) ^ (~(((int) (6)) ^ ((int) (-93)))))) & ((int) ((short) (((((int) (43755)) ^ ((int) (struct_obj_1.member_5_0))) & (((int) (var_29)) ^ ((int) (124)))) ^ ((int) ((signed char) (~((int) (12159))))))))))))); + short var_232 = (unsigned short) ((((int) (49)) || ((!((int) (7))) || ((int) ((short) (struct_obj_3.member_5_1))))) && (!((int) (52603)))); + signed char var_233 = (~((~(((int) (32286)) ^ ((int) (99)))) ^ (~(((int) (6)) ^ ((int) (-93)))))) & ((int) ((short) (((((int) (43755)) ^ ((int) (struct_obj_1.member_5_0))) & (((int) (var_29)) ^ ((int) (124)))) ^ ((int) ((signed char) (~((int) (12159)))))))); + var_234 = (short) ((((int) ((signed char) ((unsigned short) (~((int) (var_50)))))) & (~((int) ((short) (((int) (6)) | ((int) (var_40))))))) <= (((-((((int) (struct_obj_8.member_4_4)) & ((int) (struct_obj_9.member_2_4))) | ((int) (61009)))) + (2147483647)) >> (!(((~((~(((int) (32286)) ^ ((int) (99)))) ^ (~(((int) (6)) ^ ((int) (-93)))))) & ((int) ((short) (((((int) (43755)) ^ ((int) (struct_obj_1.member_5_0))) & (((int) (var_29)) ^ ((int) (124)))) ^ ((int) ((signed char) (~((int) (12159))))))))) * (((int) (struct_obj_1.member_5_3)) * ((int) (-53))))))); + signed char var_235 = !(!((int) ((signed char) ((!((int) (var_23))) && (((int) (var_2)) && ((int) (-40))))))); + short var_236 = ((~((int) (((int) (-9)) != ((int) (((int) (-6685)) <= ((int) (-51))))))) || ((((int) (((int) (var_9)) >= ((int) (struct_obj_9.member_2_1.member_1_0)))) || (((int) (var_233)) - ((int) (var_28)))) && ((int) (15198)))) || (((-(((int) (8864)) - ((int) (struct_obj_4.member_2_3.member_1_3)))) - ((((int) (-81)) - ((int) (struct_obj_4.member_2_0))) - ((int) ((signed char) (67))))) && (-((int) (((int) ((unsigned short) (29545))) < (((int) (var_54)) / ((int) (23))))))); + } + + } + + } + + if ((((int) (-30504)) ^ (((int) (struct_obj_9.member_2_0)) & ((~((int) (16009))) & (((int) (59488)) ^ ((int) (-25101)))))) & ((int) ((unsigned short) ((signed char) ((((int) (-70)) ^ ((int) ((-127 - 1)))) ^ (~((int) (-18198)))))))) + { + short var_237 = ((int) ((unsigned short) (~(~(((int) (32724)) & ((int) (-57))))))) > (~((int) (((int) (var_15)) <= (((int) ((unsigned short) (var_65))) + (((int) (var_16)) && ((int) (var_37))))))); + short var_238 = ((int) (-1594)) <= (((int) (var_37)) + ((int) (var_237))); + signed char var_239 = (((~(((((int) (var_65)) ^ ((int) (56889))) + (2147483647)) >> ((((int) (var_37)) << (((int) (struct_obj_9.member_2_4)) - (13527))) - (15204328)))) + (2147483647)) << (((int) ((unsigned short) ((((int) (-29413)) | ((int) (struct_obj_1.member_5_3))) | (~((int) (var_61)))))) - (36863))) | ((((((int) (var_22)) & ((int) (-10107))) << ((((int) (-7266)) | ((int) (struct_obj_10.member_1_0))) + (7232))) << (((int) ((signed char) (var_28))) & (((int) (var_238)) >> (((int) (struct_obj_9.member_2_5)) - (26951))))) << (((((int) ((short) (((int) (31750)) ^ ((int) (struct_obj_8.member_4_8))))) + (2147483647)) << ((((((~((int) ((signed char) (struct_obj_4.member_2_5)))) + (139)) - (25)) - (0)) - (0)) - (1))) - (2147463623))); + var_49 = (signed char) ((~((~((int) (struct_obj_1.member_5_0))) | ((~((int) (var_38))) ^ (~((int) (var_18)))))) * (~(((int) ((short) ((((int) (-74)) + (2147483647)) << (((((int) (-7673)) + (7685)) - (11)) - (1))))) | ((int) ((short) ((unsigned short) (struct_obj_8.member_4_1.member_3_1.member_1_1))))))); + if (var_30) + { + if ((-(((((int) (struct_obj_10.member_1_0)) * ((int) (4200))) * (~((int) (-32)))) * (~(-((int) (var_40)))))) >= ((int) (((~(((int) (7439)) & ((int) (var_33)))) && ((int) (((int) (var_27)) != (((int) (struct_obj_9.member_2_6)) << (((int) (43587)) - (43579)))))) < ((int) ((!((int) ((signed char) (struct_obj_8.member_4_5)))) >= ((~((int) (9170))) & (((int) (18966)) & ((int) (var_36))))))))) + { + var_240 = (signed char) ((+(((((int) (39678)) + ((int) (-20537))) + (((int) (-20330)) - ((int) (-35)))) * ((+((int) (-32053))) + ((int) (-29363))))) >> ((((int) (var_8)) || ((!((int) (22))) || (((int) (53763)) || ((int) (11024))))) && (((((int) (struct_obj_9.member_2_2)) && ((int) (var_20))) || ((int) (62563))) || (((int) ((short) (-28548))) && ((int) (struct_obj_9.member_2_5)))))); + var_241 = (unsigned short) (-((int) ((((((int) (90)) / ((int) (var_14))) >> ((-((int) (-3575))) - (3547))) | ((int) ((((int) (var_10)) * ((int) (61679))) > (((int) (var_3)) % ((int) (-39)))))) < (((int) (((int) ((signed char) (21447))) <= ((int) (((int) (struct_obj_8.member_4_1.member_3_1.member_1_2)) > ((int) (struct_obj_9.member_2_2)))))) / (~(((int) (5083)) | ((int) (var_62)))))))); + short var_242 = ((int) (((int) ((signed char) ((((int) (-123)) && ((int) (20950))) < ((int) (((int) (26747)) < ((int) (-37))))))) >= ((int) ((((int) (58514)) && ((int) (-20862))) != (!(!((int) (struct_obj_10.member_1_3)))))))) % (((((int) ((signed char) (var_55))) * (~((int) (var_40)))) % (~(((int) (struct_obj_5.member_1_3)) + ((int) (19833))))) ^ (~((((int) (6964)) || ((int) (struct_obj_5.member_1_0))) & ((int) ((short) (var_62)))))); + unsigned short var_243 = +((((int) ((unsigned short) (+((int) (struct_obj_4.member_2_7))))) / ((-((int) (struct_obj_9.member_2_1.member_1_0))) * (+((int) (struct_obj_9.member_2_1.member_1_1))))) * (+((int) ((short) (+((int) (23962))))))); + unsigned short var_244 = ((int) ((((int) ((unsigned short) (~((int) (var_54))))) ^ (~(((int) (var_38)) ^ ((int) (struct_obj_8.member_4_6))))) >= ((int) ((short) (((int) (25080)) >> ((((int) (var_21)) * ((int) (struct_obj_8.member_4_8))) + (3109978))))))) < ((int) (struct_obj_9.member_2_4)); + struct_obj_9.member_2_2 = (unsigned short) (((int) (((int) (((int) (var_33)) >= ((~((int) (27357))) | ((int) (58514))))) < ((((((int) (-24728)) + (2147483647)) >> ((((int) (-12450)) + (12482)) - (29))) >> ((((int) (57)) * ((int) (14104))) - (803923))) / ((int) (((int) (58514)) != ((int) (((int) (struct_obj_4.member_2_0)) != ((int) (struct_obj_8.member_4_5))))))))) != ((int) ((unsigned short) ((((int) ((signed char) (((int) (48)) | ((int) (var_59))))) + (2147483647)) << (((~(((int) (struct_obj_4.member_2_7)) & ((int) (var_239)))) + (102)) - (26)))))); + signed char var_245 = ((int) ((signed char) (-22439))) << ((((int) ((signed char) (((int) (var_22)) >> (((int) (var_33)) - (40281))))) / ((int) (25526))) || ((((int) ((short) (var_60))) / (((int) (-53)) * ((int) (24333)))) * ((((int) (struct_obj_8.member_4_1.member_3_1.member_1_1)) * ((int) (struct_obj_6.member_5_0))) / (((int) (7947)) * ((int) (struct_obj_9.member_2_4)))))); + var_57 = (signed char) ((short) (~((((int) ((unsigned short) (struct_obj_8.member_4_1.member_3_1.member_1_0))) | (((int) (struct_obj_6.member_5_2)) | ((int) (-127)))) ^ ((~((int) (-18008))) & (((int) (var_7)) & ((int) (var_1))))))); + signed char var_246 = (((!(((int) (-31124)) && ((int) (42538)))) / ((((int) (-26184)) & ((int) (-6497))) | (((int) (1782)) & ((int) (111))))) ^ (-((int) ((unsigned short) (((int) (10177)) > ((int) (8727))))))) - (-((int) (((int) (-72)) < (((int) ((unsigned short) (63))) ^ (((int) (-13275)) & ((int) (-32755))))))); + signed char var_247 = ((int) (((int) ((signed char) ((~((int) (var_44))) || ((int) ((signed char) (59533)))))) < ((int) (((-((int) (var_11))) & (((int) (-951)) ^ ((int) (struct_obj_8.member_4_9.member_1_1)))) != ((((int) (37950)) >> (((int) (19587)) - (19587))) && ((int) (((int) (24323)) == ((int) (var_41))))))))) >> ((int) (((!((int) (struct_obj_9.member_2_4))) && ((!((int) (-25737))) && (((int) (var_59)) || ((int) (struct_obj_9.member_2_1.member_1_0))))) == ((int) (((((int) (var_40)) | ((int) (46921))) | ((int) (struct_obj_4.member_2_3.member_1_2))) <= ((int) ((!((int) (struct_obj_8.member_4_1.member_3_1.member_1_2))) <= (((int) (119)) & ((int) (-31))))))))); + } + + if ((-((int) ((short) ((signed char) ((short) (var_20)))))) <= (((int) (((((int) (struct_obj_8.member_4_1.member_3_0)) ^ ((int) (struct_obj_9.member_2_1.member_1_0))) << ((((int) (58)) ^ ((int) (var_45))) + (128))) == ((int) (var_31)))) ^ ((int) (((((int) (struct_obj_1.member_5_1)) | ((int) (37360))) | (~((int) (var_5)))) <= ((int) (8)))))) + { + unsigned short var_248 = (unsigned short) (((((int) (struct_obj_4.member_2_3.member_1_2)) * ((int) ((short) (26360)))) / (((int) ((signed char) (8410))) * (((int) (957)) * ((int) (16064))))) * (-((-((int) (1))) * ((int) ((unsigned short) (-15383)))))); + short var_249 = (signed char) (((((int) ((short) ((((int) (-15020)) + (2147483647)) << (((int) (var_12)) - (29985))))) + (2147483647)) << ((((((int) (var_25)) | ((int) (struct_obj_7.member_1_1))) ^ (((int) (var_7)) ^ ((int) (struct_obj_2.member_5_3)))) + (31452)) - (3))) << (((int) (106)) - (106))); + short var_250 = (signed char) ((~((((int) (var_249)) * ((int) (26))) * ((int) ((signed char) (var_44))))) * (~((int) (-6112)))); + short var_251 = ~((int) ((short) (((((int) (var_60)) * ((int) (var_14))) * ((int) ((signed char) (var_35)))) * (-(((int) (struct_obj_8.member_4_3)) / ((int) (var_44))))))); + short var_252 = (~((int) ((((int) ((unsigned short) (68))) ^ (~((int) (28040)))) >= ((int) ((signed char) ((signed char) (struct_obj_8.member_4_0))))))) * ((!((((int) (var_8)) || ((int) (struct_obj_9.member_2_1.member_1_3))) && ((int) ((short) (var_59))))) && (!((((int) (21061)) && ((int) (-24998))) && (((int) (var_51)) || ((int) (var_9)))))); + short var_253 = ((int) ((signed char) (var_48))) <= ((int) (struct_obj_8.member_4_6)); + } + else + { + unsigned short var_254 = ((((((int) (102)) * ((int) (15365))) / (-((int) (-17680)))) * (-(((int) (-27940)) * ((int) (-40))))) / (((int) ((short) (-63))) * (~(((int) (struct_obj_8.member_4_1.member_3_1.member_1_2)) * ((int) (var_58)))))) & ((int) ((((int) (var_22)) + (((int) (31276)) & (~((int) (-102))))) < ((int) (((int) (struct_obj_4.member_2_6)) > ((int) ((short) (((int) (var_58)) && ((int) (struct_obj_8.member_4_1.member_3_1.member_1_1))))))))); + signed char var_255 = +((int) (var_52)); + short var_256 = var_7; + short var_257 = (((int) ((signed char) ((short) ((unsigned short) (struct_obj_9.member_2_5))))) >> ((int) ((((int) (35251)) / ((int) ((unsigned short) (var_255)))) <= ((int) ((unsigned short) (((int) (struct_obj_9.member_2_6)) > ((int) (var_42)))))))) < ((int) (var_52)); + struct_obj_9.member_2_6 = (unsigned short) (((((int) ((short) (((int) (struct_obj_4.member_2_7)) - ((int) (13943))))) + (-(-((int) (-16676))))) + (((int) (-38)) - ((-((int) (struct_obj_9.member_2_1.member_1_1))) + (-((int) (69)))))) ^ ((int) ((signed char) ((~(((int) (-28)) ^ ((int) (var_254)))) | ((int) ((unsigned short) (((int) (-28119)) ^ ((int) (-71))))))))); + unsigned short var_258 = (~((!((int) ((signed char) (11992)))) || ((((int) (15514)) && ((int) (-73))) || (((int) (26696)) && ((int) (-5402)))))) > ((((int) ((short) ((unsigned short) ((signed char) (var_63))))) + (2147483647)) << ((((((int) ((short) (~(~((int) (-81)))))) + (103)) - (21)) - (0)) - (1))); + signed char var_259 = (short) ((((((int) (struct_obj_8.member_4_9.member_1_0)) * ((int) (var_16))) - ((int) (var_7))) + (+(((int) (struct_obj_4.member_2_7)) - ((int) (struct_obj_5.member_1_3))))) * ((int) (15489))); + var_260 = (signed char) ((unsigned short) (((int) (((((int) (var_58)) >> (((int) (struct_obj_4.member_2_2)) - (30767))) >> ((((int) (var_16)) << ((int) (var_254))) - (7881))) > ((int) (-17)))) / (((int) (((int) ((unsigned short) (22400))) != (((int) (struct_obj_8.member_4_4)) & ((int) (-7838))))) ^ ((int) ((signed char) (~((int) (var_255)))))))); + } + + if ((signed char) ((short) (((((int) (-10196)) ^ ((int) (var_39))) ^ ((int) ((signed char) (19637)))) & ((int) ((unsigned short) (((int) (33)) ^ ((int) (var_14)))))))) + { + signed char var_261 = ((int) ((signed char) (~((int) ((short) (((int) (9625)) ^ ((int) (var_66)))))))) && (((int) (((~((int) (struct_obj_4.member_2_3.member_1_3))) ^ (((int) (var_14)) | ((int) (var_64)))) <= ((int) ((unsigned short) (-((int) (41740))))))) | ((int) (struct_obj_2.member_5_2))); + unsigned short var_262 = struct_obj_8.member_4_6; + short var_263 = struct_obj_8.member_4_9.member_1_2; + signed char var_264 = struct_obj_6.member_5_2; + signed char var_265 = (unsigned short) (~(-(-((int) (((int) (47121)) > ((int) (30366))))))); + unsigned short var_266 = -((int) ((signed char) (((((int) (-9)) * ((int) (struct_obj_6.member_5_1))) / (((int) (var_61)) * ((int) (var_11)))) * ((int) ((signed char) ((short) (48373))))))); + short var_267 = (((int) (var_46)) & (~((~((int) (struct_obj_8.member_4_3))) | ((int) ((unsigned short) (29846)))))) / (((int) ((short) (((int) ((unsigned short) (var_51))) || (((int) (struct_obj_8.member_4_4)) && ((int) (var_62)))))) && (((int) ((signed char) ((signed char) (-32)))) && ((((int) (var_8)) || ((int) (struct_obj_4.member_2_3.member_1_0))) && ((int) (-103))))); + var_268 = (signed char) (((int) (var_21)) - ((-((((int) (struct_obj_8.member_4_9.member_1_1)) - ((int) (var_14))) + (-((int) (var_17))))) + ((int) (struct_obj_9.member_2_5)))); + unsigned short var_269 = (~((int) ((~((int) ((unsigned short) (~((~((int) (var_27))) & (((int) (var_8)) & ((int) (-26607)))))))) != (+(!((int) (31000))))))) * (((int) (((int) (256)) >= ((int) (9376)))) % (((((int) (6933)) ^ ((int) (43243))) & (((int) (21486)) >> (((int) (-17065)) + (17068)))) << ((((int) ((short) (100))) & ((int) ((signed char) (-13)))) - (95)))); + signed char var_270 = (short) (((int) (((((int) (35227)) && ((int) (var_61))) && (!((int) (14283)))) > ((int) ((((int) (15621)) ^ ((int) (24148))) <= (((int) (struct_obj_8.member_4_9.member_1_2)) || ((int) (11653))))))) < (-((int) ((short) (((int) (struct_obj_5.member_1_3)) | ((int) (-10))))))); + } + else + { + unsigned short var_271 = (~((int) ((unsigned short) ((((int) (var_17)) & ((int) (var_4))) ^ (((int) (13016)) & ((int) (struct_obj_2.member_5_0))))))) & ((!(~(!((int) (var_17))))) / ((((int) ((signed char) (var_35))) ^ (~((int) (struct_obj_4.member_2_3.member_1_1)))) & ((~((int) (var_12))) | ((((int) (-29314)) + (2147483647)) << ((((int) (62)) - (61)) - (1)))))); + short var_272 = ((int) ((unsigned short) (((~((int) (84))) | (~((int) (110)))) & (~(((int) (115)) | ((int) (-76))))))) - ((int) (var_23)); + signed char var_273 = (signed char) ((((((int) (-16844)) | ((int) (17775))) ^ (((int) (7963)) | ((int) (12142)))) | ((~((int) (15627))) ^ (((int) (26739)) ^ ((int) (-125))))) && (((int) (((int) (((int) (var_24)) <= ((-((int) (var_16))) * ((int) ((short) (var_34)))))) < ((int) (struct_obj_3.member_5_3)))) | ((int) (((int) ((signed char) (~(((int) (var_4)) + ((int) (25973)))))) <= ((int) (-123)))))); + struct_obj_8.member_4_1.member_3_1.member_1_0 = (signed char) (~((int) ((unsigned short) (+((int) ((short) ((short) (var_62)))))))); + signed char var_274 = (-(((int) ((~((int) (var_15))) <= ((int) ((signed char) (var_271))))) % (~(~((int) (var_28)))))) * ((((int) (((int) (((int) (var_24)) <= ((-((int) (var_16))) * ((int) ((short) (var_34)))))) < ((int) (struct_obj_3.member_5_3)))) | ((int) (((int) ((signed char) (~(((int) (var_4)) + ((int) (25973)))))) <= ((int) (-123))))) ^ ((~(((int) (-19317)) & ((int) (65)))) & (!((int) (((int) (8677)) <= ((int) (12375))))))); + short var_275 = ((~(((int) (((((int) (var_65)) + (2147483647)) >> (((int) (-16890)) + (16891))) != (~((int) (17071))))) % ((int) ((unsigned short) (~((int) (var_38))))))) + (2147483647)) >> (((int) ((unsigned short) (-(((int) (struct_obj_9.member_2_1.member_1_3)) * ((int) (struct_obj_9.member_2_2)))))) && ((~(((int) (struct_obj_8.member_4_9.member_1_0)) * ((int) (var_46)))) & ((int) (struct_obj_4.member_2_0)))); + signed char var_276 = (((((int) (((int) (((int) (var_24)) <= ((-((int) (var_16))) * ((int) ((short) (var_34)))))) < ((int) (struct_obj_3.member_5_3)))) | ((int) (((int) ((signed char) (~(((int) (var_4)) + ((int) (25973)))))) <= ((int) (-123))))) || (-(~((int) (51098))))) % (((((int) (struct_obj_4.member_2_7)) & ((int) (-112))) & ((int) ((short) (25098)))) ^ ((~((int) (-101))) | (((int) (var_28)) & ((int) (-7003)))))) * ((int) ((short) (((int) ((-((int) (27204))) != (-((int) (63928))))) || ((((int) (-43)) * ((int) (-26382))) / (((int) (83)) * ((int) (14127))))))); + short var_277 = (~((int) ((short) (((int) (((int) (((int) (var_24)) <= ((-((int) (var_16))) * ((int) ((short) (var_34)))))) < ((int) (struct_obj_3.member_5_3)))) | ((int) (((int) ((signed char) (~(((int) (var_4)) + ((int) (25973)))))) <= ((int) (-123)))))))) || (~((int) (var_56))); + signed char var_278 = (~((int) ((signed char) ((((int) (var_56)) ^ ((int) (var_64))) ^ (((int) (struct_obj_1.member_5_2)) & ((int) (struct_obj_8.member_4_7))))))) >= (((int) (((int) (((int) (var_24)) <= ((-((int) (var_16))) * ((int) ((short) (var_34)))))) < ((int) (struct_obj_3.member_5_3)))) | ((int) (((int) ((signed char) (~(((int) (var_4)) + ((int) (25973)))))) <= ((int) (-123))))); + } + + short var_279 = (unsigned short) (((+((int) (var_1))) + ((int) ((signed char) (~((int) (struct_obj_8.member_4_1.member_3_1.member_1_0)))))) / (((int) (struct_obj_9.member_2_5)) && (~((int) ((signed char) (struct_obj_7.member_1_1)))))); + if (~(~((int) ((unsigned short) (~(((int) (43)) >> (((int) (39844)) - (39841)))))))) + { + short var_280 = (-(-(!((int) (16816))))) > ((((((int) (-20572)) | ((int) (struct_obj_8.member_4_0))) & (((int) (struct_obj_9.member_2_1.member_1_3)) | ((int) (30439)))) & ((((int) (-98)) ^ ((int) (-27720))) | (((int) (struct_obj_2.member_5_2)) & ((int) (7077))))) << (((int) (var_28)) - (13388))); + signed char var_281 = (short) ((signed char) (!(!(((int) (17428)) || ((int) (27105)))))); + unsigned short var_282 = (((-(((int) (56239)) | ((int) (4)))) * ((int) (((int) (((int) (23297)) <= ((int) (-220)))) > (((int) (-17097)) * ((int) (-121)))))) || ((int) (((int) (-14340)) != ((int) (((int) (20335)) < (((int) (59459)) && ((int) (-107)))))))) - (((((int) (((~(-((int) (217)))) >> (((int) (-24993)) + (25001))) <= (!((int) ((~((int) (23529))) < (((int) (105)) + ((int) (-6170)))))))) >> ((((int) (-54)) ^ ((int) ((signed char) ((unsigned short) (((int) (-3615)) ^ ((int) (struct_obj_4.member_2_1.member_1_0))))))) - (115))) & ((int) ((unsigned short) (((int) (-87)) & ((int) (-83)))))) && ((int) (((int) (-2)) != (+(((int) (17715)) & ((int) (22))))))); + unsigned short var_283 = ((~(~((int) ((short) (40109))))) | ((int) (57193))) ^ (((~((int) ((signed char) (var_239)))) ^ ((((int) (1415)) & ((int) (13531))) | (((int) (struct_obj_3.member_5_2)) | ((int) (-7807))))) & (((~((int) (23824))) ^ (~((int) (-50)))) & ((int) (-23004)))); + var_284 = (short) (!((int) ((short) ((((int) (53609)) ^ ((int) (((int) (var_29)) != ((int) (var_26))))) >= ((((int) (var_48)) / ((int) (11584))) | (((int) (-96)) ^ ((int) (23703)))))))); + struct_obj_8.member_4_5 = (short) ((short) (((~(((int) ((unsigned short) ((~(((int) (((~(-((int) (217)))) >> (((int) (-24993)) + (25001))) <= (!((int) ((~((int) (23529))) < (((int) (105)) + ((int) (-6170)))))))) >> ((((int) (-54)) ^ ((int) ((signed char) ((unsigned short) (((int) (-3615)) ^ ((int) (struct_obj_4.member_2_1.member_1_0))))))) - (115)))) ^ ((int) ((short) (((int) ((signed char) (18462))) | (((int) (var_30)) & ((int) (var_5))))))))) & ((int) (-23)))) + (2147483647)) << (((((int) (struct_obj_9.member_2_1.member_1_3)) | (((int) (52011)) | ((int) (29618)))) >> (((((int) (-17)) ^ ((int) (struct_obj_8.member_4_6))) | (((int) (struct_obj_2.member_5_2)) & ((int) (46991)))) - (46995))) - (4091)))); + } + + unsigned short var_285 = (signed char) (~(((int) ((signed char) (((int) (48619)) * ((int) (struct_obj_9.member_2_2))))) * (((int) (((~(-((int) (217)))) >> (((int) (-24993)) + (25001))) <= (!((int) ((~((int) (23529))) < (((int) (105)) + ((int) (-6170)))))))) >> ((((int) (-54)) ^ ((int) ((signed char) ((unsigned short) (((int) (-3615)) ^ ((int) (struct_obj_4.member_2_1.member_1_0))))))) - (115))))); + } + else + { + struct_obj_8.member_4_0 = (unsigned short) (!(-(!((((int) (58592)) & ((int) (var_17))) ^ (((int) (32236)) ^ ((int) (struct_obj_8.member_4_5))))))); + if (-((int) (21770))) + { + unsigned short var_286 = (~((int) ((signed char) ((((int) (7)) & ((int) (struct_obj_4.member_2_4))) ^ ((int) ((signed char) (var_64))))))) <= (((~((int) (35976))) * ((((int) (struct_obj_2.member_5_1)) * ((int) (16694))) / (((int) (var_39)) * ((int) (struct_obj_2.member_5_1))))) * (((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172))))))); + unsigned short var_287 = var_237; + signed char var_288 = (((~(((int) (10329)) | ((int) (-70)))) << (((int) ((short) (((int) (struct_obj_8.member_4_3)) >> (((int) (var_41)) - (48528))))) - (431))) & ((((int) ((signed char) (((int) (21261)) | ((int) (41469))))) + (2147483647)) << (((((((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172)))))) + (24)) - (14)) - (0)) - (1)))) ^ ((((((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172)))))) + (2147483647)) << (((((int) ((signed char) (~((int) (18910))))) - (32)) - (0)) - (1))) ^ (((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172))))))); + signed char var_289 = ((int) (((int) ((unsigned short) ((((int) (struct_obj_8.member_4_1.member_3_1.member_1_2)) ^ ((int) (var_238))) & (((int) (struct_obj_9.member_2_1.member_1_0)) & ((int) (-14985)))))) < (+(+((int) (struct_obj_4.member_2_6)))))) == (-((int) (((~((int) (var_26))) - ((int) ((short) (struct_obj_8.member_4_7)))) != ((((int) (var_52)) >> (((int) (var_9)) - (13476))) % ((int) (((int) (var_32)) > ((int) (struct_obj_9.member_2_6)))))))); + short var_290 = ~((int) (var_46)); + short var_291 = ((-(-(((int) (4132)) * ((int) (var_6))))) * (!(((int) (var_5)) / (((int) (struct_obj_4.member_2_5)) * ((int) (struct_obj_10.member_1_3)))))) / (((-(((int) (11642)) * ((int) (var_28)))) / ((((int) (var_30)) * ((int) (struct_obj_1.member_5_1))) / ((int) (108)))) * (+(-(((int) (36557)) * ((int) (-91)))))); + short var_292 = ((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172))))); + short var_293 = (((int) ((short) ((~((int) (43459))) & ((((int) (var_292)) + (2147483647)) >> (((int) (44780)) - (44767)))))) && ((int) ((!(((int) (var_44)) || ((int) (-117)))) < ((int) (14679))))) ^ (-((int) (11578))); + } + + if (~((int) ((unsigned short) ((unsigned short) (((int) ((signed char) (var_17))) & (((int) (struct_obj_8.member_4_9.member_1_0)) & ((int) (struct_obj_9.member_2_6)))))))) + { + short var_294 = (((((~((int) (47532))) + (2147483647)) >> (((int) ((short) (140))) - (114))) ^ (~((int) (10977)))) & (((int) ((signed char) (((int) (var_16)) & ((int) (var_58))))) | ((int) (-29488)))) && ((int) ((unsigned short) ((((int) ((short) (((int) (struct_obj_7.member_1_2)) | ((int) (31723))))) + (2147483647)) << (((int) (var_49)) >> (~((int) (var_61))))))); + signed char var_295 = (unsigned short) (var_58); + short var_296 = ((int) (((((int) (45)) ^ (((int) (-12922)) & ((int) (struct_obj_8.member_4_6)))) - (-(((int) (var_46)) % ((int) (var_66))))) > ((((int) ((unsigned short) (var_64))) || (((int) (struct_obj_4.member_2_3.member_1_3)) || ((int) (var_10)))) || (((int) (struct_obj_4.member_2_1.member_1_0)) && (((int) (9298)) || ((int) (var_43))))))) <= ((((int) ((signed char) (((int) (-1967)) * ((int) (var_32))))) / (-(((int) (var_1)) * ((int) (struct_obj_4.member_2_1.member_1_3))))) >> ((((((int) (struct_obj_8.member_4_1.member_3_1.member_1_0)) * ((int) (-27550))) / (((int) (var_31)) - ((int) (var_34)))) - ((((int) (23777)) * ((int) (-12271))) - ((int) (var_32)))) - (291814241))); + var_297 = (unsigned short) ((~(((int) ((signed char) ((signed char) (-27)))) & ((((int) (-12274)) ^ ((int) (50858))) | (((int) (-24967)) | ((int) (-117)))))) >> ((((int) (29155)) << (((((int) ((signed char) (32757))) + (2147483647)) >> ((~((int) (14434))) + (14457))) - (509))) >> ((~((int) (-118))) - (98)))); + short var_298 = -((int) ((~((((int) (var_63)) - ((int) (21024))) & (((int) (var_53)) || ((int) (var_21))))) != ((int) (struct_obj_2.member_5_1)))); + var_65 = (short) (var_42); + short var_299 = ((int) ((signed char) ((!(((int) (9107)) | ((int) (36489)))) != ((((int) ((((int) (var_6)) | (~((int) (var_15)))) > (((int) (-91)) ^ ((int) (var_8))))) && ((((int) (-53)) & (((int) (struct_obj_3.member_5_1)) * ((int) (struct_obj_3.member_5_1)))) * ((int) ((((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172)))))) > (!((int) (62742))))))) * ((int) (((int) ((unsigned short) (-2983))) <= (((int) ((short) (((int) (44)) | ((int) (var_28))))) % ((((int) (22182)) & ((int) (77))) ^ (((int) (struct_obj_3.member_5_3)) ^ ((int) (var_5))))))))))) * ((((int) ((((int) (var_6)) | (~((int) (var_15)))) > (((int) (-91)) ^ ((int) (var_8))))) && ((((int) (-53)) & (((int) (struct_obj_3.member_5_1)) * ((int) (struct_obj_3.member_5_1)))) * ((int) ((((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172)))))) > (!((int) (62742))))))) * ((int) (((int) ((unsigned short) (-2983))) <= (((int) ((short) (((int) (44)) | ((int) (var_28))))) % ((((int) (22182)) & ((int) (77))) ^ (((int) (struct_obj_3.member_5_3)) ^ ((int) (var_5)))))))); + unsigned short var_300 = ~(((int) ((short) ((~((int) (-2669))) ^ (~((int) (var_29)))))) | (((((int) (var_16)) | ((int) (struct_obj_8.member_4_5))) ^ (((int) (var_57)) & ((int) (var_33)))) | (~((int) (struct_obj_6.member_5_2))))); + } + else + { + short var_301 = (!((((int) (struct_obj_8.member_4_5)) || (!((int) (13152)))) && ((((int) (struct_obj_2.member_5_3)) && ((int) (var_20))) || (((int) (32258)) || ((int) (var_49)))))) || (!((!((int) ((signed char) (var_24)))) || (!(((int) (var_32)) && ((int) (var_23)))))); + signed char var_302 = ~((((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172)))))) + ((+((int) ((unsigned short) (-6620)))) + (+((int) ((signed char) (struct_obj_4.member_2_1.member_1_0)))))); + short var_303 = ((int) (((int) ((~(((int) (26)) | ((int) (38463)))) != ((int) ((short) (((int) (24326)) && ((int) (-59))))))) <= ((((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172)))))) / (-(((int) (7532)) || ((int) (19696))))))) & ((int) ((signed char) (~(~(((int) (57632)) << (((int) (-7168)) + (7176))))))); + signed char var_304 = (unsigned short) ((unsigned short) ((((-((int) (54))) + (2147483647)) >> (((int) ((short) (-9386))) + (9392))) & ((int) (((int) ((short) (struct_obj_7.member_1_0))) <= (((int) (-25666)) & ((int) (var_27))))))); + short var_305 = (((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172)))))) * (-(-(((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172)))))))); + short var_306 = ~((((~((((int) (var_302)) + (2147483647)) >> (((int) (var_61)) + (30)))) + (2147483647)) >> ((((int) (var_2)) << ((((int) ((short) (struct_obj_6.member_5_2))) + (19600)) - (29))) - (142254))) << (((((~((int) (29941))) | (~((int) (-12126)))) + (2147483647)) >> (((((int) (62210)) | ((int) (48372))) >> ((((int) (57460)) ^ ((int) (-31908))) + (40156))) - (4074))) - (1016))); + signed char var_307 = ~(((~((int) ((signed char) (-12247)))) | ((int) ((unsigned short) (~((int) (13491)))))) & ((int) ((short) ((((int) (var_54)) | ((int) (27838))) | (((((int) ((short) ((signed char) (((int) (var_33)) | ((int) (struct_obj_4.member_2_3.member_1_2)))))) + (2147483647)) >> (((~((int) (var_10))) | (~((int) (var_21)))) & (((((int) (-42)) + (2147483647)) >> ((((int) (var_32)) - (46768)) - (9))) >> ((~((int) (var_21))) - (48))))) / ((-(((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172))))))) >> ((int) ((signed char) (((int) (struct_obj_4.member_2_3.member_1_1)) && (((int) (99)) || ((int) (var_9)))))))))))); + short var_308 = struct_obj_4.member_2_1.member_1_3; + signed char var_309 = (unsigned short) (((int) ((signed char) ((+((int) (-43))) - ((int) ((unsigned short) (21945)))))) + ((int) ((signed char) ((((int) (var_41)) - ((int) (77))) + (((((int) ((short) ((signed char) (((int) (var_33)) | ((int) (struct_obj_4.member_2_3.member_1_2)))))) + (2147483647)) >> (((~((int) (var_10))) | (~((int) (var_21)))) & (((((int) (-42)) + (2147483647)) >> ((((int) (var_32)) - (46768)) - (9))) >> ((~((int) (var_21))) - (48))))) / ((-(((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172))))))) >> ((int) ((signed char) (((int) (struct_obj_4.member_2_3.member_1_1)) && (((int) (99)) || ((int) (var_9)))))))))))); + } + + if ((~(((~((int) (var_12))) & (((int) (struct_obj_6.member_5_0)) & ((int) (var_239)))) << (((~((int) (-74))) ^ (~((int) (114)))) + (75)))) && ((int) ((((((int) (13630)) ^ ((int) (19614))) >> (((int) (-34)) + (44))) | (((((int) (-65)) + (2147483647)) << (((int) (38398)) - (38398))) & (((int) (28940)) ^ ((int) (14947))))) > ((int) (((int) ((signed char) (((int) (var_48)) * ((int) (1346))))) != ((int) (var_239))))))) + { + signed char var_310 = ((((int) (struct_obj_10.member_1_2)) | ((~((int) (-28776))) & (~((int) (struct_obj_9.member_2_4))))) & ((~(((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172))))))) & ((((int) (-84)) ^ ((int) (20424))) ^ ((int) ((unsigned short) (-14767)))))) ^ (((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172)))))); + unsigned short var_311 = (unsigned short) (var_28); + unsigned short var_312 = ((-((int) ((unsigned short) (54857)))) * ((int) (((~((int) (struct_obj_3.member_5_3))) & (((int) (var_7)) || ((int) (struct_obj_4.member_2_1.member_1_0)))) < (-((int) (var_1)))))) * (~(((int) (-38)) ^ ((((int) (0)) & ((int) (-104))) & (((int) (-110)) & ((int) (-92)))))); + signed char var_313 = (unsigned short) (~((int) ((short) ((~((int) (struct_obj_9.member_2_1.member_1_3))) ^ (~((int) (102))))))); + var_314 = (signed char) (!(((((int) ((signed char) (-18731))) * (((int) (struct_obj_4.member_2_3.member_1_0)) * ((int) (struct_obj_8.member_4_4)))) * ((((int) (struct_obj_6.member_5_0)) * ((int) (86))) / (((int) (45398)) * ((int) (1603))))) << ((~((((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172)))))) & (((int) (37)) & ((int) (55829))))) + (30)))); + signed char var_315 = struct_obj_4.member_2_3.member_1_0; + signed char var_316 = (~((int) ((short) (((int) ((signed char) (struct_obj_7.member_1_1))) < (((int) (13)) || ((int) (struct_obj_8.member_4_6))))))) || (+((int) (((((int) (var_66)) >> (((int) (struct_obj_1.member_5_3)) - (710))) | (((int) (var_5)) & ((int) (8143)))) >= (-(((int) (5864)) & ((int) (var_63))))))); + unsigned short var_317 = ((int) ((unsigned short) (~(((~((int) (44320))) + (2147483647)) >> ((((int) (20877)) & ((int) (-14066))) - (16645)))))) || ((int) (struct_obj_5.member_1_3)); + short var_318 = !((int) ((~(~(((int) (var_25)) | ((int) (struct_obj_1.member_5_0))))) <= ((((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172)))))) | (((int) ((unsigned short) (struct_obj_5.member_1_0))) << ((((int) (23789)) ^ ((int) (struct_obj_3.member_5_1))) - (56480)))))); + short var_319 = -(((int) ((unsigned short) ((((int) (-6974)) && ((int) (11892))) && (((int) (-3845)) || ((int) (-41)))))) || ((!(((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172))))))) && ((int) (-19831)))); + } + else + { + short var_320 = struct_obj_4.member_2_5; + unsigned short var_321 = struct_obj_6.member_5_0; + unsigned short var_322 = ~((int) (struct_obj_8.member_4_4)); + unsigned short var_323 = ((int) (var_41)) >> ((int) (((int) (((int) (((int) ((short) (var_27))) == (~(~((int) (struct_obj_4.member_2_5)))))) < (((((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172)))))) + (2147483647)) << (((int) ((((int) (var_28)) || ((int) (struct_obj_2.member_5_0))) != (((int) (var_19)) & ((int) (struct_obj_4.member_2_1.member_1_1))))) >> (!((int) (struct_obj_2.member_5_3))))))) != ((int) (((int) ((signed char) (((int) (var_36)) - ((int) (struct_obj_2.member_5_1))))) != (!((int) (struct_obj_6.member_5_3))))))); + unsigned short var_324 = ((int) (((int) ((short) (var_27))) == (~(~((int) (struct_obj_4.member_2_5)))))) < (((((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172)))))) + (2147483647)) << (((int) ((((int) (var_28)) || ((int) (struct_obj_2.member_5_0))) != (((int) (var_19)) & ((int) (struct_obj_4.member_2_1.member_1_1))))) >> (!((int) (struct_obj_2.member_5_3))))); + short var_325 = ((((int) (((int) (((int) ((short) (var_27))) == (~(~((int) (struct_obj_4.member_2_5)))))) < (((((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172)))))) + (2147483647)) << (((int) ((((int) (var_28)) || ((int) (struct_obj_2.member_5_0))) != (((int) (var_19)) & ((int) (struct_obj_4.member_2_1.member_1_1))))) >> (!((int) (struct_obj_2.member_5_3))))))) ^ ((((int) (-122)) | ((int) (11927))) ^ (((int) (-62)) & ((int) (118))))) ^ (~((~((int) (25738))) & (~((int) (39921)))))) & ((int) ((signed char) (~(~((int) ((unsigned short) (struct_obj_3.member_5_0))))))); + signed char var_326 = (-((int) ((short) ((~((int) (-4583))) == (-((int) (var_36))))))) - ((int) (((((((int) (var_66)) >> (((int) (var_39)) - (28144))) ^ (~((int) (var_1)))) + (2147483647)) << (((((((int) (struct_obj_6.member_5_1)) << (((int) (var_8)) - (14653))) | (((int) (struct_obj_8.member_4_2)) | ((int) (101)))) - (22861934)) - (0)) - (1))) > (((int) (((int) (((int) (2)) >= ((int) (-8179)))) > (((int) (26581)) >> (((int) (-19231)) + (19234))))) >> ((int) (((int) (struct_obj_1.member_5_1)) <= (((int) (var_324)) << (((int) (var_22)) - (100)))))))); + unsigned short var_327 = ((int) ((short) (~((((int) (26866)) ^ ((int) (var_325))) & ((int) (struct_obj_3.member_5_3)))))) & ((int) ((signed char) (~((((int) (-5)) & ((int) (43))) & (((int) (var_51)) | ((int) (var_62))))))); + unsigned short var_328 = ((((((int) (var_58)) & ((int) (struct_obj_2.member_5_1))) ^ (~((int) (struct_obj_4.member_2_4)))) >> ((((int) (17357)) << (((~((int) (var_41))) + (48559)) - (8))) - (568754148))) | ((int) ((unsigned short) (((((int) (struct_obj_7.member_1_0)) + (2147483647)) >> (((int) (var_32)) - (46780))) & (((int) (var_9)) | ((int) (-22456))))))) <= (-(~((int) ((-((int) (var_43))) < (((int) (var_62)) | ((int) (struct_obj_3.member_5_1))))))); + } + + signed char var_329 = ((int) ((unsigned short) (!(!(!((int) (struct_obj_2.member_5_1))))))) != (-((int) (((int) ((((int) (9111)) * ((int) (45153))) <= (!((int) (17457))))) <= (~(((int) (77)) | ((int) (119))))))); + if (((int) ((unsigned short) (((((int) (var_12)) ^ ((int) (var_62))) | (((int) (struct_obj_10.member_1_3)) | ((int) (struct_obj_2.member_5_0)))) | (((int) ((signed char) (-7510))) ^ (((int) (-22547)) | ((int) (24754))))))) & (((~(((int) (struct_obj_3.member_5_3)) | ((int) (8)))) ^ (~(((int) (56)) ^ ((int) (3137))))) | (~((~((int) (12881))) & (((int) (var_8)) & ((int) (var_25))))))) + { + signed char var_330 = ((int) ((unsigned short) (~((((int) (39713)) * ((int) (var_65))) * ((int) ((signed char) (struct_obj_4.member_2_1.member_1_1))))))) <= (!(~((((int) (struct_obj_4.member_2_1.member_1_0)) + ((int) (var_50))) * ((int) ((short) (29769)))))); + short var_331 = ~(((~(((int) (4598)) & ((int) (2017)))) | (((int) ((signed char) (32350))) | (((int) (-20556)) & ((int) (-79))))) ^ (((~((int) (-515))) & (((int) (61)) & ((int) (43194)))) | (((int) ((unsigned short) (11581))) & (~((int) (13360)))))); + signed char var_332 = (+(-(!(((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172))))))))) <= (((~(((int) (var_28)) * ((int) (struct_obj_5.member_1_0)))) / ((((int) (var_24)) * ((int) (-103))) * (-((int) (var_58))))) * (~(((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172)))))))); + unsigned short var_333 = (signed char) ((~((((int) (struct_obj_4.member_2_3.member_1_2)) | ((int) (var_10))) & (~((int) (var_31))))) & ((int) (((int) ((unsigned short) (((int) (-65)) * ((int) (-23009))))) < ((((int) (14)) >> (((int) (9306)) - (9299))) % ((int) (((int) (-1206)) != ((int) (96)))))))); + unsigned short var_334 = !(((~(((int) (-23006)) & ((int) (39022)))) ^ (~(((int) (14922)) | ((int) (-15058))))) | (((((int) (6629)) >> (((int) (35537)) - (35535))) & ((((int) (-16560)) + (2147483647)) >> (((int) (122)) - (118)))) >> (((((int) (16902)) >> ((int) (0))) ^ (~((int) (12194)))) + (28097)))); + short var_335 = ((((((int) (3251)) && ((int) (55))) || (((int) (49719)) && ((int) (-65)))) || (!(((int) (11)) || ((int) (1092))))) && ((int) (52871))) * (!((int) ((short) (struct_obj_3.member_5_1)))); + signed char var_336 = (((int) (((!((int) (20447))) || (((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172))))))) < (((int) ((signed char) (var_49))) >> ((((int) (var_23)) % ((int) (var_331))) - (2293))))) % ((int) ((unsigned short) (~((int) (struct_obj_2.member_5_1)))))) <= (~((int) ((short) ((((int) (var_21)) && ((int) (29492))) && (!((int) (var_332))))))); + } + else + { + unsigned short var_337 = (signed char) ((-((((int) (struct_obj_8.member_4_3)) * ((int) (struct_obj_5.member_1_0))) * (~((int) (struct_obj_4.member_2_1.member_1_0))))) & ((int) ((unsigned short) ((((int) (var_7)) >> (((int) (struct_obj_4.member_2_5)) - (10080))) <= (((int) (70)) & ((int) (-14194))))))); + signed char var_338 = (-((int) (((((int) (struct_obj_8.member_4_6)) ^ ((int) (53070))) ^ (((int) (struct_obj_4.member_2_1.member_1_3)) | ((int) (var_59)))) < ((((int) (var_46)) & ((int) (-73))) && (((int) (var_39)) ^ ((int) (var_63))))))) <= ((int) (((((int) ((short) (struct_obj_8.member_4_1.member_3_0))) ^ (((int) (var_40)) % ((int) (var_22)))) && ((int) ((short) ((unsigned short) (var_19))))) < (((((int) (-62)) * ((int) (struct_obj_4.member_2_3.member_1_3))) * (!((int) (var_44)))) * (((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172))))))))); + unsigned short var_339 = (((~((int) (struct_obj_9.member_2_1.member_1_3))) ^ (~((int) ((short) (var_238))))) & (((int) ((signed char) (((int) (-12841)) | ((int) (var_37))))) ^ ((int) ((short) (~((int) (var_49))))))) | ((int) ((short) ((unsigned short) (var_4)))); + unsigned short var_340 = ((((int) (-11424)) | (~(~((int) (46432))))) & (((int) (-2781)) * ((((int) (64292)) & ((int) (-22641))) * ((int) (((int) (23837)) <= ((int) (61))))))) - ((int) (25957)); + short var_341 = ((int) ((((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172)))))) > (((int) ((short) (((int) (struct_obj_4.member_2_0)) & ((int) (struct_obj_9.member_2_2))))) >> ((int) ((((int) (struct_obj_10.member_1_3)) * ((int) (4087))) <= (~((int) (var_13)))))))) + ((int) (struct_obj_8.member_4_2)); + } + + signed char var_342 = ~(((~((int) (struct_obj_3.member_5_3))) | ((((int) (struct_obj_9.member_2_1.member_1_1)) | ((int) (struct_obj_8.member_4_1.member_3_0))) | (((int) (854)) | ((int) (struct_obj_2.member_5_0))))) | (~((~((int) (var_21))) & ((int) (struct_obj_1.member_5_3))))); + if (!((int) ((((int) ((signed char) (-19215))) / ((!((int) (354))) | (((int) (10)) * ((int) (47875))))) > ((-(((int) (18345)) >> ((((int) (14143)) - (14111)) - (6)))) >> (((((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172)))))) - (((int) (12698)) + ((int) (20337)))) + (33070)))))) + { + signed char var_343 = (unsigned short) (((int) (struct_obj_8.member_4_1.member_3_1.member_1_0)) * (!((int) (var_34)))); + unsigned short var_344 = (~(~((((int) (-7563)) ^ ((int) (19679))) & (((int) (var_51)) | ((int) (var_60)))))) < ((int) ((short) (!(!(((int) (var_41)) || ((int) (var_42))))))); + short var_345 = (signed char) ((signed char) (!(((int) (9488)) || (((int) (struct_obj_4.member_2_3.member_1_2)) && ((int) (struct_obj_1.member_5_2)))))); + signed char var_346 = var_20; + short var_347 = (((int) (28581)) / (~((((int) (-39)) ^ ((int) (66))) ^ (((int) (-11597)) & ((int) (58452)))))) >> ((int) ((-(~((int) (((int) (83)) <= ((int) (26306)))))) > ((int) (((int) ((!((int) (-99))) <= (((int) (12533)) * ((int) (7321))))) > ((~((int) (26337))) | ((int) ((short) (36444)))))))); + unsigned short var_348 = ((int) (struct_obj_4.member_2_6)) + ((int) (((((~((int) (struct_obj_8.member_4_1.member_3_0))) & (~((int) (struct_obj_9.member_2_6)))) + (2147483647)) >> ((~(((int) (-11)) ^ ((int) (var_52)))) - (9858))) < (!(!(((int) (struct_obj_1.member_5_3)) || ((int) (3))))))); + signed char var_349 = (~(((int) (2973)) ^ ((int) (57652)))) | (~(((int) ((short) (~((int) (46420))))) & ((int) ((signed char) (~((int) (5937))))))); + signed char var_350 = ((int) (((-(((int) (var_36)) * ((int) (struct_obj_9.member_2_1.member_1_0)))) / ((+((int) (var_5))) - ((int) (struct_obj_9.member_2_2)))) > (((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172)))))))) != (~((int) (((~((int) (var_30))) & (~((int) (13)))) == (~(((int) (struct_obj_10.member_1_3)) && ((int) (struct_obj_7.member_1_1))))))); + } + else + { + short var_351 = ((((int) ((short) (28973))) ^ ((((int) (5)) & ((int) (-25148))) & ((((int) (-4462)) + (2147483647)) << ((((int) (-95)) + (112)) - (17))))) | (((((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172)))))) + (2147483647)) >> ((((int) ((short) (-32))) | (((int) (58)) >> (((int) (83)) - (53)))) + (59)))) < ((int) (((((int) (-14523)) && (((int) (24739)) >> (((int) (6042)) - (6039)))) + ((int) (-9773))) >= (((!((int) (34844))) || (((int) (50)) && ((int) (108)))) && (((int) ((unsigned short) (52136))) && (((int) (63576)) || ((int) (-30405))))))); + unsigned short var_352 = (((int) (((int) ((signed char) ((unsigned short) (var_27)))) < ((int) ((((int) (-12442)) / ((int) (10549))) != (((int) (18542)) * ((int) (struct_obj_2.member_5_1))))))) / (-((((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172)))))) * (((int) (7)) * ((int) (struct_obj_1.member_5_3)))))) | ((int) ((signed char) (((((int) (struct_obj_9.member_2_6)) * ((int) (var_17))) / ((int) (var_23))) / (((int) ((short) (var_32))) * (~((int) (struct_obj_1.member_5_3))))))); + short var_353 = (signed char) ((short) (((((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172)))))) && (!((int) (31901)))) && (!(((int) (24490)) && ((int) (var_14)))))); + unsigned short var_354 = ~((((~((int) ((unsigned short) (struct_obj_7.member_1_2)))) + (2147483647)) >> (((((int) ((short) (-16611))) + (2147483647)) >> ((int) (((int) (var_237)) < ((int) (-59))))) - (2147467024))) & ((((int) (2632)) << ((~((int) (-70))) - (60))) | (((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172)))))))); + short var_355 = ~(((int) ((signed char) ((((int) (var_238)) | ((int) (-28688))) | (~((int) (struct_obj_8.member_4_7)))))) & (-((int) (-18035)))); + unsigned short var_356 = -(~((-(((int) (var_239)) ^ ((int) (struct_obj_4.member_2_5)))) % (!(!((int) (struct_obj_3.member_5_3)))))); + } + + short var_357 = ((((int) ((short) (((int) (struct_obj_9.member_2_0)) & ((int) (15110))))) | ((~((int) (var_8))) ^ (((int) (struct_obj_8.member_4_7)) | ((int) (var_66))))) ^ ((((int) ((unsigned short) (-163))) & ((int) ((short) (-51)))) ^ ((~((int) (struct_obj_8.member_4_0))) ^ ((int) ((unsigned short) (var_5)))))) < ((((((int) (struct_obj_9.member_2_1.member_1_3)) ^ ((int) (var_43))) >> ((~((int) (-19756))) - (19725))) & (~(((int) (var_60)) << ((int) (var_237))))) & ((((((int) (-91)) & ((int) (-28291))) + (2147483647)) >> ((((int) (51254)) << ((((int) (var_53)) - (13724)) - (13))) - (410005))) & ((int) (var_45)))); + var_358 = (unsigned short) (((int) (((int) ((((int) (var_2)) ^ ((int) ((unsigned short) (var_16)))) < ((int) ((signed char) (((int) (40083)) & ((int) (var_16))))))) <= ((int) (14594)))) != ((int) ((signed char) (((int) (((int) ((((int) (-5)) & ((int) (-31721))) != ((int) ((signed char) (var_35))))) <= (((int) ((unsigned short) (55455))) / (((int) (struct_obj_4.member_2_3.member_1_0)) && ((int) (struct_obj_4.member_2_6)))))) >> (((-((int) ((signed char) (var_8)))) % (((int) (-9)) + (-(((-((int) (-23416))) - ((int) ((unsigned short) (55908)))) / ((((int) (-24160)) - ((int) (28547))) * ((int) (19172))))))) + (10)))))); + } + + var_359 = (short) (!((~((int) ((unsigned short) (((int) (8977)) ^ ((int) (-2109)))))) ^ ((int) ((signed char) ((unsigned short) (~((int) (22)))))))); + if ((((int) ((short) (~(~((int) (var_43)))))) | (((~((int) (struct_obj_4.member_2_2))) + (2147483647)) >> ((((((int) (struct_obj_2.member_5_0)) & ((int) (-15349))) + (2147483647)) << (((((((((int) (-4)) + (2147483647)) >> (((int) (var_66)) - (65529))) - (67108862)) - (0)) - (0)) - (0)) - (1))) - (2147451885)))) & (((((int) (var_7)) ^ (((int) (struct_obj_4.member_2_5)) << (((int) (36)) - (31)))) << ((((int) (38)) & ((int) (var_60))) << (((int) (struct_obj_9.member_2_2)) >> (((int) (var_50)) - (46957))))) & (~((((int) (struct_obj_8.member_4_9.member_1_0)) << (((int) (7420)) - (7409))) | (~((int) (76))))))) + { + short var_360 = (((int) (var_17)) ^ (~((int) (39)))) - (~(((((int) (struct_obj_1.member_5_3)) & ((int) (struct_obj_5.member_1_3))) >> ((((int) (var_58)) & ((int) (struct_obj_4.member_2_3.member_1_1))) - (25))) | (~(((int) (struct_obj_10.member_1_3)) ^ ((int) (var_40)))))); + unsigned short var_361 = (!(((((int) (-22027)) | ((int) (struct_obj_2.member_5_3))) | (((int) (-7382)) ^ ((int) (var_35)))) & ((int) ((signed char) (~((int) (var_6))))))) & ((int) (((int) (struct_obj_9.member_2_1.member_1_3)) > (~(((~((int) (var_41))) + (2147483647)) >> ((((int) (-5606)) + (2147483647)) >> (((int) (-10)) + (38))))))); + if (109) + { + signed char var_362 = (short) ((signed char) ((((int) (24460)) + ((int) (14314))) * ((((int) (54241)) - ((int) (18419))) + (((int) (struct_obj_10.member_1_3)) + ((int) (struct_obj_2.member_5_3)))))); + unsigned short var_363 = ((((((int) (3103)) | ((int) (var_60))) << ((((int) (var_22)) | ((int) (struct_obj_8.member_4_5))) - (1270))) >> ((~(~((int) (var_36)))) - (27384))) >> (((int) ((short) (struct_obj_8.member_4_5))) - (1174))) * ((((int) ((((int) (35729)) || ((int) (var_38))) <= (!((int) (var_26))))) - (!(((int) (20238)) << (((int) (struct_obj_9.member_2_2)) - (40620))))) ^ ((int) (var_361))); + unsigned short var_364 = ((~(((int) ((unsigned short) (-12425))) & ((int) ((short) (52122))))) ^ (((~((int) (22591))) ^ (((int) (-14345)) & ((int) (51874)))) ^ ((((int) (51549)) ^ ((int) (3763))) ^ (((int) (43867)) ^ ((int) (-14)))))) & ((int) ((signed char) (14314))); + signed char var_365 = ((int) ((short) (~((int) (14314))))) >= (-(+((int) ((short) (((int) (struct_obj_5.member_1_3)) - ((int) (struct_obj_10.member_1_2))))))); + short var_366 = ((int) ((unsigned short) ((short) ((((int) (26517)) || ((int) (-9710))) && (((int) (struct_obj_9.member_2_1.member_1_0)) || ((int) (var_60))))))) >> ((int) (((int) (14314)) != ((((int) ((short) (struct_obj_6.member_5_3))) & (((int) (struct_obj_9.member_2_5)) & ((int) (-37)))) ^ (~((int) ((signed char) (struct_obj_8.member_4_9.member_1_2))))))); + var_367 = (signed char) (((int) (18490)) << ((~(~((~((int) (var_56))) ^ (((int) (-35)) | ((int) (var_50)))))) - (20202))); + short var_368 = (~((int) ((short) ((-((int) (struct_obj_4.member_2_1.member_1_3))) || ((int) ((signed char) (40213))))))) <= ((int) ((~((int) ((signed char) (((int) (var_60)) & ((int) (43)))))) <= ((~(((int) (var_12)) | ((int) (var_6)))) | ((int) ((signed char) (((int) (var_42)) & ((int) (var_66)))))))); + short var_369 = ((int) (struct_obj_4.member_2_3.member_1_1)) & (~((int) ((unsigned short) (((int) (14314)) ^ (((int) (-90)) & ((int) (74))))))); + short var_370 = ((int) ((-((int) (var_11))) < (((int) (var_46)) >> ((((((int) (var_3)) ^ ((int) (struct_obj_3.member_5_0))) + (2147483647)) >> (((~((int) (var_54))) - (24876)) - (30))) - (536863949))))) >= (!(((int) (14314)) << ((int) ((~((int) (var_38))) == (((int) (var_8)) & ((int) (struct_obj_9.member_2_2))))))); + short var_371 = ((int) (14314)) % ((int) (122)); + } + + var_46 = (unsigned short) (((int) (((int) ((~(((int) (17)) << (((int) (var_56)) - (20181)))) > ((((int) (var_35)) || ((int) (struct_obj_4.member_2_3.member_1_3))) || (((int) (struct_obj_9.member_2_2)) || ((int) (struct_obj_5.member_1_0)))))) <= (((((int) (struct_obj_8.member_4_9.member_1_0)) ^ ((int) (struct_obj_1.member_5_3))) ^ (((int) (var_46)) ^ ((int) (-14806)))) && ((~((int) (struct_obj_5.member_1_3))) & (((int) (struct_obj_1.member_5_3)) & ((int) (struct_obj_8.member_4_1.member_3_1.member_1_0))))))) || ((int) (((((int) (((int) (42)) >= ((int) (43439)))) & ((int) ((unsigned short) (var_360)))) % ((int) ((unsigned short) (~((int) (var_239)))))) <= ((int) (14314))))); + signed char var_372 = !((int) ((signed char) (!(!(((int) (var_20)) || ((int) (struct_obj_9.member_2_0))))))); + short var_373 = (((int) (((int) (var_59)) != ((int) ((unsigned short) (-((int) (var_39))))))) & (!(~((int) (struct_obj_8.member_4_2))))) > (+(((((int) (13707)) & ((int) (7604))) | (((int) (-25846)) & ((int) (-16556)))) & (~(~((int) (-31893)))))); + signed char var_374 = (((int) ((unsigned short) ((((int) (var_24)) - ((int) (-19514))) + ((int) ((unsigned short) (struct_obj_8.member_4_6)))))) % (~((((int) (struct_obj_3.member_5_1)) & ((int) (24836))) ^ ((int) (14314))))) && (((((int) ((unsigned short) (var_22))) * ((int) ((signed char) (-16118)))) / ((+((int) (32053))) * (((int) (var_46)) * ((int) (struct_obj_9.member_2_5))))) * (!(((int) ((unsigned short) (-21342))) / (((int) (-24)) * ((int) (44779)))))); + } + + if (-((((int) ((~((int) (-2283))) > ((int) (30538)))) & ((~((int) (-122))) | (((int) (20509)) | ((int) (-30753))))) ^ ((int) (struct_obj_8.member_4_2)))) + { + short var_375 = (((int) ((signed char) ((((int) (-5376)) | ((int) (33396))) & (~((int) (52)))))) | (~(~((int) (struct_obj_8.member_4_1.member_3_0))))) & (~(((((int) (struct_obj_3.member_5_2)) | ((int) (51))) ^ (((int) (struct_obj_8.member_4_9.member_1_2)) | ((int) (5146)))) ^ ((((int) (var_47)) ^ ((int) (var_59))) ^ (((int) (var_53)) ^ ((int) (var_61)))))); + short var_376 = ((int) ((short) (((int) ((signed char) (~((int) (struct_obj_7.member_1_2))))) ^ (~(((int) (struct_obj_4.member_2_7)) | ((int) (53512))))))) ^ (~((int) (struct_obj_8.member_4_3))); + if (!((((((int) (18612)) * ((int) (11102))) / (((int) (-10215)) * ((int) (14601)))) * ((int) ((unsigned short) (((int) (9895)) * ((int) (37183)))))) * ((((int) ((signed char) (5985))) * ((int) (-79))) * ((((int) (29091)) * ((int) (54881))) * (!((int) (8671))))))) + { + unsigned short var_377 = ~((((((int) (-37)) ^ ((int) (struct_obj_2.member_5_1))) & (~((int) (107)))) & ((((int) (var_26)) | ((int) (4730))) & (((int) (-82)) & ((int) (22312))))) & (((int) (struct_obj_9.member_2_4)) | ((~((int) (121))) & (((int) (struct_obj_7.member_1_2)) & ((int) (struct_obj_8.member_4_5)))))); + signed char var_378 = ~(((((int) (var_239)) | (((int) (struct_obj_8.member_4_4)) | ((int) (var_54)))) & ((int) (var_31))) | (((int) ((unsigned short) (4132))) ^ ((((int) (var_239)) | ((int) (var_27))) & ((int) ((unsigned short) (36)))))); + short var_379 = (signed char) (var_23); + signed char var_380 = !((int) (((int) (((int) ((short) (!((int) (45291))))) > ((int) (-24057)))) <= ((((int) (79)) | (((int) (7019)) * ((int) (-30489)))) + ((int) ((((int) (45)) || ((int) (19))) <= (~((int) (8145)))))))); + short var_381 = (short) (((int) (struct_obj_3.member_5_0)) * (~((((int) (var_50)) / ((int) (var_1))) * ((int) ((short) (var_34)))))); + unsigned short var_382 = !((int) ((((int) ((short) (!((int) (((int) (((int) ((short) (!((int) (45291))))) > ((int) (-24057)))) <= ((((int) (79)) | (((int) (7019)) * ((int) (-30489)))) + ((int) ((((int) (45)) || ((int) (19))) <= (~((int) (8145))))))))))) * (~(~((int) (struct_obj_4.member_2_1.member_1_3))))) != ((int) (((((int) (32580)) - ((int) (var_19))) - (((int) (var_57)) - ((int) (20)))) > ((((int) (var_31)) * ((int) (var_21))) / (((int) (var_16)) * ((int) (var_24)))))))); + signed char var_383 = -(((~((int) (62))) || ((!((int) (struct_obj_10.member_1_0))) || ((int) (var_43)))) >> (((~(((int) (var_20)) ^ ((int) (struct_obj_4.member_2_7)))) | ((((int) (9112)) ^ ((int) (var_12))) | (~((int) (struct_obj_4.member_2_1.member_1_1))))) - (63223))); + } + else + { + signed char var_384 = +((!((int) (var_15))) || (((((int) (var_22)) || ((int) (var_30))) || (((int) (var_56)) || ((int) (var_25)))) && (((int) ((short) (var_46))) && (((int) (var_14)) && ((int) (var_1)))))); + signed char var_385 = (~((int) ((-(!((int) (var_10)))) > ((int) ((((int) (7176)) || ((int) (struct_obj_3.member_5_3))) < (((int) (var_9)) ^ ((int) (var_4)))))))) & ((((((int) (var_66)) ^ ((int) (struct_obj_8.member_4_6))) ^ ((int) (var_25))) & (((int) ((signed char) (var_63))) & (((int) (41306)) ^ ((int) (-112))))) | (~(~(((int) (struct_obj_6.member_5_1)) | ((int) (20554)))))); + signed char var_386 = ((int) ((short) (((((int) (struct_obj_8.member_4_7)) | ((int) (var_23))) << (((int) ((unsigned short) (struct_obj_4.member_2_3.member_1_0))) - (10))) & ((((int) (78)) | ((int) (struct_obj_8.member_4_2))) << (((~((int) (struct_obj_8.member_4_0))) + (17374)) - (3)))))) ^ ((((int) (var_43)) << ((~((int) (struct_obj_5.member_1_0))) & (((int) (33)) >> (((int) (90)) - (76))))) & ((int) (48))); + short var_387 = ((((int) ((short) (~((int) (37783))))) & ((int) ((unsigned short) (!((int) (((int) (((int) ((short) (!((int) (45291))))) > ((int) (-24057)))) <= ((((int) (79)) | (((int) (7019)) * ((int) (-30489)))) + ((int) ((((int) (45)) || ((int) (19))) <= (~((int) (8145)))))))))))) / ((int) (64))) * ((int) (((int) ((!((int) (((int) (66)) != ((int) (61361))))) <= ((int) ((((int) (var_4)) || ((int) (var_45))) >= ((int) (((int) (10596)) == ((int) (struct_obj_3.member_5_2)))))))) != (((((int) (var_54)) * ((int) (115))) - (((int) (struct_obj_4.member_2_2)) >> (((int) (struct_obj_5.member_1_3)) + (20999)))) * ((int) (((int) ((signed char) (-2450))) == ((int) (((int) (6285)) <= ((int) (struct_obj_10.member_1_2))))))))); + short var_388 = ((int) (struct_obj_4.member_2_3.member_1_0)) >> (((((~(~((int) (struct_obj_8.member_4_6)))) ^ (~(((int) (var_62)) ^ ((int) (-20398))))) + (2147483647)) << (((!((~((int) (struct_obj_8.member_4_1.member_3_1.member_1_2))) >> ((((int) (17689)) & ((int) (58630))) - (17642)))) - (0)) - (1))) - (2147436043)); + } + + signed char var_389 = (((~((~((int) (-13180))) % ((int) ((signed char) (982))))) + (2147483647)) >> ((int) ((unsigned short) (((int) (((int) (41013)) < ((int) (struct_obj_8.member_4_9.member_1_0)))) > (((int) (-114)) % ((int) (var_52))))))) >> ((((int) (var_48)) * (!(~((int) (struct_obj_4.member_2_3.member_1_2))))) & ((-((int) ((unsigned short) (struct_obj_8.member_4_6)))) * (+(((int) (6318)) + ((int) (var_8)))))); + short var_390 = ~(((~(!((int) (((int) (((int) ((short) (!((int) (45291))))) > ((int) (-24057)))) <= ((((int) (79)) | (((int) (7019)) * ((int) (-30489)))) + ((int) ((((int) (45)) || ((int) (19))) <= (~((int) (8145)))))))))) + (2147483647)) << (((~(!((int) (((int) (((int) ((short) (!((int) (45291))))) > ((int) (-24057)))) <= ((((int) (79)) | (((int) (7019)) * ((int) (-30489)))) + ((int) ((((int) (45)) || ((int) (19))) <= (~((int) (8145)))))))))) + (5)) - (3))); + signed char var_391 = (short) (((~((int) ((unsigned short) (-29)))) ^ ((int) (-21318))) != (((int) (var_52)) >> ((((int) ((signed char) (var_41))) ^ (!((int) (((int) (((int) ((short) (!((int) (45291))))) > ((int) (-24057)))) <= ((((int) (79)) | (((int) (7019)) * ((int) (-30489)))) + ((int) ((((int) (45)) || ((int) (19))) <= (~((int) (8145)))))))))) + (109)))); + var_392 = (unsigned short) (-(+((int) ((signed char) ((short) (~((int) (var_239)))))))); + if (~(((int) (-14799)) * ((~(((int) (struct_obj_5.member_1_3)) * ((int) (-23808)))) * ((!((int) (-20034))) * (((int) (struct_obj_9.member_2_0)) * ((int) (struct_obj_10.member_1_2))))))) + { + unsigned short var_393 = ~((int) (((int) (var_14)) != (((~((int) (var_16))) | ((~(((int) (var_28)) ^ ((int) (struct_obj_4.member_2_3.member_1_0)))) ^ ((((int) (8520)) | ((int) (struct_obj_4.member_2_7))) ^ ((int) ((signed char) (32145)))))) & (((int) ((short) (var_5))) * ((int) (((int) (struct_obj_3.member_5_3)) >= ((((int) (-80)) - ((int) (-145))) - (((int) (var_24)) * ((int) (var_26)))))))))); + unsigned short var_394 = (-(((((int) (-37)) | ((int) (struct_obj_9.member_2_4))) * (((int) (var_10)) || ((int) (118)))) & ((int) (-26136)))) / ((int) (((int) ((unsigned short) ((!((int) (struct_obj_9.member_2_2))) && (((int) (var_47)) || ((int) (var_20)))))) != ((~((((int) (-31043)) + (2147483647)) << (((int) (struct_obj_3.member_5_2)) - (59825)))) - ((((int) (struct_obj_4.member_2_3.member_1_2)) * ((int) (struct_obj_1.member_5_2))) ^ (((int) (var_65)) || ((int) (struct_obj_9.member_2_6))))))); + short var_395 = (!((int) ((((int) ((signed char) (var_61))) ^ ((int) ((short) (struct_obj_2.member_5_2)))) <= ((int) (struct_obj_6.member_5_1))))) % ((((-((int) (struct_obj_8.member_4_1.member_3_1.member_1_1))) + (-((int) (21146)))) * (-((int) (var_11)))) ^ (((int) ((unsigned short) (((int) (var_35)) >> (((int) (var_35)) - (14408))))) || ((int) (var_43)))); + signed char var_396 = ((((-((int) (114))) / (((int) (10051)) * ((int) (3676)))) * ((int) (10897))) * (~((((int) (52640)) / ((int) (57215))) * (((int) (126)) * ((int) (21)))))) * ((int) (-104)); + short var_397 = struct_obj_4.member_2_3.member_1_2; + unsigned short var_398 = +((int) ((short) (var_17))); + short var_399 = (((int) (39888)) || ((int) ((signed char) ((((int) (-25317)) | ((int) (5975))) | (((int) (struct_obj_7.member_1_2)) ^ ((int) (19725))))))) + ((int) ((~(~(((int) (var_52)) * ((int) (struct_obj_4.member_2_5))))) <= (((((int) (24622)) & ((int) (struct_obj_8.member_4_6))) >> ((((int) (-6)) ^ ((int) (struct_obj_8.member_4_9.member_1_1))) + (13903))) | ((((int) (struct_obj_4.member_2_1.member_1_1)) & ((int) (var_65))) | (~((int) (var_9))))))); + signed char var_400 = (~((int) (struct_obj_9.member_2_2))) & (!((int) (((int) (((int) ((short) (!((int) (45291))))) > ((int) (-24057)))) <= ((((int) (79)) | (((int) (7019)) * ((int) (-30489)))) + ((int) ((((int) (45)) || ((int) (19))) <= (~((int) (8145))))))))); + short var_401 = (((int) (30788)) || (((((int) (struct_obj_4.member_2_1.member_1_1)) || ((int) (var_54))) && (((int) (struct_obj_9.member_2_5)) || ((int) (31866)))) && (!(((int) (-25)) || ((int) (var_25)))))) && ((((!((int) (-8773))) && (((int) (var_4)) || ((int) (struct_obj_6.member_5_2)))) || (((int) ((unsigned short) (struct_obj_10.member_1_0))) || (!((int) (var_390))))) || (((int) (var_63)) && ((((int) (var_14)) && ((int) (var_3))) && (((int) (46668)) && ((int) (var_376)))))); + short var_402 = -((+((((int) (struct_obj_6.member_5_1)) * ((int) (struct_obj_10.member_1_3))) / (((int) (41269)) * ((int) (4485))))) * ((+(((int) (71)) * ((int) (struct_obj_7.member_1_0)))) / ((((int) (85)) * ((int) (var_14))) * ((int) (struct_obj_3.member_5_2))))); + } + else + { + short var_403 = struct_obj_3.member_5_2; + var_40 = (signed char) (((int) ((((int) ((+((int) (struct_obj_8.member_4_6))) != ((int) ((unsigned short) (var_24))))) & (~(((int) (struct_obj_4.member_2_1.member_1_0)) >> (((int) (5468)) - (5438))))) >= ((int) ((short) ((unsigned short) (((int) (6863)) > ((int) (struct_obj_9.member_2_1.member_1_0)))))))) >> ((((((int) (89)) & ((int) (-26560))) ^ ((int) ((unsigned short) (61166)))) | ((((int) (struct_obj_3.member_5_1)) & ((int) (25315))) ^ (((int) (7697)) & ((int) (89))))) >> (((int) ((signed char) (-(((int) (struct_obj_3.member_5_3)) + ((int) (40803)))))) + (79)))); + short var_404 = ((int) (var_23)) >> ((((((int) (94)) | ((int) (63983))) >> ((((int) (var_52)) << ((((int) (-34)) + (64)) - (13))) - (1294204900))) & (!((int) (((int) (((int) ((short) (!((int) (45291))))) > ((int) (-24057)))) <= ((((int) (79)) | (((int) (7019)) * ((int) (-30489)))) + ((int) ((((int) (45)) || ((int) (19))) <= (~((int) (8145)))))))))) << (((~((int) ((signed char) (var_46)))) | (((int) (struct_obj_4.member_2_0)) | (~((int) (struct_obj_6.member_5_1))))) + (15))); + unsigned short var_405 = (short) (~((~(~((int) (-82)))) & (~(~((int) (var_21)))))); + unsigned short var_406 = (!((int) ((((((int) (-5843)) + (2147483647)) >> (((int) (9959)) - (9945))) || (((int) (65528)) % ((int) (18356)))) > ((int) (-82))))) & ((int) ((((((int) (16978)) << (((int) (55441)) - (55441))) & (~((int) (20123)))) << ((((((int) (-53)) & ((int) (-20160))) + (2147483647)) << ((((int) (63586)) ^ ((int) (48225))) - (17411))) - (2147463464))) <= (~(!(((int) (32938)) && ((int) (55062))))))); + short var_407 = (~(~((int) ((unsigned short) (~((int) (30575))))))) < (~((~((int) ((unsigned short) (var_24)))) % (~((int) (((int) (struct_obj_9.member_2_2)) != ((int) (struct_obj_10.member_1_2))))))); + var_37 = (signed char) (((int) ((unsigned short) (!((((int) (struct_obj_5.member_1_0)) * ((int) (4381))) / (((int) (struct_obj_9.member_2_0)) * ((int) (var_8))))))) & (!((int) (((int) (((int) ((short) (!((int) (45291))))) > ((int) (-24057)))) <= ((((int) (79)) | (((int) (7019)) * ((int) (-30489)))) + ((int) ((((int) (45)) || ((int) (19))) <= (~((int) (8145)))))))))); + unsigned short var_408 = ((int) ((!((((int) ((-127 - 1))) * ((int) (var_23))) * ((int) (var_405)))) <= ((int) ((unsigned short) ((!((int) (struct_obj_8.member_4_1.member_3_1.member_1_1))) != (~((int) (14031)))))))) << ((int) (((int) ((unsigned short) ((unsigned short) (+((int) (8559)))))) == ((((int) ((signed char) (-13521))) & ((int) (18645))) >> ((int) (((int) (((int) (115)) >= ((int) (24451)))) > ((int) (((int) (20299)) <= ((int) (-4935))))))))); + unsigned short var_409 = ~((~((int) ((unsigned short) (((int) (-5693)) | ((int) (struct_obj_8.member_4_1.member_3_1.member_1_1)))))) | (!((int) (((int) (((int) ((short) (!((int) (45291))))) > ((int) (-24057)))) <= ((((int) (79)) | (((int) (7019)) * ((int) (-30489)))) + ((int) ((((int) (45)) || ((int) (19))) <= (~((int) (8145)))))))))); + signed char var_410 = (signed char) ((((int) ((signed char) (((int) (struct_obj_8.member_4_3)) - ((int) (2744))))) * (+((int) (struct_obj_8.member_4_9.member_1_2)))) > ((int) (struct_obj_4.member_2_1.member_1_0))); + } + + unsigned short var_411 = (signed char) (24176); + } + + if ((short) (((!(((int) (struct_obj_1.member_5_2)) && ((int) (50462)))) || ((!((int) (var_26))) && (!((int) (var_239))))) && (!((int) ((signed char) (((int) (-15398)) && ((int) (struct_obj_4.member_2_3.member_1_1)))))))) + { + if (~((int) ((signed char) (((((int) (-3658)) & ((int) (46399))) & (~((int) (var_6)))) & ((((int) (struct_obj_8.member_4_1.member_3_1.member_1_0)) & ((int) (struct_obj_8.member_4_2))) | (~((int) (var_55)))))))) + { + signed char var_412 = (((((((~((int) (36437))) + (2147483647)) << ((((int) (struct_obj_1.member_5_3)) << (((int) (var_2)) - (17781))) - (5920))) & (~((int) ((signed char) (struct_obj_4.member_2_1.member_1_3))))) ^ (((((int) (var_33)) << (((int) (17994)) - (17983))) >> (((int) ((short) (var_20))) + (16020))) ^ (((~((int) (101))) + (2147483647)) >> ((((int) (-7863)) ^ ((int) (struct_obj_4.member_2_4))) - (21936))))) | (~((int) (struct_obj_4.member_2_3.member_1_2)))) | ((!(!((int) (struct_obj_6.member_5_2)))) || ((((int) (-22401)) || ((int) (var_15))) || (((int) (73)) || ((int) (-31)))))) >> (((~(~((int) (77)))) & ((int) ((signed char) (~((int) ((unsigned short) (-3189))))))) - (66)); + unsigned short var_413 = ~((~(((int) ((unsigned short) (var_63))) ^ (((int) (struct_obj_4.member_2_3.member_1_3)) ^ ((int) (888))))) && ((int) ((signed char) (((int) ((short) (92))) >> (((int) ((signed char) (83))) - (81)))))); + signed char var_414 = ((int) ((short) (~((int) ((signed char) (!((int) (31724)))))))) != ((int) (((int) ((short) ((!((int) (var_61))) || (((int) (struct_obj_9.member_2_1.member_1_3)) && ((int) (var_15)))))) < ((int) (((((int) (struct_obj_6.member_5_3)) >> (((int) (42310)) - (42285))) && (~((int) ((short) (~(~((int) (-20)))))))) <= (~(((int) (25509)) || ((int) (var_26)))))))); + signed char var_415 = ~((int) ((short) (~(~((int) (-20)))))); + struct_obj_5.member_1_3 = (short) ((((int) (((((int) (1141)) >> (((int) (20167)) - (20155))) * (!((int) (7901)))) > (((int) ((unsigned short) (-12160))) || (((int) (6205)) || ((int) (-116)))))) >> ((int) (((!((int) (var_26))) && (((int) (-16178)) || ((int) (-93)))) < ((int) ((-((int) (struct_obj_4.member_2_3.member_1_1))) != ((int) ((signed char) (var_56)))))))) == ((((~((int) (-13334))) & (((int) (38790)) & ((int) (46)))) | (((int) ((short) (var_52))) ^ ((int) ((short) (6800))))) ^ ((int) ((signed char) ((signed char) (((int) (49)) ^ ((int) (-7974)))))))); + } + + if ((((int) ((signed char) ((((int) (var_16)) ^ ((int) (var_60))) ^ (~((int) (8171)))))) ^ (~((int) (var_63)))) || (((((((~((int) (36437))) + (2147483647)) << ((((int) (struct_obj_1.member_5_3)) << (((int) (var_2)) - (17781))) - (5920))) & (~((int) ((signed char) (struct_obj_4.member_2_1.member_1_3))))) ^ (((((int) (var_33)) << (((int) (17994)) - (17983))) >> (((int) ((short) (var_20))) + (16020))) ^ (((~((int) (101))) + (2147483647)) >> ((((int) (-7863)) ^ ((int) (struct_obj_4.member_2_4))) - (21936))))) | (~((int) (struct_obj_4.member_2_3.member_1_2)))) * ((((int) ((short) (35294))) * ((+(((int) ((unsigned short) (((int) (-7293)) * ((int) (5069))))) * ((int) ((signed char) (((int) (struct_obj_2.member_5_3)) * ((int) (var_16))))))) * (((int) (((int) (var_34)) < ((int) ((short) ((unsigned short) (var_24)))))) & ((~((int) ((short) (var_14)))) & (~(~((int) (var_14)))))))) * ((-((int) (-14699))) / (((int) (32201)) * ((int) (13800))))))) + { + unsigned short var_416 = -(!(+((((int) (var_11)) >> (((int) (62073)) - (62065))) - ((int) (((int) (26396)) > ((int) (var_23))))))); + signed char var_417 = (((~(((+(((int) ((unsigned short) (((int) (-7293)) * ((int) (5069))))) * ((int) ((signed char) (((int) (struct_obj_2.member_5_3)) * ((int) (var_16))))))) * (((int) (((int) (var_34)) < ((int) ((short) ((unsigned short) (var_24)))))) & ((~((int) ((short) (var_14)))) & (~(~((int) (var_14))))))) & ((int) ((unsigned short) (var_239))))) + (2147483647)) >> ((((int) (struct_obj_6.member_5_2)) | (~(((int) (struct_obj_4.member_2_3.member_1_0)) | ((int) (48769))))) + (3079))) >> (((((~((int) (-24))) & (((int) (var_30)) >> (((int) (var_7)) - (32)))) << (((int) ((short) (((int) (struct_obj_2.member_5_0)) & ((int) (struct_obj_6.member_5_3))))) - (12279))) | ((int) ((signed char) (struct_obj_9.member_2_1.member_1_1)))) + (62)); + signed char var_418 = ((int) ((signed char) (-((int) ((unsigned short) ((short) (struct_obj_1.member_5_3))))))) == ((((((int) (14395)) ^ ((int) (28584))) ^ (((int) (struct_obj_8.member_4_9.member_1_0)) | ((int) (var_239)))) ^ (~(((int) (32)) ^ ((int) (struct_obj_3.member_5_3))))) ^ ((int) ((short) ((((int) (struct_obj_5.member_1_1)) & ((int) (var_13))) ^ (((int) (var_5)) | ((int) (-69))))))); + signed char var_419 = (~((~(((int) (28263)) ^ ((int) (115)))) ^ ((((int) (21)) & ((int) (71))) | ((int) (var_39))))) & ((((((~((int) (36437))) + (2147483647)) << ((((int) (struct_obj_1.member_5_3)) << (((int) (var_2)) - (17781))) - (5920))) & (~((int) ((signed char) (struct_obj_4.member_2_1.member_1_3))))) ^ (((((int) (var_33)) << (((int) (17994)) - (17983))) >> (((int) ((short) (var_20))) + (16020))) ^ (((~((int) (101))) + (2147483647)) >> ((((int) (-7863)) ^ ((int) (struct_obj_4.member_2_4))) - (21936))))) | (~((int) (struct_obj_4.member_2_3.member_1_2)))); + signed char var_420 = (~(((((int) ((signed char) (-94))) ^ ((int) ((signed char) (struct_obj_7.member_1_1)))) + (2147483647)) >> ((~(~((int) (struct_obj_10.member_1_3)))) + (21785)))) != ((~((int) ((short) ((short) (-27))))) && (~(-((int) (var_37))))); + unsigned short var_421 = ~(((int) ((signed char) (+(!((int) (var_4)))))) & ((int) (((~((int) (var_30))) && (((int) (var_23)) && ((int) (struct_obj_8.member_4_9.member_1_0)))) != ((((((~((int) (36437))) + (2147483647)) << ((((int) (struct_obj_1.member_5_3)) << (((int) (var_2)) - (17781))) - (5920))) & (~((int) ((signed char) (struct_obj_4.member_2_1.member_1_3))))) ^ (((((int) (var_33)) << (((int) (17994)) - (17983))) >> (((int) ((short) (var_20))) + (16020))) ^ (((~((int) (101))) + (2147483647)) >> ((((int) (-7863)) ^ ((int) (struct_obj_4.member_2_4))) - (21936))))) | (~((int) (struct_obj_4.member_2_3.member_1_2))))))); + } + + if ((((((~((int) (36437))) + (2147483647)) << ((((int) (struct_obj_1.member_5_3)) << (((int) (var_2)) - (17781))) - (5920))) & (~((int) ((signed char) (struct_obj_4.member_2_1.member_1_3))))) ^ (((((int) (var_33)) << (((int) (17994)) - (17983))) >> (((int) ((short) (var_20))) + (16020))) ^ (((~((int) (101))) + (2147483647)) >> ((((int) (-7863)) ^ ((int) (struct_obj_4.member_2_4))) - (21936))))) | (~((int) (struct_obj_4.member_2_3.member_1_2)))) + { + var_36 = (short) (25335); + unsigned short var_422 = (((int) ((signed char) ((-((int) (struct_obj_4.member_2_1.member_1_3))) <= ((int) (((int) (-14940)) < ((int) (52041))))))) * (((((int) (struct_obj_2.member_5_2)) ^ ((int) (57552))) >> (((int) (2460)) & ((int) (var_38)))) || ((int) (((int) ((unsigned short) (-2096))) <= (((int) (var_25)) - ((int) (var_66))))))) < ((((+((int) (struct_obj_6.member_5_3))) + (+((int) (46470)))) - ((+((int) (2855))) + (((int) (var_41)) - ((int) (-121))))) + (-((-((int) (var_58))) + ((int) ((short) (-127)))))); + unsigned short var_423 = 44; + short var_424 = -(-((int) ((!(~((int) (61500)))) <= ((~((int) (var_37))) || ((int) (((int) (var_21)) >= ((int) (var_7)))))))); + unsigned short var_425 = (short) ((~(~(((int) (-11932)) ^ ((int) (var_239))))) ^ (~(~(((int) (-7336)) ^ ((int) (5408)))))); + unsigned short var_426 = !(((int) (((int) (((int) (283)) <= ((int) (65)))) != ((int) ((signed char) (((int) (22882)) ^ ((int) (29567))))))) || (-(((int) ((signed char) (var_239))) | (((int) (struct_obj_4.member_2_3.member_1_3)) & ((int) (-27)))))); + unsigned short var_427 = (((((~((int) (struct_obj_3.member_5_3))) ^ (((int) (-24690)) | ((int) (91)))) + (2147483647)) >> ((int) ((((int) (-28477)) + ((int) (var_17))) == (~((int) (var_30)))))) / ((int) ((short) ((short) (((int) (-30015)) - ((int) (65016))))))) >= ((int) (struct_obj_6.member_5_2)); + short var_428 = (+((int) ((short) ((((int) (-99)) * ((int) (var_58))) + (((int) (-8669)) - ((int) (3621))))))) < ((int) ((signed char) (~(((((int) (var_64)) + (2147483647)) << ((int) (var_427))) << (((((int) ((unsigned short) (11))) - (10)) - (0)) - (1)))))); + signed char var_429 = ((((int) ((unsigned short) (~((int) (var_50))))) * (~((int) (var_5)))) * ((int) (var_47))) * ((~(((int) ((short) (64554))) * (((int) (68)) * ((int) (39))))) * (((+((int) (-19580))) / (((int) (-26334)) * ((int) (56761)))) * (((+(((int) ((unsigned short) (((int) (-7293)) * ((int) (5069))))) * ((int) ((signed char) (((int) (struct_obj_2.member_5_3)) * ((int) (var_16))))))) * (((int) (((int) (var_34)) < ((int) ((short) ((unsigned short) (var_24)))))) & ((~((int) ((short) (var_14)))) & (~(~((int) (var_14))))))) * (((int) (struct_obj_9.member_2_1.member_1_0)) * ((int) (var_31)))))); + } + + if ((~((~(~((int) (var_56)))) | ((((int) (var_43)) >> (((int) (var_13)) + (23914))) >> ((((int) (struct_obj_4.member_2_3.member_1_1)) & ((int) (var_6))) - (35519))))) ^ ((~((int) (struct_obj_8.member_4_1.member_3_1.member_1_2))) & (~(~(((int) (struct_obj_8.member_4_0)) << ((((int) (struct_obj_9.member_2_1.member_1_1)) - (31950)) - (6))))))) + { + short var_430 = (!((~(((int) (var_57)) | ((int) (-5372)))) ^ ((((int) (var_20)) & ((int) (var_18))) | (~((int) (struct_obj_7.member_1_0)))))) && ((int) (struct_obj_4.member_2_6)); + signed char var_431 = (unsigned short) (~(((((int) (struct_obj_4.member_2_5)) ^ ((int) (struct_obj_8.member_4_1.member_3_1.member_1_2))) & (((int) (19)) & ((int) (7794)))) & ((~((int) (var_46))) ^ (~((int) (var_62)))))); + short var_432 = ((((int) (var_28)) - (((int) (-23906)) - (((int) (var_22)) + ((int) (struct_obj_4.member_2_3.member_1_3))))) - (((((int) (var_2)) + ((int) (struct_obj_10.member_1_0))) + (((int) (struct_obj_10.member_1_2)) - ((int) (55916)))) + (-(((int) (var_23)) - ((int) (29449)))))) || ((int) ((signed char) ((~(~((int) (var_48)))) | ((((int) (struct_obj_6.member_5_0)) ^ ((int) (struct_obj_6.member_5_0))) ^ (((int) (55178)) & ((int) (var_56))))))); + signed char var_433 = ((int) (struct_obj_9.member_2_5)) || ((((((int) (27241)) | ((int) (var_51))) & (((int) (84)) | ((int) (-11135)))) | ((int) (struct_obj_3.member_5_0))) | ((int) ((short) (~(((int) (var_17)) | ((int) (3828))))))); + short var_434 = !(((int) ((unsigned short) ((((int) (struct_obj_8.member_4_0)) & ((int) (-2293))) <= (((int) (34)) | ((int) (var_39)))))) << ((((((int) (-29164)) & ((int) (struct_obj_8.member_4_5))) ^ ((int) ((unsigned short) (struct_obj_6.member_5_2)))) >> ((((~((int) (struct_obj_8.member_4_5))) + (2147483647)) >> (((int) (var_2)) - (17779))) - (67108820))) - (364))); + signed char var_435 = ~(~((int) ((signed char) (-(((int) (struct_obj_9.member_2_2)) && ((int) (struct_obj_9.member_2_1.member_1_0))))))); + signed char var_436 = (signed char) ((-((((int) (48727)) << (((((int) (var_51)) + (11808)) - (5)) - (2))) << (((((int) (-23500)) + (2147483647)) >> (((int) (struct_obj_8.member_4_1.member_3_1.member_1_1)) - (25280))) - (1048564)))) < ((int) (struct_obj_7.member_1_0))); + unsigned short var_437 = ((-(-((((int) (-8)) ^ ((int) (65))) & (~((int) (struct_obj_1.member_5_1)))))) + (2147483647)) >> ((int) ((short) (!(!(((int) (115)) && ((int) (14265))))))); + unsigned short var_438 = ~(((((int) ((short) ((short) (var_13)))) || (!((int) (var_48)))) || ((int) ((unsigned short) (!((int) (31752)))))) || ((int) ((short) ((short) (var_13))))); + unsigned short var_439 = ((int) ((unsigned short) ((((((int) (var_42)) + (2147483647)) >> (((int) (struct_obj_9.member_2_4)) - (13535))) & (~((int) (var_56)))) << ((((int) (-17065)) | ((int) ((signed char) (struct_obj_8.member_4_2)))) + (17025))))) & ((~((+(((int) ((unsigned short) (((int) (-7293)) * ((int) (5069))))) * ((int) ((signed char) (((int) (struct_obj_2.member_5_3)) * ((int) (var_16))))))) * (((int) (((int) (var_34)) < ((int) ((short) ((unsigned short) (var_24)))))) & ((~((int) ((short) (var_14)))) & (~(~((int) (var_14)))))))) ^ ((int) (var_40))); + } + + short var_440 = (+((int) (((+(((int) ((unsigned short) (((int) (-7293)) * ((int) (5069))))) * ((int) ((signed char) (((int) (struct_obj_2.member_5_3)) * ((int) (var_16))))))) * (((int) (((int) (var_34)) < ((int) ((short) ((unsigned short) (var_24)))))) & ((~((int) ((short) (var_14)))) & (~(~((int) (var_14))))))) <= ((int) ((unsigned short) (!((int) (var_56)))))))) <= ((int) (((int) ((signed char) (((((((~((int) (36437))) + (2147483647)) << ((((int) (struct_obj_1.member_5_3)) << (((int) (var_2)) - (17781))) - (5920))) & (~((int) ((signed char) (struct_obj_4.member_2_1.member_1_3))))) ^ (((((int) (var_33)) << (((int) (17994)) - (17983))) >> (((int) ((short) (var_20))) + (16020))) ^ (((~((int) (101))) + (2147483647)) >> ((((int) (-7863)) ^ ((int) (struct_obj_4.member_2_4))) - (21936))))) | (~((int) (struct_obj_4.member_2_3.member_1_2)))) / (((int) (var_60)) * ((int) (-77)))))) == ((int) ((((((((~((int) (36437))) + (2147483647)) << ((((int) (struct_obj_1.member_5_3)) << (((int) (var_2)) - (17781))) - (5920))) & (~((int) ((signed char) (struct_obj_4.member_2_1.member_1_3))))) ^ (((((int) (var_33)) << (((int) (17994)) - (17983))) >> (((int) ((short) (var_20))) + (16020))) ^ (((~((int) (101))) + (2147483647)) >> ((((int) (-7863)) ^ ((int) (struct_obj_4.member_2_4))) - (21936))))) | (~((int) (struct_obj_4.member_2_3.member_1_2)))) % ((((((~((int) (36437))) + (2147483647)) << ((((int) (struct_obj_1.member_5_3)) << (((int) (var_2)) - (17781))) - (5920))) & (~((int) ((signed char) (struct_obj_4.member_2_1.member_1_3))))) ^ (((((int) (var_33)) << (((int) (17994)) - (17983))) >> (((int) ((short) (var_20))) + (16020))) ^ (((~((int) (101))) + (2147483647)) >> ((((int) (-7863)) ^ ((int) (struct_obj_4.member_2_4))) - (21936))))) | (~((int) (struct_obj_4.member_2_3.member_1_2))))) >= ((int) ((((int) (var_66)) && ((int) (var_60))) >= (+((int) (var_2))))))))); + short var_441 = struct_obj_3.member_5_0; + if ((((~((int) (var_441))) * (+(((int) (struct_obj_6.member_5_2)) + ((int) (var_60))))) && ((int) ((((int) (struct_obj_6.member_5_0)) && (!((int) (25)))) <= ((int) ((signed char) ((signed char) (var_33))))))) || (((~(((int) (struct_obj_5.member_1_1)) & ((int) (11652)))) & ((+(((int) ((unsigned short) (((int) (-7293)) * ((int) (5069))))) * ((int) ((signed char) (((int) (struct_obj_2.member_5_3)) * ((int) (var_16))))))) * (((int) (((int) (var_34)) < ((int) ((short) ((unsigned short) (var_24)))))) & ((~((int) ((short) (var_14)))) & (~(~((int) (var_14)))))))) | (~((int) ((unsigned short) ((signed char) (var_60))))))) + { + signed char var_442 = ~((((+((int) (var_7))) / (((int) (18532)) * ((int) (var_28)))) * ((int) (struct_obj_1.member_5_3))) * (((((int) (var_18)) * ((int) (struct_obj_6.member_5_1))) / (~((int) (struct_obj_4.member_2_3.member_1_1)))) / ((((int) (64)) * ((int) (-16))) * (((int) (var_31)) * ((int) (65)))))); + signed char var_443 = var_18; + signed char var_444 = ~(~((~(((int) (var_30)) ^ ((int) (struct_obj_8.member_4_4)))) | ((int) ((unsigned short) (~((int) (struct_obj_9.member_2_1.member_1_0))))))); + short var_445 = ((+((((int) (struct_obj_4.member_2_1.member_1_1)) + ((int) (struct_obj_9.member_2_5))) + (((int) (13876)) * ((int) (26471))))) / (-((((int) (12947)) - ((int) (28265))) + (((int) (-30980)) - ((int) (40610)))))) << ((+((int) (((int) ((unsigned short) (var_11))) != ((int) ((signed char) (var_41)))))) >> (((int) ((unsigned short) ((short) (~((int) (struct_obj_4.member_2_0)))))) - (57920))); + short var_446 = ((int) ((~(((int) (31)) || (((int) (struct_obj_5.member_1_3)) && ((int) (var_14))))) > (~((int) (18166))))) > (((int) (((int) ((((int) (4507)) >> (((int) (60479)) - (60459))) > (((int) (14247)) * ((int) (var_44))))) < ((int) ((!((int) (var_15))) <= (+((int) (struct_obj_4.member_2_7))))))) | (~((((int) (15746)) | ((int) (struct_obj_9.member_2_2))) ^ ((int) ((unsigned short) (-5912)))))); + unsigned short var_447 = (+((int) (((int) ((unsigned short) (((int) (-119)) + ((int) (91))))) <= ((((int) (52)) | ((int) (-85))) ^ (((int) (36281)) ^ ((int) (11743))))))) & (~((int) ((short) (((int) ((unsigned short) (5509))) / (((int) (53477)) * ((int) (-1233))))))); + signed char var_448 = (~((int) ((short) (((int) ((short) (var_12))) ^ (~((int) (var_15))))))) | ((int) ((signed char) (~(~((int) ((unsigned short) (var_31))))))); + unsigned short var_449 = (short) ((((int) ((signed char) ((unsigned short) (-9779)))) || ((((int) (var_6)) - (-((+(((int) ((unsigned short) (((int) (-7293)) * ((int) (5069))))) * ((int) ((signed char) (((int) (struct_obj_2.member_5_3)) * ((int) (var_16))))))) * (((int) (((int) (var_34)) < ((int) ((short) ((unsigned short) (var_24)))))) & ((~((int) ((short) (var_14)))) & (~(~((int) (var_14))))))))) % ((int) (var_4)))) && ((((int) ((unsigned short) (2615))) && ((int) ((unsigned short) (-127)))) && ((((int) (var_443)) && ((int) (var_56))) || (((int) (struct_obj_5.member_1_3)) || ((int) (struct_obj_1.member_5_1)))))); + } + else + { + unsigned short var_450 = ((int) ((short) (-(((int) (1)) >> ((+(((int) ((unsigned short) (((int) (-7293)) * ((int) (5069))))) * ((int) ((signed char) (((int) (struct_obj_2.member_5_3)) * ((int) (var_16))))))) * (((int) (((int) (var_34)) < ((int) ((short) ((unsigned short) (var_24)))))) & ((~((int) ((short) (var_14)))) & (~(~((int) (var_14))))))))))) != ((int) ((signed char) ((((int) (var_6)) - (-((+(((int) ((unsigned short) (((int) (-7293)) * ((int) (5069))))) * ((int) ((signed char) (((int) (struct_obj_2.member_5_3)) * ((int) (var_16))))))) * (((int) (((int) (var_34)) < ((int) ((short) ((unsigned short) (var_24)))))) & ((~((int) ((short) (var_14)))) & (~(~((int) (var_14))))))))) % ((int) (var_4))))); + short var_451 = ~((((((int) (var_51)) & ((int) (var_64))) & ((((((~((int) (36437))) + (2147483647)) << ((((int) (struct_obj_1.member_5_3)) << (((int) (var_2)) - (17781))) - (5920))) & (~((int) ((signed char) (struct_obj_4.member_2_1.member_1_3))))) ^ (((((int) (var_33)) << (((int) (17994)) - (17983))) >> (((int) ((short) (var_20))) + (16020))) ^ (((~((int) (101))) + (2147483647)) >> ((((int) (-7863)) ^ ((int) (struct_obj_4.member_2_4))) - (21936))))) | (~((int) (struct_obj_4.member_2_3.member_1_2))))) & (~(((int) (6939)) ^ ((int) (5312))))) & (~((((int) (62)) << (((int) (var_13)) + (23928))) & (((int) (var_3)) | ((int) (struct_obj_6.member_5_3)))))); + unsigned short var_452 = ((((((int) (struct_obj_4.member_2_5)) & ((int) (-26752))) || ((int) ((signed char) (-20709)))) - ((int) (((int) ((unsigned short) (45959))) <= (((int) (var_32)) / ((int) (-65)))))) && (+(((int) (struct_obj_3.member_5_3)) || ((int) ((((int) ((short) (struct_obj_2.member_5_0))) & (((int) (var_21)) | ((int) (var_3)))) != (((int) ((short) (6))) ^ (!((int) (var_26))))))))) >> ((int) (((int) (((int) ((((int) (var_28)) >> (((int) (-22)) + (23))) >= (((int) (var_51)) | ((int) (103))))) != (((int) ((signed char) (var_21))) | ((int) ((unsigned short) (var_60)))))) <= ((int) ((~(+((int) (53974)))) <= ((int) (((((((~((int) (36437))) + (2147483647)) << ((((int) (struct_obj_1.member_5_3)) << (((int) (var_2)) - (17781))) - (5920))) & (~((int) ((signed char) (struct_obj_4.member_2_1.member_1_3))))) ^ (((((int) (var_33)) << (((int) (17994)) - (17983))) >> (((int) ((short) (var_20))) + (16020))) ^ (((~((int) (101))) + (2147483647)) >> ((((int) (-7863)) ^ ((int) (struct_obj_4.member_2_4))) - (21936))))) | (~((int) (struct_obj_4.member_2_3.member_1_2)))) <= ((int) (((int) (19953)) >= ((int) (-25036)))))))))); + short var_453 = ~((int) ((unsigned short) (~((((int) (20)) << (((int) (var_3)) - (54))) << ((((~((int) (35514))) + (35541)) - (3)) - (21)))))); + signed char var_454 = ~(!((int) (((int) ((unsigned short) (((int) (17187)) >= ((int) (3599))))) < (((int) ((short) (var_12))) >> ((~((int) (struct_obj_2.member_5_1))) + (25779)))))); + short var_455 = (((int) ((signed char) ((signed char) (((int) (struct_obj_8.member_4_4)) ^ ((int) (var_452)))))) | (~((int) (struct_obj_4.member_2_3.member_1_3)))) >> ((((((int) ((unsigned short) (124))) & (~((int) (57361)))) << ((~(((int) (93)) ^ ((int) (59)))) + (110))) << ((~(~(~((int) (8))))) + (11))) - (55278)); + unsigned short var_456 = ((int) ((((((((~((int) (36437))) + (2147483647)) << ((((int) (struct_obj_1.member_5_3)) << (((int) (var_2)) - (17781))) - (5920))) & (~((int) ((signed char) (struct_obj_4.member_2_1.member_1_3))))) ^ (((((int) (var_33)) << (((int) (17994)) - (17983))) >> (((int) ((short) (var_20))) + (16020))) ^ (((~((int) (101))) + (2147483647)) >> ((((int) (-7863)) ^ ((int) (struct_obj_4.member_2_4))) - (21936))))) | (~((int) (struct_obj_4.member_2_3.member_1_2)))) ^ ((int) ((signed char) (((int) (63815)) >> (((int) (-65)) + (94)))))) <= ((int) (99)))) & (!((int) ((signed char) ((unsigned short) (((int) (var_20)) >> (((int) (var_35)) - (14412))))))); + signed char var_457 = (!((int) ((signed char) ((((int) (11972)) || ((int) (struct_obj_7.member_1_0))) || (((int) (struct_obj_4.member_2_1.member_1_3)) || ((int) (91))))))) && ((((+(((int) (struct_obj_3.member_5_3)) || ((int) ((((int) ((short) (struct_obj_2.member_5_0))) & (((int) (var_21)) | ((int) (var_3)))) != (((int) ((short) (6))) ^ (!((int) (var_26)))))))) && (((int) (-24193)) || ((int) (struct_obj_4.member_2_1.member_1_0)))) || ((int) (69))) || (!((!((int) (36135))) && (!((int) (-42)))))); + signed char var_458 = ((int) ((signed char) (((((int) (var_441)) & ((int) (-251))) & (((int) (34879)) & ((int) (struct_obj_4.member_2_7)))) & ((((int) (48265)) * ((int) (var_56))) / (~((int) (-71))))))) & ((int) (((-(((int) (62323)) | ((int) (24633)))) & (~(+(((int) (struct_obj_3.member_5_3)) || ((int) ((((int) ((short) (struct_obj_2.member_5_0))) & (((int) (var_21)) | ((int) (var_3)))) != (((int) ((short) (6))) ^ (!((int) (var_26)))))))))) >= ((int) ((signed char) (~(((int) (-16927)) & ((int) (struct_obj_1.member_5_2)))))))); + } + + } + else + { + unsigned short var_459 = ((int) ((-((int) ((short) (((int) (-8)) < ((int) (18519)))))) != ((int) ((short) ((((int) (10757)) | ((int) (16517))) ^ (~((int) (8440)))))))) ^ ((int) (var_52)); + unsigned short var_460 = (-(~((int) (((int) (((int) (((int) (struct_obj_4.member_2_7)) > ((~((int) (struct_obj_4.member_2_0))) | ((int) ((short) (var_35)))))) > (~(~(((int) (39209)) ^ ((int) (struct_obj_4.member_2_1.member_1_3))))))) != ((int) (((int) ((short) (((int) (((int) (var_14)) == ((int) (struct_obj_3.member_5_2)))) * ((int) (((int) (struct_obj_4.member_2_3.member_1_3)) >= ((int) (56773))))))) <= (((((int) (var_13)) + (2147483647)) >> (((int) ((short) (-14702))) + (14731))) << (((int) (struct_obj_2.member_5_1)) - (25749))))))))) == ((int) (((int) ((signed char) ((((int) (var_20)) << (((int) (var_40)) - (63))) == ((((int) (struct_obj_5.member_1_0)) + (2147483647)) << (((int) (31224)) - (31224)))))) <= (!((((int) (struct_obj_10.member_1_2)) * ((int) (63260))) / (((int) (struct_obj_8.member_4_3)) * ((int) (23510))))))); + unsigned short var_461 = (((int) ((signed char) ((((int) (var_42)) ^ ((int) (var_55))) >> ((((int) (var_45)) & ((int) (25562))) - (25483))))) & ((int) (((int) (((int) (((int) (struct_obj_4.member_2_7)) > ((~((int) (struct_obj_4.member_2_0))) | ((int) ((short) (var_35)))))) > (~(~(((int) (39209)) ^ ((int) (struct_obj_4.member_2_1.member_1_3))))))) != ((int) (((int) ((short) (((int) (((int) (var_14)) == ((int) (struct_obj_3.member_5_2)))) * ((int) (((int) (struct_obj_4.member_2_3.member_1_3)) >= ((int) (56773))))))) <= (((((int) (var_13)) + (2147483647)) >> (((int) ((short) (-14702))) + (14731))) << (((int) (struct_obj_2.member_5_1)) - (25749)))))))) > (-((int) (struct_obj_1.member_5_3))); + unsigned short var_462 = ((int) (var_49)) * ((~(-(((int) (-125)) * ((int) (struct_obj_6.member_5_0))))) / ((int) ((unsigned short) ((short) (((int) (var_21)) * ((int) (var_2))))))); + if ((unsigned short) (~(~((int) (((int) (((int) (((int) (struct_obj_4.member_2_7)) > ((~((int) (struct_obj_4.member_2_0))) | ((int) ((short) (var_35)))))) > (~(~(((int) (39209)) ^ ((int) (struct_obj_4.member_2_1.member_1_3))))))) != ((int) (((int) ((short) (((int) (((int) (var_14)) == ((int) (struct_obj_3.member_5_2)))) * ((int) (((int) (struct_obj_4.member_2_3.member_1_3)) >= ((int) (56773))))))) <= (((((int) (var_13)) + (2147483647)) >> (((int) ((short) (-14702))) + (14731))) << (((int) (struct_obj_2.member_5_1)) - (25749)))))))))) + { + signed char var_463 = (short) (((int) ((short) (((int) (var_6)) != (~((int) (var_17)))))) > (((int) ((short) (((int) (125)) * ((int) (struct_obj_4.member_2_0))))) / (~(((int) (struct_obj_8.member_4_7)) * ((int) (struct_obj_9.member_2_1.member_1_0)))))); + signed char var_464 = (unsigned short) (((int) ((((int) (var_239)) || (((int) (7)) && ((int) (-32493)))) != (((int) ((signed char) (var_10))) && (-((int) (var_14)))))) & (((~((((int) (-16750)) + (2147483647)) << ((int) (var_49)))) + (2147483647)) >> (((((int) (struct_obj_1.member_5_2)) | ((int) (struct_obj_2.member_5_1))) | (((int) (var_38)) & ((int) (5832)))) - (65230)))); + short var_465 = (unsigned short) ((!((int) (struct_obj_4.member_2_1.member_1_3))) * ((-(((int) (-30177)) * ((int) (var_61)))) * ((~((int) (struct_obj_4.member_2_1.member_1_1))) / (((int) (5831)) * ((int) (var_40)))))); + var_53 = (short) (((int) (var_23)) < ((int) ((-(((((int) (-65)) + (2147483647)) >> (((int) (-13186)) + (13192))) || ((int) (((int) (((int) (((int) (struct_obj_4.member_2_7)) > ((~((int) (struct_obj_4.member_2_0))) | ((int) ((short) (var_35)))))) > (~(~(((int) (39209)) ^ ((int) (struct_obj_4.member_2_1.member_1_3))))))) != ((int) (((int) ((short) (((int) (((int) (var_14)) == ((int) (struct_obj_3.member_5_2)))) * ((int) (((int) (struct_obj_4.member_2_3.member_1_3)) >= ((int) (56773))))))) <= (((((int) (var_13)) + (2147483647)) >> (((int) ((short) (-14702))) + (14731))) << (((int) (struct_obj_2.member_5_1)) - (25749))))))))) < ((((int) (-21429)) + (2147483647)) >> ((!((int) (16614))) && ((int) (13925))))))); + signed char var_466 = (~(~(~(~((int) (8094)))))) ^ ((int) ((short) (~((int) ((signed char) (~((int) (-104)))))))); + signed char var_467 = ((int) ((signed char) (~((int) ((signed char) (~((int) (struct_obj_2.member_5_1)))))))) | (~((int) ((short) (-42)))); + var_468 = (signed char) (((!((int) (struct_obj_4.member_2_3.member_1_3))) * ((int) ((unsigned short) ((((int) (struct_obj_8.member_4_7)) * ((int) (65006))) / (-((int) (struct_obj_8.member_4_1.member_3_1.member_1_1))))))) < (~(((((int) (struct_obj_8.member_4_9.member_1_0)) ^ ((int) (struct_obj_5.member_1_0))) ^ (((int) (2436)) | ((int) (var_37)))) ^ (~(~((int) (var_467))))))); + } + + } + + } + + short var_469 = (~(((int) ((unsigned short) (var_36))) & (((int) ((unsigned short) (var_18))) & (~((int) (struct_obj_2.member_5_0)))))) ^ ((int) ((short) (~((((int) (var_10)) >> (((int) (struct_obj_2.member_5_1)) - (25743))) << ((~((int) (var_49))) + (31)))))); + signed char var_470 = (~(~((int) ((signed char) ((unsigned short) (var_9)))))) != ((((((int) (-2067)) ^ ((int) (struct_obj_8.member_4_4))) ^ (~((int) (var_49)))) | (((~((int) (28770))) + (2147483647)) << (((((((int) (var_45)) | ((int) (var_27))) + (29)) - (25)) - (0)) - (1)))) << ((((int) (var_65)) + (12873)) - (27))); + unsigned short var_471 = var_26; + unsigned short var_472 = -(-(((int) (59835)) + ((int) (15808)))); + if ((unsigned short) ((~((((int) (-18340)) ^ ((int) (-18253))) ^ (~((int) (-24880))))) | ((int) (-126)))) + { + unsigned short var_473 = ((~((((int) (struct_obj_1.member_5_2)) * ((int) (5330))) / (((int) (struct_obj_1.member_5_2)) * ((int) (101))))) * ((int) (struct_obj_8.member_4_3))) | (+(((int) (7754)) + ((((int) (struct_obj_2.member_5_3)) * ((int) (var_48))) - ((int) (struct_obj_3.member_5_2))))); + if ((~((int) ((unsigned short) ((unsigned short) (-((int) (15894))))))) >= (!(((!((int) (12826))) * (((int) (127)) * ((int) (var_36)))) * ((int) ((signed char) (((int) (-15438)) * ((int) (var_32)))))))) + { + unsigned short var_474 = ((int) (struct_obj_3.member_5_2)) ^ (!((int) (((int) ((signed char) (((int) (struct_obj_6.member_5_3)) * ((int) (var_4))))) <= ((int) (((int) ((signed char) (var_12))) < (((int) (46)) * ((int) (37)))))))); + short var_475 = (short) ((((((int) (var_25)) | ((int) (-14169))) ^ (((int) (var_8)) ^ ((int) (4475)))) | ((((int) (var_28)) ^ ((int) (var_15))) & (~((int) (var_29))))) < ((((int) (var_11)) >> (((int) (var_13)) ^ ((int) (var_13)))) | ((int) (struct_obj_3.member_5_2)))); + unsigned short var_476 = ((int) (10092)) > ((int) ((((int) (((int) (((int) (struct_obj_8.member_4_1.member_3_1.member_1_0)) <= ((int) (struct_obj_6.member_5_0)))) == (~((int) (17336))))) & (((((int) (-11297)) + (2147483647)) >> (((int) (var_52)) - (9862))) & ((int) (var_63)))) > ((~((int) (struct_obj_8.member_4_1.member_3_1.member_1_0))) ^ ((~((int) (struct_obj_9.member_2_7))) | (((int) (-28444)) ^ ((int) (2438))))))); + unsigned short var_477 = ((int) (struct_obj_9.member_2_1.member_1_3)) << ((~(~((((int) (var_50)) | ((int) (struct_obj_8.member_4_1.member_3_1.member_1_0))) & ((int) ((signed char) (-123)))))) + (132)); + unsigned short var_478 = ((~((int) ((unsigned short) ((((int) (62522)) * ((int) (struct_obj_3.member_5_1))) - ((int) (124)))))) + (2147483647)) >> (((int) (struct_obj_3.member_5_2)) - (59812)); + unsigned short var_479 = ~((int) ((((int) (((int) ((signed char) (21844))) <= ((int) (((int) (var_18)) <= ((int) (var_24)))))) & ((~((int) (var_26))) % (((int) (46805)) && ((int) (var_469))))) != (((int) (struct_obj_3.member_5_2)) - (((int) ((short) ((((((int) (var_25)) | ((int) (-14169))) ^ (((int) (var_8)) ^ ((int) (4475)))) | ((((int) (var_28)) ^ ((int) (var_15))) & (~((int) (var_29))))) < ((((int) (var_11)) >> (((int) (var_13)) ^ ((int) (var_13)))) | ((int) (struct_obj_3.member_5_2)))))) - ((int) (struct_obj_9.member_2_1.member_1_1)))))); + short var_480 = ((+((((int) (8636)) - ((int) (-105))) + (((int) (-27878)) - ((int) (61359))))) && (~((~((int) (var_28))) | ((int) ((short) (18641)))))) && ((int) ((signed char) ((~(((int) (-99)) * ((int) (96)))) / (((int) (10930)) * ((int) (-99)))))); + if ((((int) (struct_obj_8.member_4_2)) && ((int) ((short) ((short) ((((((int) (var_25)) | ((int) (-14169))) ^ (((int) (var_8)) ^ ((int) (4475)))) | ((((int) (var_28)) ^ ((int) (var_15))) & (~((int) (var_29))))) < ((((int) (var_11)) >> (((int) (var_13)) ^ ((int) (var_13)))) | ((int) (struct_obj_3.member_5_2)))))))) || (!((int) ((short) ((!((int) (889))) && (((int) (var_29)) && ((int) (86)))))))) + { + signed char var_481 = ~(~(((((int) (struct_obj_4.member_2_3.member_1_0)) * ((int) (var_4))) * (~((int) (17223)))) / (~(((int) (545)) * ((int) (var_44)))))); + short var_482 = ((~(~(((int) (var_479)) >> (((int) (struct_obj_8.member_4_1.member_3_0)) - (649))))) | ((((~((int) (struct_obj_4.member_2_0))) + (2147483647)) >> ((((int) (var_481)) ^ ((int) (var_64))) + (63))) << (((~(((int) (struct_obj_9.member_2_1.member_1_0)) | ((int) (var_471)))) + (14662)) - (23)))) & (~(((((int) (-26622)) & ((int) (13554))) ^ ((int) (47104))) | ((((int) (12106)) ^ ((int) (29))) & (((int) (15902)) | ((int) (40455)))))); + signed char var_483 = -(((((int) ((short) ((((((int) (var_25)) | ((int) (-14169))) ^ (((int) (var_8)) ^ ((int) (4475)))) | ((((int) (var_28)) ^ ((int) (var_15))) & (~((int) (var_29))))) < ((((int) (var_11)) >> (((int) (var_13)) ^ ((int) (var_13)))) | ((int) (struct_obj_3.member_5_2)))))) - (((int) (struct_obj_8.member_4_2)) - ((int) (struct_obj_8.member_4_1.member_3_1.member_1_0)))) + (-((int) ((unsigned short) (struct_obj_1.member_5_3))))) - ((-(((int) (var_470)) - ((int) (-23)))) - ((((int) (-24447)) - ((int) (var_33))) - (((int) (struct_obj_7.member_1_2)) + ((int) (99)))))); + unsigned short var_484 = ~((((int) (var_469)) * ((int) ((signed char) (((int) (var_8)) * ((int) (var_17)))))) * (-((-((int) (-8))) / (((int) (struct_obj_8.member_4_6)) * ((int) (struct_obj_4.member_2_3.member_1_3)))))); + unsigned short var_485 = ((int) ((signed char) (!(!((int) ((unsigned short) (var_6))))))) % ((int) ((signed char) (struct_obj_3.member_5_2))); + short var_486 = (signed char) (!((((int) (struct_obj_3.member_5_2)) * ((int) ((short) (var_1)))) / (-(+((int) (-32650)))))); + var_41 = (unsigned short) (~((int) (struct_obj_3.member_5_2))); + unsigned short var_487 = !(((~((int) ((signed char) (var_48)))) + ((int) ((signed char) (!((((int) (struct_obj_3.member_5_2)) * ((int) ((short) (var_1)))) / (-(+((int) (-32650))))))))) & ((int) (((int) (var_61)) >= ((int) ((unsigned short) (var_28)))))); + signed char var_488 = ((((((int) (21529)) ^ ((int) (4132))) | ((int) ((signed char) (!((((int) (struct_obj_3.member_5_2)) * ((int) ((short) (var_1)))) / (-(+((int) (-32650))))))))) & (~(~((int) (var_49))))) ^ ((~(((int) (struct_obj_8.member_4_1.member_3_0)) | ((int) (-6)))) ^ (~(((int) (var_10)) | ((int) (var_55)))))) & ((((((int) (28)) ^ ((int) (34913))) | (((int) (27968)) & ((int) (-10524)))) & ((int) (-28484))) & ((int) ((unsigned short) (91)))); + signed char var_489 = -63; + } + else + { + short var_490 = (((((int) ((signed char) (var_41))) * ((int) ((short) ((((((int) (var_25)) | ((int) (-14169))) ^ (((int) (var_8)) ^ ((int) (4475)))) | ((((int) (var_28)) ^ ((int) (var_15))) & (~((int) (var_29))))) < ((((int) (var_11)) >> (((int) (var_13)) ^ ((int) (var_13)))) | ((int) (struct_obj_3.member_5_2))))))) * (!((int) ((short) ((((((int) (var_25)) | ((int) (-14169))) ^ (((int) (var_8)) ^ ((int) (4475)))) | ((((int) (var_28)) ^ ((int) (var_15))) & (~((int) (var_29))))) < ((((int) (var_11)) >> (((int) (var_13)) ^ ((int) (var_13)))) | ((int) (struct_obj_3.member_5_2)))))))) * (((int) ((((int) (-53)) * ((int) (var_46))) <= ((int) (var_51)))) & ((((int) (var_2)) ^ ((int) (var_60))) % (((int) (var_45)) || ((int) (18)))))) >= ((((int) (-108)) & (((int) ((unsigned short) (var_29))) / (((int) (-6368)) * ((int) (53451))))) & (((int) (((int) ((unsigned short) (var_48))) >= (((int) (64011)) + ((int) (struct_obj_4.member_2_3.member_1_3))))) ^ ((((int) (var_20)) + ((int) (-88))) + (((int) (var_61)) || ((int) (9688)))))); + unsigned short var_491 = ((int) (var_33)) >> ((int) ((((int) ((short) (+((int) (struct_obj_1.member_5_3))))) * (((-(((int) (var_28)) * ((int) (struct_obj_2.member_5_3)))) * (((int) ((short) (var_14))) / (((int) (16571)) * ((int) (59287))))) * ((int) (43731)))) < (((((int) (struct_obj_4.member_2_6)) / ((int) (var_66))) * ((int) ((short) ((((((int) (var_25)) | ((int) (-14169))) ^ (((int) (var_8)) ^ ((int) (4475)))) | ((((int) (var_28)) ^ ((int) (var_15))) & (~((int) (var_29))))) < ((((int) (var_11)) >> (((int) (var_13)) ^ ((int) (var_13)))) | ((int) (struct_obj_3.member_5_2))))))) & (~(~((int) (struct_obj_9.member_2_7))))))); + short var_492 = (((int) ((short) (~(((int) (-93)) || ((int) (-125)))))) || ((int) ((~(((int) (struct_obj_4.member_2_6)) >> (((int) (struct_obj_8.member_4_6)) + (13828)))) == ((int) (struct_obj_8.member_4_7))))) >> ((int) (((((int) (31254)) << (((((int) (-32124)) ^ ((int) (21005))) + (12173)) - (11))) >> ((int) (struct_obj_8.member_4_9.member_1_0))) > (-((int) ((((int) (var_59)) | ((int) (var_490))) <= (((int) (var_65)) & ((int) (var_19)))))))); + unsigned short var_493 = ((int) ((unsigned short) (!(((int) (((int) (var_490)) >= ((int) (-22338)))) && (~((int) (struct_obj_8.member_4_6))))))) > (((int) (((int) ((~((int) (-5961))) < ((int) (var_58)))) < ((((int) (27882)) + ((int) (-8226))) | (~((int) (var_22)))))) & (!((int) (var_7)))); + short var_494 = (unsigned short) (~((int) (((int) (15)) < ((~((int) (-9))) % ((int) ((short) (61065))))))); + } + + if (((((((int) (-6660)) & ((int) (11))) | (((int) (27466)) | ((int) (-98)))) & ((((int) (43475)) & ((int) (20006))) ^ ((int) ((signed char) (28278))))) ^ (~(((int) (-60)) ^ (~((int) (28567)))))) | ((((int) (struct_obj_3.member_5_1)) & (~((int) ((unsigned short) (var_476))))) | ((~(((int) (struct_obj_8.member_4_6)) ^ ((int) (struct_obj_10.member_1_3)))) ^ ((((int) (var_476)) ^ ((int) (struct_obj_8.member_4_9.member_1_0))) & ((int) ((signed char) (struct_obj_1.member_5_2))))))) + { + signed char var_495 = -(~(~(((int) (39754)) || ((int) ((unsigned short) (10557)))))); + unsigned short var_496 = (~(~((int) (((int) (((int) (40028)) < ((int) (46)))) >= (((int) (-9194)) || ((int) (-122))))))) != (((int) (19860)) % ((int) ((signed char) (-((int) (var_20)))))); + unsigned short var_497 = (-(((((int) (struct_obj_4.member_2_6)) / ((int) (var_479))) - (((int) (9407)) + ((int) (var_35)))) * (+((int) ((unsigned short) (25874)))))) && ((int) ((((int) ((short) (struct_obj_8.member_4_5))) & (~(((int) (struct_obj_1.member_5_3)) | ((int) (var_26))))) != (((int) ((short) ((((((int) (var_25)) | ((int) (-14169))) ^ (((int) (var_8)) ^ ((int) (4475)))) | ((((int) (var_28)) ^ ((int) (var_15))) & (~((int) (var_29))))) < ((((int) (var_11)) >> (((int) (var_13)) ^ ((int) (var_13)))) | ((int) (struct_obj_3.member_5_2)))))) * (((int) ((short) (var_17))) * ((int) ((signed char) (var_54))))))); + signed char var_498 = ((int) (((int) ((short) ((((int) (var_11)) && ((int) (struct_obj_10.member_1_2))) && (!((int) (12032)))))) < (((-((int) (struct_obj_9.member_2_4))) * ((int) ((signed char) (-((int) (var_20)))))) >> ((((int) (var_495)) & ((int) (var_29))) & (!((int) (struct_obj_4.member_2_1.member_1_3))))))) != (((int) ((unsigned short) (~((int) (var_51))))) ^ ((((int) ((short) (struct_obj_1.member_5_3))) ^ (~((int) (struct_obj_4.member_2_1.member_1_0)))) | (((int) ((short) (var_32))) ^ ((int) ((signed char) (struct_obj_4.member_2_1.member_1_1)))))); + signed char var_499 = ((int) (-23634)) >= (~((~(~((int) (struct_obj_3.member_5_2)))) & ((int) (var_58)))); + } + else + { + var_500 = (signed char) (-107); + short var_501 = (signed char) (((int) (((((int) (-24644)) * ((int) (-5259))) * (!((int) (-106)))) >= (~((int) ((short) (23525)))))) * (((int) (((int) ((short) (7351))) != ((int) ((short) (12121))))) * ((int) (-13473)))); + var_52 = (short) (~((int) (var_474))); + unsigned short var_502 = ((int) ((signed char) (-((int) (var_20))))) < ((int) ((short) ((+(((int) (var_66)) + ((int) (var_51)))) - (-(((int) (var_476)) + ((int) (var_16))))))); + short var_503 = struct_obj_3.member_5_2; + short var_504 = var_32; + unsigned short var_505 = ((int) ((unsigned short) (((((int) (var_43)) * ((int) (585))) / ((int) ((signed char) (struct_obj_5.member_1_0)))) * (((int) ((unsigned short) (struct_obj_2.member_5_3))) / (((int) (var_10)) * ((int) (22670))))))) * ((+((int) ((signed char) (((int) (61178)) / ((int) (63555)))))) * (!((!((int) (var_469))) * (-((int) (var_25)))))); + } + + } + + signed char var_506 = var_31; + unsigned short var_507 = (((int) (var_26)) | (~((int) (var_47)))) % ((~(-(((int) (var_43)) * ((int) (33232))))) & (((int) (((int) (((int) (27)) >= ((int) (-76)))) != ((int) (((int) (5702)) != ((int) (-95)))))) + ((int) (2753)))); + if (!((int) (((int) ((~(((int) (28215)) || ((int) (17957)))) <= ((((int) (51658)) ^ ((int) (23571))) & (((int) (53850)) ^ ((int) (-59)))))) >= ((int) ((signed char) ((((int) (struct_obj_10.member_1_2)) / ((int) (struct_obj_1.member_5_1))) % ((int) (var_29)))))))) + { + if (-((int) ((~((~((int) (123))) - (~((int) (var_33))))) == (((int) (((int) (((int) (var_16)) >= ((int) (struct_obj_6.member_5_1)))) != (((int) (var_3)) | ((int) (struct_obj_8.member_4_1.member_3_1.member_1_2))))) & (~((int) (7351))))))) + { + signed char var_508 = (signed char) (((int) (struct_obj_3.member_5_2)) & ((int) (var_58))); + short var_509 = (+((!((int) ((unsigned short) (-21610)))) >> (((int) ((signed char) (((int) (struct_obj_8.member_4_5)) * ((int) (113))))) + (81)))) % ((((int) ((signed char) ((signed char) (((int) (37329)) | ((int) (93)))))) + (2147483647)) << ((((int) ((unsigned short) ((((int) (6310)) << (((int) (32576)) - (32569))) | (((int) (49981)) >> (((int) (-4570)) + (4580)))))) - (21295)) - (1))); + signed char var_510 = ((int) (var_26)) <= ((int) (((int) ((((int) ((-((int) ((short) (-4355)))) < (-((int) (struct_obj_3.member_5_2))))) - (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) || ((~((int) (-19743))) * (((int) (58561)) / ((int) (40662)))))) <= ((int) ((signed char) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) <= ((((int) (49)) ^ ((int) (7553))) & ((int) ((signed char) (23467))))))))) <= ((int) (((!((int) (var_52))) - (((int) (var_31)) | ((int) (var_23)))) == ((int) ((signed char) (-((int) (-2995))))))))); + signed char var_511 = ~(((int) ((short) ((~((int) (-11638))) & (((int) (8453)) & ((int) (-22258)))))) ^ (~(~((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475))))))))))))); + unsigned short var_512 = (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) >> (((int) (struct_obj_9.member_2_1.member_1_1)) - (31954))) != ((int) ((((int) (struct_obj_4.member_2_5)) || (!((int) ((signed char) (var_44))))) < ((int) ((unsigned short) (((int) (((int) (-26302)) == ((int) (20343)))) > ((int) ((short) (-28144)))))))); + short var_513 = ((int) ((unsigned short) (-16))) * ((int) (var_16)); + var_514 = (short) (~(((~((int) (struct_obj_3.member_5_2))) & (~(~((int) (var_20))))) ^ (((int) (struct_obj_4.member_2_3.member_1_2)) & ((int) (struct_obj_8.member_4_9.member_1_2))))); + short var_515 = ~((int) ((short) ((unsigned short) ((signed char) (((int) (var_19)) ^ ((int) (var_12))))))); + signed char var_516 = -((int) (var_66)); + unsigned short var_517 = struct_obj_1.member_5_0; + } + else + { + short var_518 = var_19; + unsigned short var_519 = (short) (((int) ((short) (+((int) ((unsigned short) (var_12)))))) & (((!((int) (var_35))) | ((int) (((int) (var_7)) < ((int) (struct_obj_4.member_2_1.member_1_3))))) || (~((int) (((int) (17060)) <= ((int) (10237))))))); + unsigned short var_520 = (((int) ((((((int) (-30670)) + (2147483647)) << (((((int) (-18058)) + (18075)) - (16)) - (1))) - (((int) (-4556)) & ((int) (-56)))) < ((((int) (struct_obj_6.member_5_3)) && ((int) (struct_obj_7.member_1_0))) || ((int) (var_27))))) + ((int) (struct_obj_8.member_4_5))) - (~((int) ((unsigned short) ((((int) (6497)) - ((int) (var_56))) & (-((int) (var_29))))))); + signed char var_521 = (unsigned short) (~((int) (struct_obj_3.member_5_2))); + var_522 = (signed char) ((((+(+(+((int) (45430))))) + (((int) (-2768)) * ((int) ((signed char) (((int) (24766)) * ((int) (6852))))))) + (2147483647)) << (((((((int) (-103)) + (108)) - (4)) - (0)) - (0)) - (1))); + short var_523 = ((~((int) ((!((int) (((int) (7275)) > ((int) (3644))))) == ((((int) (12413)) << (((int) (19590)) - (19580))) >> ((((int) (115)) & ((int) (55843))) - (26)))))) + (2147483647)) >> (((-(+(+((int) (var_507))))) - ((((int) ((short) (var_61))) + (((int) (42857)) + ((int) (var_1)))) - ((-((int) (var_7))) * ((int) (16))))) + (110426)); + short var_524 = (~(~((((int) (var_30)) ^ ((int) (struct_obj_8.member_4_4))) & (((int) (var_40)) ^ ((int) (struct_obj_4.member_2_6)))))) > (~((~(((int) (var_1)) * ((int) (var_520)))) / ((((int) (struct_obj_5.member_1_0)) * ((int) (struct_obj_8.member_4_6))) / ((int) ((short) (struct_obj_10.member_1_3)))))); + signed char var_525 = (((int) ((signed char) (!(((int) (126)) & ((int) (var_36)))))) & (((int) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) > ((int) ((~(+((int) (28029)))) <= ((int) ((unsigned short) (((int) (-1114)) ^ ((int) (struct_obj_4.member_2_6))))))))) - (((int) ((short) (((~((int) (1416))) + (2147483647)) >> (((int) (-93)) + (101))))) && (((((int) (24281)) & ((int) (struct_obj_4.member_2_1.member_1_1))) >> ((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475))))))))))) >> (((int) (var_30)) - (42699)))))) || (((int) (((((int) ((unsigned short) (~((int) (8))))) >> (((int) (25621)) - (25605))) | (((~((int) (var_31))) << (((((int) (struct_obj_4.member_2_4)) + (2147483647)) << ((((int) (-62)) + (71)) - (9))) - (2147464435))) >> (((int) (4111)) >> (((int) (19804)) - (19790))))) >= (((((int) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) > ((int) ((~(+((int) (28029)))) <= ((int) ((unsigned short) (((int) (-1114)) ^ ((int) (struct_obj_4.member_2_6))))))))) - (((int) ((short) (((~((int) (1416))) + (2147483647)) >> (((int) (-93)) + (101))))) && (((((int) (24281)) & ((int) (struct_obj_4.member_2_1.member_1_1))) >> ((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475))))))))))) >> (((int) (var_30)) - (42699))))) & ((int) (var_3))) & (!(!(((int) (struct_obj_4.member_2_4)) && ((int) (var_3)))))))) | ((~(~((int) (9)))) & ((((int) (16613)) ^ ((int) (-20))) ^ (~((int) (-10292)))))); + var_36 = (short) (((~((!((int) (-104))) * (((int) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) > ((int) ((~(+((int) (28029)))) <= ((int) ((unsigned short) (((int) (-1114)) ^ ((int) (struct_obj_4.member_2_6))))))))) - (((int) ((short) (((~((int) (1416))) + (2147483647)) >> (((int) (-93)) + (101))))) && (((((int) (24281)) & ((int) (struct_obj_4.member_2_1.member_1_1))) >> ((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475))))))))))) >> (((int) (var_30)) - (42699))))))) * (-((int) ((unsigned short) (((int) (struct_obj_1.member_5_1)) * ((int) (10162))))))) || ((int) (struct_obj_5.member_1_0))); + } + + signed char var_526 = (((int) ((((int) ((-((int) ((short) (-4355)))) < (-((int) (struct_obj_3.member_5_2))))) - (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) || ((~((int) (-19743))) * (((int) (58561)) / ((int) (40662)))))) <= ((int) ((signed char) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) <= ((((int) (49)) ^ ((int) (7553))) & ((int) ((signed char) (23467))))))))) && ((int) (27198))) % ((((int) ((((int) (57392)) & ((int) (50780))) == ((int) ((short) (54035))))) & (+((int) (((int) (13979)) <= ((int) (5855)))))) || ((((int) (6763)) + ((int) (39071))) + ((int) (struct_obj_3.member_5_2)))); + var_64 = (signed char) ((signed char) (!(~((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475))))))))))))); + if ((~(((((int) (struct_obj_4.member_2_3.member_1_0)) || ((int) (30335))) % (((int) (var_43)) || ((int) (25266)))) | (+(+((int) (var_52)))))) <= ((int) ((signed char) (((~((int) (struct_obj_8.member_4_7))) | (((int) (var_61)) | ((int) (var_5)))) | (((int) ((short) (struct_obj_6.member_5_3))) ^ (((int) (struct_obj_1.member_5_2)) & ((int) (struct_obj_6.member_5_1)))))))) + { + signed char var_527 = ((!((int) (struct_obj_3.member_5_2))) && ((int) (var_41))) >= ((((int) (struct_obj_3.member_5_2)) | ((int) ((((int) (struct_obj_4.member_2_1.member_1_3)) - ((int) (19837))) != (!((int) (struct_obj_10.member_1_3)))))) + (((~((int) (var_64))) ^ ((int) (var_37))) & (~(((int) (struct_obj_8.member_4_1.member_3_1.member_1_1)) | ((int) (var_62)))))); + short var_528 = struct_obj_9.member_2_0; + signed char var_529 = (((int) (struct_obj_3.member_5_2)) || ((((int) ((signed char) (var_17))) || (((int) (var_38)) && ((int) (var_36)))) || ((int) ((short) (((int) (var_3)) && ((int) (var_15))))))) != (!((int) ((signed char) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))))); + short var_530 = !((int) ((signed char) ((short) (~(((int) (-6761)) * ((int) (var_527))))))); + unsigned short var_531 = (((int) ((-((int) ((short) (-4355)))) < (-((int) (struct_obj_3.member_5_2))))) - (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) || ((~((int) (-19743))) * (((int) (58561)) / ((int) (40662)))))) <= ((int) ((signed char) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) <= ((((int) (49)) ^ ((int) (7553))) & ((int) ((signed char) (23467))))))); + } + + if ((-(((int) ((short) (((int) (var_507)) * ((int) (var_59))))) * (+(((int) (var_63)) * ((int) (var_526)))))) + (((+((int) ((unsigned short) (76)))) + ((int) ((unsigned short) (+((int) (11621)))))) * (((int) (95)) + ((int) ((((int) ((-((int) ((short) (-4355)))) < (-((int) (struct_obj_3.member_5_2))))) - (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) || ((~((int) (-19743))) * (((int) (58561)) / ((int) (40662)))))) <= ((int) ((signed char) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) <= ((((int) (49)) ^ ((int) (7553))) & ((int) ((signed char) (23467)))))))))))) + { + unsigned short var_532 = ((int) (((int) ((short) ((((int) (23716)) << (((int) (var_38)) - (38))) || (~((int) (var_47)))))) < (((int) ((unsigned short) (25887))) | ((-((int) (41298))) - ((int) (((int) (-91)) > ((int) (35354)))))))) + ((int) ((((int) (((int) (((int) (-71)) == ((int) (struct_obj_6.member_5_3)))) < (~((int) (var_18))))) >> ((~(!((int) (struct_obj_3.member_5_1)))) + (27))) > ((-((int) (((int) (struct_obj_3.member_5_0)) <= ((int) (var_6))))) - ((int) ((signed char) (((int) (65033)) + ((int) (struct_obj_3.member_5_0)))))))); + short var_533 = (short) ((((((int) (struct_obj_9.member_2_1.member_1_3)) >> ((int) (var_470))) << (((int) (-34)) + (50))) || (((int) ((signed char) (30726))) / (((int) (struct_obj_8.member_4_4)) + ((int) (struct_obj_4.member_2_4))))) * ((int) (((int) (struct_obj_9.member_2_7)) != (((int) (var_27)) + (((int) (struct_obj_2.member_5_1)) || ((int) (struct_obj_8.member_4_6))))))); + short var_534 = ~((!((!((int) (-8725))) * (((int) (var_18)) * ((int) (var_24))))) * ((int) ((unsigned short) (12434)))); + unsigned short var_535 = (short) (((int) ((unsigned short) ((signed char) (((int) (var_27)) || ((int) (var_24)))))) && ((!(!((int) (var_17)))) && ((int) ((short) (((int) (-42)) || ((int) (32757))))))); + signed char var_536 = ~((int) (struct_obj_4.member_2_3.member_1_2)); + var_62 = (unsigned short) (var_10); + signed char var_537 = ((int) (((int) ((~(~((int) (49907)))) != (((int) (((int) (-19054)) <= ((int) (var_43)))) + ((int) ((signed char) (17511)))))) == ((int) (10634)))) < (((int) (struct_obj_6.member_5_3)) - ((int) (((int) ((((int) (var_64)) * ((int) (var_21))) >= (((int) (var_26)) || ((int) (struct_obj_9.member_2_2))))) < ((int) (var_53))))); + unsigned short var_538 = +((int) (var_470)); + signed char var_539 = var_27; + } + else + { + unsigned short var_540 = (signed char) (((int) ((signed char) (~(!((int) (-16)))))) | (~(-((int) (((int) (7587)) <= ((int) (var_45))))))); + unsigned short var_541 = !((((((int) ((signed char) (-121))) + (2147483647)) >> ((int) ((((int) ((-((int) ((short) (-4355)))) < (-((int) (struct_obj_3.member_5_2))))) - (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) || ((~((int) (-19743))) * (((int) (58561)) / ((int) (40662)))))) <= ((int) ((signed char) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) <= ((((int) (49)) ^ ((int) (7553))) & ((int) ((signed char) (23467)))))))))) || (~(((int) (struct_obj_4.member_2_3.member_1_1)) * ((int) (var_469))))) || (!((int) ((short) (((int) (-12)) * ((int) (18))))))); + short var_542 = -(+((int) (var_27))); + var_543 = (signed char) ((-(((((int) (64835)) >> (((int) (1187)) - (1187))) >> ((~((int) (var_25))) + (149))) >> (((int) ((short) (((int) (struct_obj_7.member_1_2)) | ((int) (struct_obj_4.member_2_1.member_1_1))))) + (128)))) / ((int) ((((~((int) (struct_obj_4.member_2_3.member_1_3))) | (~((int) (-17256)))) & ((int) (struct_obj_8.member_4_1.member_3_1.member_1_0))) != (~(-((int) ((signed char) (var_2)))))))); + var_544 = (unsigned short) ((((+(((int) (var_42)) * ((int) (struct_obj_4.member_2_3.member_1_3)))) - ((int) ((short) ((unsigned short) (117))))) + ((int) ((short) ((((int) (106)) * ((int) (12343))) - (((int) (6)) + ((int) (var_53))))))) > ((-((((int) (var_13)) * ((int) (19559))) * (((int) (var_469)) * ((int) (var_46))))) * ((((int) ((unsigned short) (-19))) / (((int) (20823)) * ((int) (var_4)))) * ((((int) (29348)) * ((int) (32247))) / ((int) ((signed char) (var_24))))))); + short var_545 = -((int) ((signed char) ((short) ((~((int) (1578))) ^ ((int) ((signed char) (26515))))))); + short var_546 = ((~(~((((int) (struct_obj_4.member_2_7)) + (2147483647)) << (((int) (var_14)) - (26))))) | ((int) ((short) (((int) ((short) (struct_obj_4.member_2_0))) ^ (((int) (var_66)) & ((int) (-119))))))) % ((int) ((signed char) ((unsigned short) (~(((int) (11516)) & ((int) (var_545))))))); + var_547 = (signed char) ((short) (var_25)); + var_59 = (unsigned short) (~(((int) (var_41)) << (((((~((int) (struct_obj_4.member_2_6))) | (((int) (var_16)) >> (((int) (struct_obj_7.member_1_0)) + (102)))) + (2147483647)) << (((((((((int) ((short) (struct_obj_8.member_4_1.member_3_1.member_1_2))) ^ ((int) ((((int) ((-((int) ((short) (-4355)))) < (-((int) (struct_obj_3.member_5_2))))) - (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) || ((~((int) (-19743))) * (((int) (58561)) / ((int) (40662)))))) <= ((int) ((signed char) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) <= ((((int) (49)) ^ ((int) (7553))) & ((int) ((signed char) (23467)))))))))) + (78)) - (2)) - (0)) - (0)) - (0)) - (1))) - (2147427589)))); + } + + short var_548 = !(((!(((int) (var_54)) && ((int) (var_11)))) || ((((int) (var_18)) || ((int) (var_7))) && (((int) (var_16)) || ((int) (struct_obj_9.member_2_2))))) >> ((int) ((((int) ((-((int) ((short) (-4355)))) < (-((int) (struct_obj_3.member_5_2))))) - (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) || ((~((int) (-19743))) * (((int) (58561)) / ((int) (40662)))))) <= ((int) ((signed char) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) <= ((((int) (49)) ^ ((int) (7553))) & ((int) ((signed char) (23467)))))))))); + var_549 = (signed char) (~(~(~((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475))))))))))))); + } + + if (struct_obj_4.member_2_5) + { + unsigned short var_550 = +((int) (((int) ((short) (((int) ((short) (21542))) & ((int) (((int) (var_17)) > ((int) (41361))))))) != ((int) (((int) ((((int) (struct_obj_5.member_1_1)) >> (((int) (var_11)) - (9751))) >= (~((int) (var_30))))) < ((int) ((signed char) ((signed char) (62686)))))))); + short var_551 = ~((((int) (struct_obj_3.member_5_2)) + (((int) (struct_obj_5.member_1_0)) + (((int) (2)) - ((int) (var_55))))) << ((((-(((int) (struct_obj_6.member_5_3)) || ((int) (var_48)))) / ((int) ((~((int) (var_7))) <= ((int) (((int) (56959)) == ((int) (struct_obj_8.member_4_8))))))) + (29)) - (24))); + unsigned short var_552 = (~(~((int) (var_13)))) * (!(!(((int) ((short) (29468))) && (!((int) (struct_obj_8.member_4_2)))))); + if ((((int) (var_18)) % (+((int) ((signed char) (((int) (11489)) * ((int) (9265))))))) > (((!((int) ((short) (var_40)))) && (((int) (var_471)) || (((int) (44877)) || ((int) (struct_obj_10.member_1_2))))) - ((((int) ((short) (var_47))) && ((int) (struct_obj_3.member_5_2))) || ((((int) (var_48)) || ((int) (3022))) && (!((int) (var_471))))))) + { + var_48 = (unsigned short) (((int) ((short) (((int) ((unsigned short) (((int) (var_24)) * ((int) (var_41))))) * (~((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))))))) & (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) & ((~((int) (((int) (21911)) >= ((int) (71))))) | (~(!((int) (var_21))))))); + signed char var_553 = ((+((int) ((((int) ((-((int) ((short) (-4355)))) < (-((int) (struct_obj_3.member_5_2))))) - (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) || ((~((int) (-19743))) * (((int) (58561)) / ((int) (40662)))))) <= ((int) ((signed char) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) <= ((((int) (49)) ^ ((int) (7553))) & ((int) ((signed char) (23467)))))))))) / (~((((int) (struct_obj_6.member_5_3)) << (((int) (var_33)) - (40297))) | ((int) ((signed char) (struct_obj_2.member_5_0)))))) - ((!((!((int) (var_26))) && ((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))))) * ((int) ((!((int) (((int) (var_63)) <= ((int) (var_550))))) >= ((+((int) (75))) + (((int) (-34)) + ((int) (var_28))))))); + unsigned short var_554 = (short) ((-((int) (((int) (((int) (var_48)) != ((int) (-19268)))) > (((int) (var_36)) << (((int) (var_29)) - (51738)))))) < (!(((int) (struct_obj_2.member_5_2)) << (((int) (struct_obj_9.member_2_7)) - (21083))))); + unsigned short var_555 = (((((int) (-7012)) ^ (((int) (var_34)) ^ ((int) (struct_obj_3.member_5_1)))) | (~((int) ((short) (366))))) | ((~(((int) (11695)) | ((int) (-51)))) | ((int) ((signed char) ((unsigned short) (var_17)))))) != ((int) ((((int) ((-((int) ((short) (-4355)))) < (-((int) (struct_obj_3.member_5_2))))) - (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) || ((~((int) (-19743))) * (((int) (58561)) / ((int) (40662)))))) <= ((int) ((signed char) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) <= ((((int) (49)) ^ ((int) (7553))) & ((int) ((signed char) (23467))))))))); + signed char var_556 = ((((((int) (struct_obj_4.member_2_3.member_1_1)) && ((int) (struct_obj_6.member_5_2))) || (((int) (var_60)) || ((int) (struct_obj_4.member_2_3.member_1_2)))) || ((int) (-11))) && (!((((int) (var_65)) && ((int) (struct_obj_9.member_2_4))) && (((int) (var_3)) && ((int) (var_51)))))) && (((int) ((unsigned short) ((short) (((int) (var_50)) && ((int) (struct_obj_7.member_1_0)))))) || (((int) ((unsigned short) (!((int) (8848))))) || ((((int) (var_45)) && ((int) (-14256))) || (((int) (var_19)) && ((int) (var_550)))))); + } + + var_52 = (short) (~((((((int) (var_24)) + ((int) (struct_obj_9.member_2_1.member_1_0))) + (((int) (struct_obj_2.member_5_0)) - ((int) (var_66)))) - (-(((int) (125)) - ((int) (var_40))))) * ((-(((int) (struct_obj_8.member_4_0)) - ((int) (var_6)))) * (+((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))))))); + if ((((int) (var_29)) >> (-((!((int) (var_57))) && (!((int) (var_39)))))) % ((~(~((int) (((int) (114)) <= ((int) (34964)))))) - (~((int) ((+((int) (-8064))) > (((int) (var_470)) | ((int) (var_507)))))))) + { + unsigned short var_557 = ((((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) & ((int) ((short) ((signed char) (struct_obj_4.member_2_5))))) >> ((int) ((short) (((int) (var_8)) / (((int) (10468)) * ((int) (-23532))))))) >> ((int) (((int) (struct_obj_5.member_1_0)) <= ((int) ((short) (-(((int) (-100)) * ((int) (var_19)))))))); + var_558 = (short) (!(~((~(((int) (var_31)) - ((int) (var_557)))) >> (((int) ((signed char) (((int) (-19435)) % ((int) (struct_obj_9.member_2_1.member_1_0))))) + (55))))); + signed char var_559 = -35; + var_64 = (signed char) (((((int) (var_473)) % (~(((int) (struct_obj_6.member_5_2)) && ((int) (struct_obj_4.member_2_1.member_1_0))))) && (!((((int) (-4)) || ((int) (3208))) && (!((int) (-40)))))) == ((int) (struct_obj_1.member_5_3))); + signed char var_560 = (((int) (var_13)) & (~((int) (11657)))) ^ ((~((((int) (var_25)) ^ ((int) (var_559))) ^ (((int) (struct_obj_8.member_4_1.member_3_1.member_1_2)) ^ ((int) (-22908))))) ^ ((~((int) ((((int) ((-((int) ((short) (-4355)))) < (-((int) (struct_obj_3.member_5_2))))) - (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) || ((~((int) (-19743))) * (((int) (58561)) / ((int) (40662)))))) <= ((int) ((signed char) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) <= ((((int) (49)) ^ ((int) (7553))) & ((int) ((signed char) (23467)))))))))) & ((int) ((((int) ((-((int) ((short) (-4355)))) < (-((int) (struct_obj_3.member_5_2))))) - (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) || ((~((int) (-19743))) * (((int) (58561)) / ((int) (40662)))))) <= ((int) ((signed char) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) <= ((((int) (49)) ^ ((int) (7553))) & ((int) ((signed char) (23467))))))))))); + short var_561 = struct_obj_8.member_4_7; + signed char var_562 = ~((int) ((unsigned short) ((unsigned short) ((~((int) (var_561))) & (((int) (var_26)) ^ ((int) (var_469))))))); + short var_563 = struct_obj_3.member_5_2; + short var_564 = !((int) (((int) (((((int) (struct_obj_3.member_5_0)) & ((int) (struct_obj_9.member_2_1.member_1_0))) % (((int) (var_60)) && ((int) (var_470)))) > (!(+((int) (32834)))))) > (((~((int) (-117))) & (~((int) (struct_obj_3.member_5_2)))) || (-((int) ((signed char) (var_45))))))); + short var_565 = ((int) ((((int) ((((int) (-30333)) & ((int) (var_55))) <= ((int) (struct_obj_8.member_4_6)))) & ((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475))))))))))) < (!(~(~((int) (var_28))))))) > (-((int) (((~((int) (struct_obj_9.member_2_5))) - (((int) (struct_obj_5.member_1_1)) && ((int) (struct_obj_6.member_5_3)))) <= (-(~((int) (21443))))))); + } + + short var_566 = ~(((int) ((unsigned short) ((short) (struct_obj_3.member_5_2)))) >> ((~((int) ((unsigned short) (((int) (struct_obj_8.member_4_1.member_3_1.member_1_0)) ^ ((int) (56133)))))) + (9444))); + signed char var_567 = ((int) (-25334)) & ((int) ((signed char) (((int) ((((int) (var_46)) >> ((int) (var_46))) >= (+((int) (var_58))))) < ((int) (struct_obj_7.member_1_0))))); + if (~(((~(~((int) (var_1)))) ^ (~(((int) (16674)) & ((int) (-20))))) ^ ((int) (7212)))) + { + unsigned short var_568 = (!(+((((int) (8032)) >> (((int) (-71)) + (87))) * ((int) ((signed char) (66)))))) >> ((((int) (struct_obj_3.member_5_2)) << ((int) ((signed char) ((!((int) (-111))) >= ((int) (((int) (-21044)) == ((int) (11494)))))))) - (119619)); + short var_569 = (unsigned short) ((((((int) (12689)) & ((int) (struct_obj_9.member_2_0))) & (~((int) (29330)))) | ((int) (struct_obj_3.member_5_2))) & (~((int) ((short) (~((int) (struct_obj_8.member_4_4))))))); + unsigned short var_570 = ((+((int) ((short) (((int) (-55)) * ((int) (var_41)))))) * (!(-((int) ((((int) ((-((int) ((short) (-4355)))) < (-((int) (struct_obj_3.member_5_2))))) - (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) || ((~((int) (-19743))) * (((int) (58561)) / ((int) (40662)))))) <= ((int) ((signed char) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) <= ((((int) (49)) ^ ((int) (7553))) & ((int) ((signed char) (23467)))))))))))) && ((int) ((unsigned short) (((((int) (64)) || ((int) (struct_obj_4.member_2_3.member_1_2))) % ((int) (((int) (struct_obj_4.member_2_6)) != ((int) (struct_obj_2.member_5_1))))) * (((int) ((signed char) (-28985))) ^ ((int) (22407)))))); + unsigned short var_571 = (~((int) (-20282))) & ((int) ((signed char) (((~(((int) (-25685)) ^ ((int) (-111)))) + (2147483647)) << (((~((int) (var_13))) >> ((((int) (struct_obj_6.member_5_3)) << (((int) (22066)) - (22056))) - (12717046))) - (23))))); + short var_572 = ((int) ((~(~(((int) (22554)) | ((int) (var_42))))) < (~((((int) (var_12)) >> (((int) (var_36)) - (27368))) >> ((~((int) (680))) + (687)))))) <= (!(!((int) (((int) ((signed char) (struct_obj_10.member_1_3))) >= (+((int) (84))))))); + signed char var_573 = ((~(((int) ((signed char) (((int) (59675)) || ((int) (-27347))))) << ((-((int) (struct_obj_3.member_5_2))) + (59837)))) + (2147483647)) >> ((~((int) (struct_obj_3.member_5_2))) + (59829)); + signed char var_574 = ((~((int) (struct_obj_8.member_4_1.member_3_1.member_1_2))) & (((~((int) (struct_obj_5.member_1_1))) | (~((int) (struct_obj_8.member_4_9.member_1_1)))) | ((~((int) (49))) | ((int) ((short) (((int) (((int) ((signed char) (((int) (25082)) || ((int) (struct_obj_4.member_2_1.member_1_1))))) <= ((int) (69)))) << ((~((+((int) (var_2))) / ((int) (var_34)))) - (233)))))))) && ((int) ((unsigned short) ((~(((int) (var_472)) >> (((int) (35425)) - (35422)))) & ((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475))))))))))))); + unsigned short var_575 = ~((int) ((~((int) ((unsigned short) (((int) (var_46)) | ((int) (var_20)))))) >= ((int) ((signed char) (((int) (((int) (-21055)) > ((int) (20469)))) % ((int) (55942))))))); + } + else + { + signed char var_576 = ((int) ((~(~((int) (((int) (struct_obj_10.member_1_3)) < ((int) (var_58)))))) <= ((int) (((int) ((((int) (-88)) * ((int) (28366))) != ((int) (struct_obj_3.member_5_2)))) < (~(((int) (var_7)) & ((int) (struct_obj_7.member_1_2)))))))) == ((int) ((short) ((((int) ((-((int) ((short) (-4355)))) < (-((int) (struct_obj_3.member_5_2))))) - (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) || ((~((int) (-19743))) * (((int) (58561)) / ((int) (40662)))))) <= ((int) ((signed char) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) <= ((((int) (49)) ^ ((int) (7553))) & ((int) ((signed char) (23467)))))))))); + var_51 = (short) (-(~((int) (54)))); + signed char var_577 = (unsigned short) ((signed char) ((((int) ((unsigned short) (var_12))) ^ (~((int) (var_38)))) | (~(~((int) (struct_obj_8.member_4_0)))))); + short var_578 = !(~((int) ((short) (((int) (((int) (var_34)) >= ((int) (var_577)))) & ((int) (((int) (var_63)) != ((int) (5719)))))))); + signed char var_579 = +((((+((int) (40951))) | (~((int) (var_506)))) / ((((int) (27014)) | ((int) (41639))) ^ (((int) (91)) | ((int) (struct_obj_8.member_4_4))))) << ((int) (((int) (struct_obj_9.member_2_5)) != ((int) (((int) ((short) (29451))) >= (+((int) (var_51)))))))); + unsigned short var_580 = (unsigned short) ((unsigned short) (var_65)); + short var_581 = ~((int) (struct_obj_3.member_5_2)); + short var_582 = ((int) (((int) (struct_obj_3.member_5_2)) < ((int) (((-((int) (var_45))) >> ((int) ((((int) ((-((int) ((short) (-4355)))) < (-((int) (struct_obj_3.member_5_2))))) - (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) || ((~((int) (-19743))) * (((int) (58561)) / ((int) (40662)))))) <= ((int) ((signed char) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) <= ((((int) (49)) ^ ((int) (7553))) & ((int) ((signed char) (23467)))))))))) >= ((int) ((short) (((int) (20524)) * ((int) (struct_obj_8.member_4_1.member_3_0))))))))) ^ ((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))); + unsigned short var_583 = +((((int) ((short) (18))) | ((int) ((signed char) ((short) (var_58))))) | (((int) ((((int) ((-((int) ((short) (-4355)))) < (-((int) (struct_obj_3.member_5_2))))) - (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) || ((~((int) (-19743))) * (((int) (58561)) / ((int) (40662)))))) <= ((int) ((signed char) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) <= ((((int) (49)) ^ ((int) (7553))) & ((int) ((signed char) (23467))))))))) & (~(~((int) (var_66)))))); + signed char var_584 = !((int) ((short) (((int) ((+((int) (var_25))) <= (~((int) (var_567))))) ^ ((int) ((signed char) ((signed char) (3847))))))); + } + + } + + if ((signed char) (((int) (var_62)) & ((int) (((int) (var_8)) <= (!((int) ((unsigned short) (1490)))))))) + { + short var_585 = (short) (((int) (-70)) | ((!((int) ((short) (struct_obj_1.member_5_0)))) && ((int) (struct_obj_3.member_5_2)))); + if (((int) ((signed char) (((int) ((signed char) (((int) (11726)) * ((int) (var_42))))) * (~(~((int) (struct_obj_1.member_5_1))))))) * (((((int) ((signed char) (var_469))) * ((int) (struct_obj_3.member_5_2))) * ((int) ((unsigned short) (~((int) (-20687)))))) * ((int) ((short) ((!((int) (-36))) * ((int) (48610))))))) + { + signed char var_586 = ~((!(((int) ((signed char) (42650))) / (((int) (struct_obj_9.member_2_2)) | ((int) (struct_obj_9.member_2_2))))) >> ((((int) ((signed char) (((int) (-63)) ^ ((int) (var_472))))) ^ ((~((int) (53084))) | (((int) (var_37)) & ((int) (var_10))))) - (53044))); + signed char var_587 = (short) (((int) (24145)) < (~((~((int) (-20377))) | (((int) (var_32)) & ((int) (var_25)))))); + short var_588 = (((int) ((short) (~((int) (var_15))))) * ((int) ((unsigned short) (~(((int) (var_27)) * ((int) (var_18))))))) / ((int) ((unsigned short) (var_37))); + signed char var_589 = (+(!((((int) (-93)) & ((int) (-2615))) | ((int) ((short) (-123)))))) & ((int) (struct_obj_4.member_2_3.member_1_3)); + signed char var_590 = ((((int) (17070)) << (((int) (19866)) - (19850))) | (((int) ((short) (((int) (var_26)) != ((int) (var_7))))) >> ((int) ((((int) (var_58)) & ((int) (var_53))) < ((int) (((int) (var_40)) <= ((int) (55455)))))))) / ((((int) ((short) (-((int) (var_46))))) + (2147483647)) >> (((int) (struct_obj_10.member_1_3)) + (21794))); + var_591 = (signed char) (((~((((int) (struct_obj_6.member_5_0)) << (((int) (var_506)) - (34))) << (((~((int) (var_60))) + (21611)) - (23)))) & ((int) (var_10))) | ((int) (49472))); + short var_592 = (unsigned short) ((short) ((signed char) ((!((int) (26965))) ^ (((int) (18006)) + ((int) (36)))))); + unsigned short var_593 = (short) ((((int) ((((int) (-29676)) * ((int) (25475))) >= ((int) ((unsigned short) (var_26))))) & ((int) ((((int) (struct_obj_8.member_4_6)) ^ ((int) (9575))) != (((int) (10136)) % ((int) (struct_obj_7.member_1_2)))))) <= ((int) (((int) ((((int) (40469)) & ((int) (7768))) == ((int) ((short) (-29505))))) <= (~(((int) (var_11)) | ((int) (struct_obj_3.member_5_0))))))); + unsigned short var_594 = (unsigned short) ((((int) ((((int) (-50)) || ((int) (-78))) > (-((int) (struct_obj_3.member_5_1))))) & (-((int) ((unsigned short) (var_18))))) % ((int) (((-((int) (-24452))) * (!((int) (struct_obj_1.member_5_3)))) != (((~((~((int) (12794))) & ((((int) (-15515)) + (2147483647)) >> (((int) (var_30)) - (42687))))) - ((int) ((short) ((((int) (var_32)) || ((int) (var_12))) >> ((~((int) (-11674))) - (11648)))))) && ((int) (struct_obj_4.member_2_3.member_1_1)))))); + } + + unsigned short var_595 = (unsigned short) (!((int) ((short) (struct_obj_4.member_2_4)))); + unsigned short var_596 = ((int) (((int) ((signed char) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) + (((int) (59094)) + ((int) (struct_obj_9.member_2_1.member_1_3)))))) > (((!((int) (var_27))) - ((int) (((int) (var_10)) <= ((int) (var_60))))) && ((((int) ((-127 - 1))) * ((int) (var_40))) * (-((int) (19780))))))) & ((int) ((-((int) (-43))) < (-((int) ((((int) (var_43)) + ((int) (struct_obj_5.member_1_3))) < (((int) (26468)) % ((int) (60870)))))))); + signed char var_597 = ~((int) ((short) (~((((int) (21151)) ^ ((int) (struct_obj_8.member_4_9.member_1_2))) & (((int) (var_8)) >> (((int) (var_506)) - (22))))))); + unsigned short var_598 = ((((int) (20683)) && ((((int) (76)) && ((int) (var_53))) || ((int) ((unsigned short) (var_61))))) || (((((int) (-10814)) && ((int) (22918))) && (((int) (79)) && ((int) (7990)))) || ((((int) (var_10)) || ((int) (var_44))) || (((int) (28091)) || ((int) (16480)))))) * ((((int) ((((int) (9562)) | ((int) (var_64))) < (-((int) (var_38))))) | ((int) (((int) ((unsigned short) (var_506))) < (((int) (struct_obj_4.member_2_2)) || ((int) (var_34)))))) + ((int) ((~((int) (struct_obj_8.member_4_3))) > (~((int) ((unsigned short) (struct_obj_4.member_2_2))))))); + struct_obj_10.member_1_2 = (signed char) (-(-(((~((int) (27631))) & (((int) (25634)) | ((int) (struct_obj_4.member_2_3.member_1_2)))) ^ ((int) ((((int) ((-((int) ((short) (-4355)))) < (-((int) (struct_obj_3.member_5_2))))) - (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) || ((~((int) (-19743))) * (((int) (58561)) / ((int) (40662)))))) <= ((int) ((signed char) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) <= ((((int) (49)) ^ ((int) (7553))) & ((int) ((signed char) (23467)))))))))))); + if (((int) ((signed char) (((int) ((short) (((int) (var_43)) && ((int) (40250))))) || ((int) ((signed char) (var_25)))))) != ((int) ((+((int) ((~((int) ((((int) ((-((int) ((short) (-4355)))) < (-((int) (struct_obj_3.member_5_2))))) - (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) || ((~((int) (-19743))) * (((int) (58561)) / ((int) (40662)))))) <= ((int) ((signed char) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) <= ((((int) (49)) ^ ((int) (7553))) & ((int) ((signed char) (23467)))))))))) == ((-((int) (var_7))) || (((int) (struct_obj_4.member_2_3.member_1_2)) || ((int) (var_12))))))) <= ((int) ((~(~(((int) (var_27)) & ((int) (-98))))) <= ((int) (((((int) (-10897)) || ((int) (struct_obj_4.member_2_3.member_1_3))) || ((int) (var_14))) != ((int) (struct_obj_3.member_5_2))))))))) + { + signed char var_599 = (((int) ((short) (struct_obj_9.member_2_0))) ^ (((((int) ((signed char) (var_2))) ^ (~((int) (23693)))) + (2147483647)) << ((((((int) (struct_obj_5.member_1_0)) + (127)) - (21)) - (0)) - (1)))) | ((((~((int) (var_48))) ^ (((int) (struct_obj_3.member_5_0)) & ((int) (55751)))) ^ (~(((int) (-60)) ^ ((int) (150))))) & (~(((int) ((unsigned short) (struct_obj_4.member_2_6))) ^ (((int) (5973)) << (((int) (36731)) - (36715)))))); + unsigned short var_600 = ~(+(((int) ((short) ((((int) ((-((int) ((short) (-4355)))) < (-((int) (struct_obj_3.member_5_2))))) - (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) || ((~((int) (-19743))) * (((int) (58561)) / ((int) (40662)))))) <= ((int) ((signed char) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) <= ((((int) (49)) ^ ((int) (7553))) & ((int) ((signed char) (23467)))))))))) | ((((int) (struct_obj_8.member_4_1.member_3_1.member_1_1)) & ((int) (struct_obj_9.member_2_2))) | (((int) (var_2)) | ((int) (var_506)))))); + short var_601 = (((int) ((-((int) ((short) (-4355)))) < (-((int) (struct_obj_3.member_5_2))))) - (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) || ((~((int) (-19743))) * (((int) (58561)) / ((int) (40662)))))) <= ((int) ((signed char) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) <= ((((int) (49)) ^ ((int) (7553))) & ((int) ((signed char) (23467))))))); + unsigned short var_602 = ((int) ((short) ((((int) ((short) (15058))) - (((int) (13)) + ((int) (var_57)))) + (-(((int) (var_53)) + ((int) (var_53))))))) * ((int) (var_39)); + signed char var_603 = var_6; + unsigned short var_604 = ((int) (((int) (-22742)) > (~((((int) (var_24)) ^ ((int) (struct_obj_5.member_1_3))) ^ (((int) (28)) ^ ((int) (var_28))))))) * ((int) ((short) ((((int) (struct_obj_3.member_5_2)) && (!((int) (89)))) | (~((int) (struct_obj_4.member_2_3.member_1_2)))))); + short var_605 = (signed char) ((((~((int) (-124))) & (~((int) (4435)))) | ((((int) (46344)) & ((int) (48688))) | (((int) (-81)) ^ ((int) (22626))))) | (~(~(((int) (28400)) ^ ((int) (80)))))); + signed char var_606 = !(((int) ((~(((int) (var_595)) + ((int) (struct_obj_9.member_2_1.member_1_0)))) > (((int) (((int) (37904)) <= ((int) (struct_obj_8.member_4_3)))) & (!((int) (var_8)))))) & (+(((int) ((short) (var_14))) % ((int) ((signed char) (-120)))))); + unsigned short var_607 = ~((int) ((signed char) (struct_obj_3.member_5_2))); + short var_608 = (short) (((int) (((((int) (-67)) ^ ((int) (23314))) & (~((int) (2233)))) == ((int) ((((int) ((-((int) ((short) (-4355)))) < (-((int) (struct_obj_3.member_5_2))))) - (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) || ((~((int) (-19743))) * (((int) (58561)) / ((int) (40662)))))) <= ((int) ((signed char) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) <= ((((int) (49)) ^ ((int) (7553))) & ((int) ((signed char) (23467))))))))))) + ((int) (-24744))); + } + else + { + signed char var_609 = ((int) ((~((((int) (var_596)) | ((int) (struct_obj_8.member_4_8))) || ((int) (var_22)))) != ((int) ((short) (((int) (((int) (-29)) != ((int) (36)))) & ((int) (((int) (30)) <= ((int) (struct_obj_4.member_2_1.member_1_0))))))))) && (+((int) (((int) ((unsigned short) (((int) (struct_obj_8.member_4_1.member_3_0)) / ((int) (struct_obj_10.member_1_3))))) < ((int) (((int) (((int) (struct_obj_4.member_2_3.member_1_0)) > ((int) (var_43)))) <= (~((int) (25446)))))))); + unsigned short var_610 = (short) ((+((((int) (var_49)) - ((int) (struct_obj_8.member_4_9.member_1_0))) + (-((int) (54566))))) * ((int) (var_34))); + short var_611 = ((int) ((signed char) (~((int) (struct_obj_2.member_5_1))))) ^ ((((int) ((short) ((signed char) (62)))) << ((((((int) (25)) ^ ((int) (-16))) + (2147483647)) << ((((int) (5683)) & ((int) (-10))) - (5682))) - (2147483607))) | (((int) ((signed char) (((int) (13434)) >> (((int) (-71)) + (97))))) << ((((int) (20025)) >> (((int) (-101)) + (122))) << ((int) ((signed char) (-4597)))))); + var_42 = (signed char) (((int) (((int) ((unsigned short) ((!((int) (var_21))) * (((int) (var_55)) * ((int) (var_473)))))) <= ((int) (((int) ((((int) (struct_obj_8.member_4_1.member_3_0)) || ((int) (var_38))) <= (((int) (var_56)) * ((int) (struct_obj_8.member_4_9.member_1_0))))) > ((((int) (var_57)) & ((int) (var_37))) || (~((int) (var_5)))))))) <= ((int) (var_62))); + short var_612 = (~((int) (((int) ((((int) (-86)) & ((int) (var_1))) >= ((int) (63479)))) != ((int) (var_50))))) % (((int) (((((int) (struct_obj_1.member_5_2)) ^ ((int) (struct_obj_8.member_4_5))) | (((int) (-7103)) ^ ((int) (96)))) < ((int) (var_39)))) | ((int) ((~((int) ((unsigned short) (var_53)))) != (((int) (((int) (struct_obj_3.member_5_0)) != ((int) (struct_obj_6.member_5_1)))) && ((int) ((signed char) (40))))))); + } + + if ((~((int) ((signed char) (~((int) (-2706)))))) <= (+(((((int) (struct_obj_9.member_2_1.member_1_3)) + ((int) (-38))) * ((int) ((unsigned short) (var_48)))) * (-(((int) (53)) + ((int) (42))))))) + { + short var_613 = ((int) ((unsigned short) (~((~((int) (35514))) | (((int) (-11248)) | ((int) (-11218))))))) & (~(~((int) ((short) ((unsigned short) (var_17)))))); + short var_614 = (((((int) ((signed char) (var_60))) & ((int) (struct_obj_8.member_4_9.member_1_1))) >> ((int) ((signed char) (((int) (var_60)) || ((int) (struct_obj_9.member_2_7)))))) || (((((int) (var_58)) * ((int) (41314))) / (((int) (struct_obj_9.member_2_0)) * ((int) (var_30)))) * ((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))))) * ((int) (((((int) (-2486)) ^ ((int) ((unsigned short) (112)))) % (-((int) ((short) (struct_obj_8.member_4_1.member_3_1.member_1_0))))) < (((int) ((((int) (struct_obj_9.member_2_1.member_1_3)) + ((int) (var_62))) >= (!((int) (struct_obj_2.member_5_0))))) || ((int) ((unsigned short) (+((int) (struct_obj_8.member_4_9.member_1_2)))))))); + unsigned short var_615 = (unsigned short) (((int) (-15187)) * (!((((int) (82)) * ((int) (7986))) * ((int) ((signed char) (-8101)))))); + unsigned short var_616 = ((int) (struct_obj_5.member_1_1)) > ((((int) ((+((int) ((~((int) ((((int) ((-((int) ((short) (-4355)))) < (-((int) (struct_obj_3.member_5_2))))) - (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) || ((~((int) (-19743))) * (((int) (58561)) / ((int) (40662)))))) <= ((int) ((signed char) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) <= ((((int) (49)) ^ ((int) (7553))) & ((int) ((signed char) (23467)))))))))) == ((-((int) (var_7))) || (((int) (struct_obj_4.member_2_3.member_1_2)) || ((int) (var_12))))))) <= ((int) ((~(~(((int) (var_27)) & ((int) (-98))))) <= ((int) (((((int) (-10897)) || ((int) (struct_obj_4.member_2_3.member_1_3))) || ((int) (var_14))) != ((int) (struct_obj_3.member_5_2)))))))) & (((int) (struct_obj_3.member_5_2)) >> (((int) ((signed char) (struct_obj_6.member_5_1))) - (108)))) >> (((~(~((int) (struct_obj_10.member_1_0)))) ^ (((int) (var_507)) - (((int) (var_37)) && ((int) (var_47))))) - (2008))); + unsigned short var_617 = var_40; + unsigned short var_618 = ~(~((~(((int) (-49)) | ((int) (6)))) ^ (~(((int) (-101)) | ((int) (-118)))))); + var_52 = (short) (((int) ((~((((int) (58053)) * ((int) (-35))) / (((int) (-22)) * ((int) (4112))))) > (((((int) (-100)) & ((int) (34043))) ^ (((int) (10311)) | ((int) (-10654)))) & (~(((int) (-22199)) | ((int) (22289))))))) && (((int) (struct_obj_3.member_5_2)) >> (+((int) ((short) ((((int) ((-((int) ((short) (-4355)))) < (-((int) (struct_obj_3.member_5_2))))) - (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) || ((~((int) (-19743))) * (((int) (58561)) / ((int) (40662)))))) <= ((int) ((signed char) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) <= ((((int) (49)) ^ ((int) (7553))) & ((int) ((signed char) (23467))))))))))))); + } + else + { + short var_619 = ((~(((int) ((short) (13900))) * ((int) ((signed char) (-20248))))) * (((((int) (-975)) * ((int) (struct_obj_9.member_2_1.member_1_0))) / (((int) (var_9)) * ((int) (struct_obj_3.member_5_0)))) * ((((int) (5)) * ((int) (28036))) * (!((int) (struct_obj_8.member_4_1.member_3_1.member_1_1)))))) || (((int) ((signed char) (((int) ((unsigned short) (struct_obj_4.member_2_1.member_1_0))) && ((int) ((unsigned short) (var_8)))))) & ((((int) ((unsigned short) (var_41))) ^ (((int) (var_35)) | ((int) (var_9)))) | (((int) ((unsigned short) (struct_obj_3.member_5_3))) ^ (((int) (17186)) >> (((int) (struct_obj_9.member_2_1.member_1_1)) - (31946)))))); + unsigned short var_620 = (~(((int) ((signed char) (~((int) (var_41))))) & ((int) ((unsigned short) (struct_obj_3.member_5_2))))) / ((int) (-5296)); + signed char var_621 = var_20; + short var_622 = (((int) (struct_obj_6.member_5_0)) | ((~((int) (2))) | (((int) ((signed char) (struct_obj_4.member_2_2))) ^ ((int) ((+((int) ((~((int) ((((int) ((-((int) ((short) (-4355)))) < (-((int) (struct_obj_3.member_5_2))))) - (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) || ((~((int) (-19743))) * (((int) (58561)) / ((int) (40662)))))) <= ((int) ((signed char) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) <= ((((int) (49)) ^ ((int) (7553))) & ((int) ((signed char) (23467)))))))))) == ((-((int) (var_7))) || (((int) (struct_obj_4.member_2_3.member_1_2)) || ((int) (var_12))))))) <= ((int) ((~(~(((int) (var_27)) & ((int) (-98))))) <= ((int) (((((int) (-10897)) || ((int) (struct_obj_4.member_2_3.member_1_3))) || ((int) (var_14))) != ((int) (struct_obj_3.member_5_2))))))))))) ^ ((((int) ((signed char) (~((int) (var_31))))) | ((int) (struct_obj_3.member_5_2))) | ((int) ((unsigned short) ((unsigned short) (~((int) (var_2))))))); + short var_623 = ((((int) ((unsigned short) ((signed char) (var_18)))) || (((int) ((+((int) ((~((int) ((((int) ((-((int) ((short) (-4355)))) < (-((int) (struct_obj_3.member_5_2))))) - (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) || ((~((int) (-19743))) * (((int) (58561)) / ((int) (40662)))))) <= ((int) ((signed char) (((int) (((((int) (struct_obj_3.member_5_2)) ^ ((int) (-77))) & (((int) ((short) (~((int) (-10947))))) | ((((int) (var_30)) >> (((int) (145)) - (138))) | ((((int) (-11225)) + (2147483647)) >> (((int) (31473)) - (31471)))))) >= ((int) (((-(-((int) (struct_obj_2.member_5_0)))) * (-((int) ((unsigned short) (var_1))))) > ((int) (((int) ((unsigned short) (~((int) (-5))))) != (((int) (struct_obj_3.member_5_2)) && (((int) (var_17)) << (((int) (var_9)) - (13475)))))))))) <= ((((int) (49)) ^ ((int) (7553))) & ((int) ((signed char) (23467)))))))))) == ((-((int) (var_7))) || (((int) (struct_obj_4.member_2_3.member_1_2)) || ((int) (var_12))))))) <= ((int) ((~(~(((int) (var_27)) & ((int) (-98))))) <= ((int) (((((int) (-10897)) || ((int) (struct_obj_4.member_2_3.member_1_3))) || ((int) (var_14))) != ((int) (struct_obj_3.member_5_2)))))))) && (((int) (2844)) && ((int) (struct_obj_8.member_4_5))))) || (!((((int) (43906)) || ((int) (var_470))) || (((int) (var_27)) && ((int) (var_52)))))) && (((int) ((signed char) ((((int) (-26084)) || ((int) (struct_obj_8.member_4_4))) || (((int) (struct_obj_4.member_2_1.member_1_0)) || ((int) (var_12)))))) || (((int) (var_45)) && ((((int) (struct_obj_8.member_4_9.member_1_0)) || ((int) (var_23))) && ((int) (struct_obj_4.member_2_1.member_1_1))))); + signed char var_624 = +(~(((int) ((((int) (4004)) ^ ((int) (var_26))) <= (((int) (var_16)) << (((int) (struct_obj_4.member_2_0)) - (7592))))) << (!((int) (var_51))))); + short var_625 = ((int) ((signed char) ((signed char) ((((int) (58)) || ((int) (5530))) >> ((-((int) (var_472))) + (10129)))))) || (+(((((int) (var_624)) * ((int) (struct_obj_10.member_1_3))) * (~((int) (-13129)))) * ((((int) (-6837)) * ((int) (-86))) / (((int) (78)) * ((int) (-2058)))))); + unsigned short var_626 = -(~(~(~((int) (var_28))))); + } + + } + + short var_627 = (((~(((int) (21000)) & ((int) (61917)))) ^ ((((int) (30872)) ^ ((int) (struct_obj_3.member_5_2))) & (((int) (var_472)) & ((int) (var_46))))) | (((((int) (23969)) | ((int) (var_23))) & (((int) (var_38)) ^ ((int) (31735)))) & (~(~((int) (struct_obj_4.member_2_3.member_1_3)))))) & (((((int) (struct_obj_9.member_2_6)) & (~((int) (var_22)))) ^ (((int) (-36)) & (~((int) (var_15))))) | ((int) (struct_obj_4.member_2_4))); + } + +} diff --git a/multiple_labels_crash_test/func.ref.s b/multiple_labels_crash_test/func.ref.s new file mode 100644 index 00000000..3e08e447 --- /dev/null +++ b/multiple_labels_crash_test/func.ref.s @@ -0,0 +1,5170 @@ +// File generated by CompCert 3.7 +// Command line: -dmach -S tmp/func.c -o tmp/func.ref.s + .text + .balign 2 + .globl foo +foo: + mov x29, sp + sub sp, sp, #32 + str x29, [sp, #0] + str x30, [sp, #8] + str x19, [sp, #16] + str x20, [sp, #24] + adrp x16, var_47 + ldrsb w0, [x16, #:lo12:var_47] + movn w16, #5210, lsl #0 + and w0, w0, w16 + ubfiz w0, w0, 0, 16 + cmp w0, #1125 + cset x0, le + cbz w0, .L100 + adrp x16, var_24 + ldrsh w0, [x16, #:lo12:var_24] + movz w16, #16885, lsl #0 + eor w0, w0, w16 + movn w16, #103, lsl #0 + orr w15, w0, w16 + adrp x16, struct_obj_4 + 22 + ldrh w14, [x16, #:lo12:struct_obj_4 + 22] + sbfiz w17, w14, 0, 8 + cmp w15, w17 + cset x0, le + cmp w0, #1 + cset x0, ne + adrp x16, var_58 + strb w0, [x16, #:lo12:var_58] + orr w9, wzr, #1 + orr w11, wzr, #1 + adrp x16, struct_obj_4 + 12 + ldrsb w4, [x16, #:lo12:struct_obj_4 + 12] + sub w12, w9, w4 + adrp x16, var_15 + ldrh w3, [x16, #:lo12:var_15] + sub w7, wzr, w3 + sbfiz w13, w7, 0, 8 + sub w13, w13, #43 + lsl w11, w11, w13 + sub w0, w12, w11 + cbnz w0, .L101 + adrp x16, struct_obj_10 + 6 + ldrsh w0, [x16, #:lo12:struct_obj_10 + 6] + sbfiz w5, w0, 0, 8 + adrp x16, var_31 + ldrsh w0, [x16, #:lo12:var_31] + sub w0, w5, w0 + add w0, w0, #24576 + add w0, w0, #2605 + sub w0, wzr, w0 + cmp w0, #0 + cset x0, ne + cbz w0, .L102 +.L101: + movz w0, #0, lsl #0 + movz w16, #51591, lsl #0 + cmp w0, w16 + cset x0, eq + adrp x16, var_27 + ldrsh w15, [x16, #:lo12:var_27] + adrp x16, struct_obj_6 + 4 + ldrh w29, [x16, #:lo12:struct_obj_6 + 4] + and w6, w15, w29 + orn w4, wzr, w6 + movz w16, #29499, lsl #0 + and w9, w4, w16 + adrp x16, var_23 + ldrh w17, [x16, #:lo12:var_23] + cmp w9, w17 + cset x17, le + lsl w0, w0, w17 + sbfiz w29, w0, 0, 16 + adrp x16, var_30 + ldrh w11, [x16, #:lo12:var_30] + adrp x16, var_3 + ldrsb w5, [x16, #:lo12:var_3] + sub w0, w5, #49 + lsl w10, w11, w0 + movn w16, #245, lsl #0 + eor w9, w10, w16 + cbnz w9, .L103 + adrp x16, var_9 + ldrh w14, [x16, #:lo12:var_9] + adrp x16, struct_obj_4 + 2 + ldrsb w17, [x16, #:lo12:struct_obj_4 + 2] + movz w16, #53547, lsl #0 + orr w15, w17, w16 + sub w12, w15, #53248 + sub w12, w12, #359 + asr w3, w14, w12 + cmp w3, #0 + cset x11, ne + b .L104 +.L103: + orr w11, wzr, #1 +.L104: + adrp x16, struct_obj_7 + 2 + ldrsh w4, [x16, #:lo12:struct_obj_7 + 2] + movz w13, #53518, lsl #0 + movk w13, #32767, lsl #16 + adrp x16, struct_obj_4 + 26 + ldrsh w5, [x16, #:lo12:struct_obj_4 + 26] + adrp x16, var_34 + ldrsb w12, [x16, #:lo12:var_34] + eor w10, w5, w12 + sub w5, w10, #8192 + sub w5, w5, #1378 + asr w6, w13, w5 + adrp x16, struct_obj_4 + 2 + ldrsb w5, [x16, #:lo12:struct_obj_4 + 2] + orn w1, wzr, w5 + adrp x16, var_1 + ldrh w3, [x16, #:lo12:var_1] + sbfiz w0, w3, 0, 8 + adrp x16, var_19 + ldrsb w7, [x16, #:lo12:var_19] + adrp x16, struct_obj_1 + 4 + ldrh w10, [x16, #:lo12:struct_obj_1 + 4] + and w12, w7, w10 + movz w16, #113, lsl #0 + and w12, w12, w16 + orr w0, w0, w12 + cmp w1, w0 + cset x0, ne + asr w14, w6, w0 + eor w10, w4, w14 + orr w16, wzr, #2147483647 + add w8, w10, w16 + adrp x16, var_29 + ldrh w6, [x16, #:lo12:var_29] + adrp x16, var_8 + ldrh w2, [x16, #:lo12:var_8] + and w14, w6, w2 + adrp x16, var_48 + ldrh w3, [x16, #:lo12:var_48] + orr w10, w14, w3 + adrp x16, struct_obj_8 + 18 + ldrsh w12, [x16, #:lo12:struct_obj_8 + 18] + orn w4, wzr, w12 + adrp x16, struct_obj_8 + 20 + ldrsh w3, [x16, #:lo12:struct_obj_8 + 20] + ubfiz w1, w3, 0, 16 + sub w3, w1, #49152 + sub w3, w3, #2540 + lsl w7, w4, w3 + and w10, w10, w7 + movz w4, #49144, lsl #0 + adrp x16, struct_obj_5 + 2 + ldrsh w1, [x16, #:lo12:struct_obj_5 + 2] + sub w13, w1, #28672 + sub w13, w13, #274 + lsl w17, w4, w13 + sub w13, wzr, w11 + add w15, w13, #5 + lsl w17, w17, w15 + adrp x16, struct_obj_2 + 2 + ldrh w11, [x16, #:lo12:struct_obj_2 + 2] + movz w16, #27896, lsl #0 + eor w14, w11, w16 + adrp x16, var_56 + ldrh w13, [x16, #:lo12:var_56] + orn w15, wzr, w13 + add w11, w15, #16384 + add w11, w11, #3806 + lsl w1, w14, w11 + eor w2, w17, w1 + movz w16, #33395, lsl #0 + movk w16, #1535, lsl #16 + sub w2, w2, w16 + lsl w14, w10, w2 + asr w14, w8, w14 + cbz w14, .L105 + adrp x16, struct_obj_3 + 2 + ldrh w10, [x16, #:lo12:struct_obj_3 + 2] + cbz w10, .L106 + adrp x16, var_18 + ldrsb w2, [x16, #:lo12:var_18] + cmp w2, #0 + cset x7, ne + b .L107 +.L106: + movz w7, #0, lsl #0 +.L107: + movz w6, #0, lsl #0 + cbz w6, .L108 + orr w8, wzr, #1 + b .L109 +.L108: + orr w8, wzr, #1 +.L109: + cmp w7, #0 + cset x6, lt + cmp w6, w0 + cset x17, ge + movn w2, #2717, lsl #0 + adrp x16, struct_obj_9 + 26 + ldrsh w4, [x16, #:lo12:struct_obj_9 + 26] + madd w12, w4, w2, wzr + orr w16, wzr, #2147483647 + add w11, w12, w16 + orr w3, wzr, w11, asr #3 + cmp w3, #0 + cset x10, eq + cmp w17, w10 + cset x10, ne + asr w8, w10, w8 + ubfiz w3, w8, 0, 16 + cbnz w9, .L110 + adrp x16, var_9 + ldrh w10, [x16, #:lo12:var_9] + movz w16, #53547, lsl #0 + orr w1, w5, w16 + sub w4, w1, #53248 + sub w4, w4, #359 + asr w9, w10, w4 + cmp w9, #0 + cset x1, ne + b .L111 +.L110: + orr w1, wzr, #1 +.L111: + movz w2, #34812, lsl #0 + adrp x16, var_13 + ldrsh w11, [x16, #:lo12:var_13] + madd w14, w11, w2, wzr + adrp x16, struct_obj_1 + 2 + ldrh w6, [x16, #:lo12:struct_obj_1 + 2] + adrp x16, var_65 + ldrsh w4, [x16, #:lo12:var_65] + madd w9, w6, w4, wzr + sdiv w9, w14, w9 + orr w8, wzr, #62 + adrp x16, var_35 + ldrh w2, [x16, #:lo12:var_35] + madd w14, w2, w8, wzr + cmp w14, #0 + cset x10, eq + madd w15, w9, w10, wzr + sub w2, wzr, w0 + madd w12, w15, w2, wzr + sub w1, wzr, w1 + eor w11, w12, w1 + adrp x16, var_70 + strb w11, [x16, #:lo12:var_70] + adrp x16, var_30 + ldrh w7, [x16, #:lo12:var_30] + adrp x16, var_3 + ldrsb w15, [x16, #:lo12:var_3] + sub w0, w15, #49 + lsl w0, w7, w0 + movn w16, #245, lsl #0 + eor w0, w0, w16 + cbnz w0, .L112 + adrp x16, var_9 + ldrh w15, [x16, #:lo12:var_9] + movz w16, #53547, lsl #0 + orr w2, w5, w16 + sub w1, w2, #53248 + sub w1, w1, #359 + asr w14, w15, w1 + cmp w14, #0 + cset x7, ne + b .L113 +.L112: + orr w7, wzr, #1 +.L113: + sub w10, wzr, w7 + movz w12, #20687, lsl #0 + movk w12, #32767, lsl #16 + adrp x16, var_4 + ldrh w6, [x16, #:lo12:var_4] + sbfiz w14, w6, 0, 16 + sub w13, w14, #3630 + asr w5, w12, w13 + eor w17, w10, w5 + orr w16, wzr, #2147483647 + add w15, w17, w16 + adrp x16, struct_obj_4 + 12 + ldrsb w12, [x16, #:lo12:struct_obj_4 + 12] + orn w2, wzr, w12 + adrp x16, struct_obj_2 + 2 + ldrh w11, [x16, #:lo12:struct_obj_2 + 2] + orn w2, w2, w11 + ubfiz w1, w2, 0, 16 + sub w0, w1, #61440 + sub w0, w0, #4095 + lsl w8, w15, w0 + adrp x16, var_41 + ldrh w7, [x16, #:lo12:var_41] + adrp x16, struct_obj_9 + 22 + ldrh w5, [x16, #:lo12:struct_obj_9 + 22] + adrp x16, struct_obj_9 + 20 + ldrsh w4, [x16, #:lo12:struct_obj_9 + 20] + sub w0, w4, #12288 + sub w0, w0, #1248 + lsl w17, w5, w0 + eor w13, w7, w17 + eor w0, w8, w13 + adrp x16, struct_obj_9 + 22 + strh w0, [x16, #:lo12:struct_obj_9 + 22] + movz w8, #35578, lsl #0 + adrp x16, struct_obj_5 + ldrsb w2, [x16, #:lo12:struct_obj_5] + madd w14, w2, w8, wzr + movz w11, #103, lsl #0 + madd w13, w3, w11, wzr + madd w8, w14, w13, wzr + adrp x16, var_26 + ldrh w12, [x16, #:lo12:var_26] + cbnz w12, .L105 + adrp x16, var_34 + ldrsb w11, [x16, #:lo12:var_34] + cmp w11, #0 + cset x7, ne +.L105: + adrp x16, var_61 + ldrsb w0, [x16, #:lo12:var_61] + adrp x16, var_15 + ldrh w14, [x16, #:lo12:var_15] + orr w10, w0, w14 + adrp x16, var_52 + ldrsh w8, [x16, #:lo12:var_52] + movz w16, #5914, lsl #0 + and w0, w8, w16 + orr w6, w10, w0 + adrp x16, struct_obj_2 + ldrsh w10, [x16, #:lo12:struct_obj_2] + bic w8, w6, w10 + adrp x16, var_24 + ldrsh w10, [x16, #:lo12:var_24] + movz w16, #31461, lsl #0 + orr w10, w10, w16 + orr w3, w8, w10 + movz w4, #0, lsl #0 + sbfiz w0, w4, 0, 8 + cmp w3, w0 + cset x3, ne + adrp x16, var_78 + strh w3, [x16, #:lo12:var_78] + adrp x16, struct_obj_8 + ldrh w13, [x16, #:lo12:struct_obj_8] + sub w10, wzr, w13 + cbz w10, .L114 + adrp x16, struct_obj_4 + ldrsh w11, [x16, #:lo12:struct_obj_4] + cbnz w11, .L115 + adrp x16, struct_obj_8 + 4 + ldrsb w6, [x16, #:lo12:struct_obj_8 + 4] + cbnz w6, .L115 + orr w8, wzr, #1 + cmp w29, #0 + cset x2, ne + adrp x16, struct_obj_1 + 2 + ldrh w9, [x16, #:lo12:struct_obj_1 + 2] + cmp w9, #0 + csel x0, x8, x2, ne +.L115: + adrp x16, var_54 + ldrsh w0, [x16, #:lo12:var_54] + orr w16, wzr, #2147483647 + add w17, w0, w16 + adrp x16, var_62 + ldrh w14, [x16, #:lo12:var_62] + adrp x16, struct_obj_2 + 4 + ldrh w7, [x16, #:lo12:struct_obj_2 + 4] + eor w12, w14, w7 + sbfiz w29, w12, 0, 16 + sub w6, w29, #24576 + sub w6, w6, #440 + asr w0, w17, w6 + adrp x16, var_54 + strh w0, [x16, #:lo12:var_54] + adrp x16, var_47 + ldrsb w0, [x16, #:lo12:var_47] + orn w12, wzr, w0 + adrp x16, struct_obj_7 + 2 + ldrsh w0, [x16, #:lo12:struct_obj_7 + 2] + orr w16, wzr, #2147483647 + add w13, w0, w16 + adrp x16, var_18 + ldrsb w11, [x16, #:lo12:var_18] + sub w14, w11, #75 + asr w3, w13, w14 + madd w0, w12, w3, wzr + cmp w0, #0 + cset x0, le + orn w12, wzr, w0 + movn w3, #21, lsl #0 + adrp x16, struct_obj_4 + 18 + ldrsh w14, [x16, #:lo12:struct_obj_4 + 18] + madd w15, w14, w3, wzr + movn w6, #32288, lsl #0 + adrp x16, var_6 + ldrh w29, [x16, #:lo12:var_6] + madd w7, w29, w6, wzr + sdiv w2, w15, w7 + orn w0, wzr, w2 + adrp x16, struct_obj_2 + 2 + ldrh w11, [x16, #:lo12:struct_obj_2 + 2] + adrp x16, var_4 + ldrh w7, [x16, #:lo12:var_4] + madd w14, w11, w7, wzr + adrp x16, var_7 + ldrsb w1, [x16, #:lo12:var_7] + cmp w1, #0 + cset x8, eq + madd w9, w14, w8, wzr + orn w7, wzr, w9 + madd w0, w0, w7, wzr + cmp w12, w0 + cset x0, gt + adrp x16, var_82 + strh w0, [x16, #:lo12:var_82] +.L114: + adrp x16, struct_obj_4 + 18 + ldrsh w0, [x16, #:lo12:struct_obj_4 + 18] + cbz w0, .L102 + adrp x16, struct_obj_2 + 4 + ldrh w0, [x16, #:lo12:struct_obj_2 + 4] + cmp w0, #0 + cset x0, ne +.L102: + adrp x16, struct_obj_3 + ldrsh w0, [x16, #:lo12:struct_obj_3] + cbnz w0, .L116 + adrp x16, var_33 + ldrh w0, [x16, #:lo12:var_33] + cbnz w0, .L117 + adrp x16, var_28 + ldrsh w0, [x16, #:lo12:var_28] + cmp w0, #0 + cset x0, ne + b .L118 +.L117: + orr w0, wzr, #1 + b .L118 +.L116: + orr w0, wzr, #1 +.L118: + orn w12, wzr, w0 + adrp x16, var_2 + ldrh w1, [x16, #:lo12:var_2] + adrp x16, struct_obj_4 + 26 + ldrsh w29, [x16, #:lo12:struct_obj_4 + 26] + sub w0, w1, w29 + sbfiz w15, w0, 0, 8 + cmp w12, w15 + b.ge .L119 + adrp x16, var_17 + ldrsh w7, [x16, #:lo12:var_17] + cbnz w7, .L120 + adrp x16, struct_obj_8 + 22 + ldrh w13, [x16, #:lo12:struct_obj_8 + 22] + cmp w13, #0 + cset x4, ne + b .L121 +.L120: + orr w4, wzr, #1 +.L121: + eor w15, w4, #1 + eor w9, w15, #1 + adrp x16, var_47 + ldrsb w3, [x16, #:lo12:var_47] + cmp w3, #0 + cset x8, ne + movz w16, #14251, lsl #0 + cmp w8, w16 + cset x3, le + cmp w3, w7 + cset x8, ne + ubfiz w12, w29, 0, 16 + cmp w8, w12 + cset x13, ge + adrp x16, struct_obj_1 + ldrsh w12, [x16, #:lo12:struct_obj_1] + ubfiz w17, w12, 0, 16 + orn w4, wzr, w17 + movz w16, #40329, lsl #0 + movk w16, #116, lsl #16 + eor w11, w4, w16 + eor w15, w13, w11 + cbz w15, .L122 + movz w4, #0, lsl #0 + adrp x16, struct_obj_5 + ldrsb w7, [x16, #:lo12:struct_obj_5] + movz w16, #12154, lsl #0 + eor w7, w7, w16 + adrp x16, var_1 + ldrh w1, [x16, #:lo12:var_1] + adrp x16, struct_obj_10 + 6 + ldrsh w4, [x16, #:lo12:struct_obj_10 + 6] + movn w16, #9, lsl #0 + orr w10, w4, w16 + eor w29, w1, w10 + eor w2, w7, w29 + adrp x16, struct_obj_8 + 26 + ldrsb w4, [x16, #:lo12:struct_obj_8 + 26] + orr w0, w4, w9 + and w0, w2, w0 + sbfiz w0, w0, 0, 8 + adrp x16, var_90 + strh w0, [x16, #:lo12:var_90] + adrp x16, var_16 + ldrh w0, [x16, #:lo12:var_16] + movz w16, #56567, lsl #0 + eor w12, w0, w16 + adrp x16, struct_obj_7 + ldrsb w8, [x16, #:lo12:struct_obj_7] + and w14, w12, w8 + adrp x16, var_8 + ldrh w11, [x16, #:lo12:var_8] + orr w12, w14, w11 + adrp x16, var_5 + ldrh w2, [x16, #:lo12:var_5] + adrp x16, var_32 + ldrh w3, [x16, #:lo12:var_32] + eon w1, w2, w3 + adrp x16, var_34 + ldrsb w4, [x16, #:lo12:var_34] + movz w16, #44163, lsl #0 + and w5, w4, w16 + sbfiz w9, w5, 0, 8 + orr w3, w1, w9 + bic w0, w12, w3 + adrp x16, var_94 + strh w0, [x16, #:lo12:var_94] + b .L123 +.L122: + adrp x16, struct_obj_6 + 6 + ldrsh w0, [x16, #:lo12:struct_obj_6 + 6] + adrp x16, var_100 + strh w0, [x16, #:lo12:var_100] +.L123: + adrp x16, struct_obj_8 + 24 + ldrh w0, [x16, #:lo12:struct_obj_8 + 24] + sbfiz w0, w0, 0, 8 + adrp x16, var_106 + strh w0, [x16, #:lo12:var_106] + adrp x16, var_55 + ldrsb w4, [x16, #:lo12:var_55] + adrp x16, var_3 + ldrsb w6, [x16, #:lo12:var_3] + adrp x16, struct_obj_2 + 4 + ldrh w5, [x16, #:lo12:struct_obj_2 + 4] + movz w16, #19146, lsl #0 + orr w2, w5, w16 + eon w8, w2, w6 + ubfiz w6, w8, 0, 16 + adrp x16, struct_obj_8 + 16 + ldrsb w17, [x16, #:lo12:struct_obj_8 + 16] + adrp x16, var_2 + ldrh w1, [x16, #:lo12:var_2] + eon w10, w17, w1 + movz w16, #33293, lsl #0 + orr w15, w4, w16 + adrp x16, struct_obj_4 + 2 + ldrsb w29, [x16, #:lo12:struct_obj_4 + 2] + eon w17, w15, w29 + and w14, w10, w17 + and w0, w6, w14 + cmp w0, #0 + cset x0, eq + adrp x16, var_46 + strh w0, [x16, #:lo12:var_46] + orr w0, wzr, #1 + adrp x16, var_40 + strb w0, [x16, #:lo12:var_40] + adrp x16, var_7 + ldrsb w0, [x16, #:lo12:var_7] + ubfiz w0, w0, 0, 16 + cbz w0, .L124 + adrp x16, struct_obj_8 + 28 + ldrsh w0, [x16, #:lo12:struct_obj_8 + 28] + cbz w0, .L124 + adrp x16, var_11 + ldrsh w0, [x16, #:lo12:var_11] + cmp w0, #0 + cset x0, ne + cbz w0, .L124 + adrp x16, struct_obj_7 + 2 + ldrsh w0, [x16, #:lo12:struct_obj_7 + 2] + cbnz w0, .L124 + adrp x16, var_17 + ldrsh w0, [x16, #:lo12:var_17] + cmp w0, #0 + cset x0, ne + cbnz w0, .L124 + adrp x16, var_10 + ldrh w0, [x16, #:lo12:var_10] + b .L124 +.L119: + adrp x16, struct_obj_8 + 28 + ldrsh w0, [x16, #:lo12:struct_obj_8 + 28] + cbnz w0, .L125 + adrp x16, struct_obj_4 + 4 + ldrsh w0, [x16, #:lo12:struct_obj_4 + 4] + cmp w0, #0 + cset x0, ne + b .L126 +.L125: + orr w0, wzr, #1 +.L126: + adrp x16, struct_obj_4 + 8 + ldrsh w12, [x16, #:lo12:struct_obj_4 + 8] + adrp x16, struct_obj_2 + 2 + ldrh w14, [x16, #:lo12:struct_obj_2 + 2] + sdiv w13, w12, w14 + msub w7, w13, w14, w12 + sbfiz w11, w7, 0, 8 + movz w16, #54823, lsl #0 + cmp w0, w16 + cset x8, le + orr w8, w11, w8 + adrp x16, var_9 + ldrh w6, [x16, #:lo12:var_9] + adrp x16, var_15 + ldrh w11, [x16, #:lo12:var_15] + adrp x16, struct_obj_2 + 6 + ldrsh w12, [x16, #:lo12:struct_obj_2 + 6] + eor w0, w11, w12 + adrp x16, struct_obj_4 + ldrsh w5, [x16, #:lo12:struct_obj_4] + movn w16, #116, lsl #0 + and w12, w5, w16 + orr w0, w0, w12 + bic w9, w6, w0 + adrp x16, struct_obj_4 + 2 + ldrsb w11, [x16, #:lo12:struct_obj_4 + 2] + orr w5, w9, w11 + ubfiz w10, w5, 0, 16 + adrp x16, struct_obj_4 + 18 + ldrsh w0, [x16, #:lo12:struct_obj_4 + 18] + madd w5, w10, w0, wzr + cmp w8, w5 + cset x15, gt + adrp x16, var_21 + ldrsb w2, [x16, #:lo12:var_21] + orn w29, wzr, w2 + movn w16, #38, lsl #0 + orr w5, w29, w16 + adrp x16, var_23 + ldrh w4, [x16, #:lo12:var_23] + eon w8, w4, w2 + adrp x16, var_38 + ldrsb w17, [x16, #:lo12:var_38] + adrp x16, var_61 + ldrsb w3, [x16, #:lo12:var_61] + bic w29, w17, w3 + eor w1, w8, w29 + and w3, w5, w1 + and w14, w15, w3 + adrp x16, var_37 + strb w14, [x16, #:lo12:var_37] + sbfiz w0, w0, 0, 8 +.L124: + orr w0, wzr, #1 + cbz w0, .L127 + adrp x16, struct_obj_7 + 2 + ldrsh w0, [x16, #:lo12:struct_obj_7 + 2] + cbnz w0, .L128 + adrp x16, var_14 + ldrsb w0, [x16, #:lo12:var_14] + cmp w0, #0 + cset x0, ne + cbnz w0, .L128 + adrp x16, var_20 + ldrh w0, [x16, #:lo12:var_20] + adrp x16, var_129 + strh w0, [x16, #:lo12:var_129] + orr w0, wzr, #1 + cbnz w0, .L129 + orr w0, wzr, #1 + b .L129 +.L128: + adrp x16, struct_obj_4 + 24 + ldrh w29, [x16, #:lo12:struct_obj_4 + 24] + adrp x16, var_58 + ldrsb w5, [x16, #:lo12:var_58] + sdiv w13, w29, w5 + msub w3, w13, w5, w29 + adrp x16, var_27 + ldrsh w4, [x16, #:lo12:var_27] + orn w7, wzr, w4 + sdiv w2, w3, w7 + msub w0, w2, w7, w3 + ubfiz w0, w0, 0, 16 + adrp x16, struct_obj_9 + ldrsh w0, [x16, #:lo12:struct_obj_9] + adrp x16, var_123 + strh w0, [x16, #:lo12:var_123] + adrp x16, struct_obj_4 + 2 + ldrsb w0, [x16, #:lo12:struct_obj_4 + 2] + cbz w0, .L129 + orr w0, wzr, #1 + cbz w0, .L129 + orr w0, wzr, #1 +.L129: + adrp x16, struct_obj_9 + 20 + ldrsh w11, [x16, #:lo12:struct_obj_9 + 20] + adrp x16, var_48 + ldrh w13, [x16, #:lo12:var_48] + add w0, w11, w13 + orn w0, wzr, w0 + adrp x16, struct_obj_4 + 24 + ldrh w1, [x16, #:lo12:struct_obj_4 + 24] + adrp x16, var_9 + ldrh w13, [x16, #:lo12:var_9] + adrp x16, var_56 + ldrh w10, [x16, #:lo12:var_56] + and w29, w10, #-97 + eon w7, w13, w29 + cbz w7, .L130 + adrp x16, struct_obj_3 + 2 + ldrh w11, [x16, #:lo12:struct_obj_3 + 2] + cbz w11, .L131 + adrp x16, var_18 + ldrsb w13, [x16, #:lo12:var_18] +.L131: + orr w5, wzr, #1 + movz w15, #0, lsl #0 + adrp x16, var_64 + ldrsb w0, [x16, #:lo12:var_64] + cmp w0, #0 + csel x17, x5, x15, ne + cbnz w17, .L132 + adrp x16, var_28 + ldrsh w8, [x16, #:lo12:var_28] +.L132: + adrp x16, struct_obj_6 + ldrsh w7, [x16, #:lo12:struct_obj_6] + bic w0, w1, w7 + adrp x16, var_143 + strb w0, [x16, #:lo12:var_143] +.L130: + adrp x16, struct_obj_10 + 6 + ldrsh w10, [x16, #:lo12:struct_obj_10 + 6] + adrp x16, struct_obj_8 + 28 + ldrsh w15, [x16, #:lo12:struct_obj_8 + 28] + sub w4, w10, w15 + adrp x16, struct_obj_5 + 6 + ldrsh w5, [x16, #:lo12:struct_obj_5 + 6] + orr w16, wzr, #2147483647 + add w2, w5, w16 + cmp w4, w2, asr #11 + cset x0, lt + sub w15, wzr, w0 + movz w3, #21384, lsl #0 + adrp x16, struct_obj_4 + 12 + ldrsb w14, [x16, #:lo12:struct_obj_4 + 12] + adrp x16, struct_obj_4 + 8 + ldrsh w8, [x16, #:lo12:struct_obj_4 + 8] + madd w7, w14, w8, wzr + madd w5, w7, w3, wzr + bic w15, w15, w5 + adrp x16, var_11 + ldrsh w17, [x16, #:lo12:var_11] + movz w16, #28869, lsl #0 + orr w12, w17, w16 + adrp x16, struct_obj_10 + 4 + ldrsb w7, [x16, #:lo12:struct_obj_10 + 4] + adrp x16, struct_obj_7 + 4 + ldrsb w9, [x16, #:lo12:struct_obj_7 + 4] + adrp x16, var_31 + ldrsh w1, [x16, #:lo12:var_31] + and w11, w9, w1 + orn w17, w7, w11 + orr w13, w12, w17 + cmp w15, w13 + cset x0, eq + adrp x16, var_55 + strb w0, [x16, #:lo12:var_55] + adrp x16, var_50 + ldrh w29, [x16, #:lo12:var_50] + adrp x16, struct_obj_6 + 4 + ldrh w12, [x16, #:lo12:struct_obj_6 + 4] + adrp x16, var_51 + ldrsh w11, [x16, #:lo12:var_51] + movz w16, #58076, lsl #0 + eor w9, w29, w16 + adrp x16, struct_obj_2 + 2 + ldrh w10, [x16, #:lo12:struct_obj_2 + 2] + adrp x16, struct_obj_8 + ldrh w11, [x16, #:lo12:struct_obj_8] + sub w11, w11, #16384 + sub w11, w11, #954 + lsl w4, w10, w11 + eor w0, w9, w4 + adrp x16, var_8 + ldrh w1, [x16, #:lo12:var_8] + sub w15, w1, #12288 + sub w15, w15, #2352 + asr w29, w0, w15 + adrp x16, var_45 + ldrsb w5, [x16, #:lo12:var_45] + movz w16, #27168, lsl #0 + cmp w5, w16 + cset x12, gt + movz w16, #32858, lsl #0 + cmp w12, w16 + cset x9, lt + orr w0, wzr, w9, asr #3 + lsl w0, w29, w0 + sbfiz w0, w0, 0, 8 + cbz w0, .L127 + adrp x16, var_28 + ldrsh w0, [x16, #:lo12:var_28] + adrp x16, var_29 + ldrh w0, [x16, #:lo12:var_29] + cmp w0, #0 + cset x17, ne + movz w10, #0, lsl #0 + movz w1, #0, lsl #0 + cmp w17, #0 + csel x0, x10, x1, ne + eor w1, w0, #1 + adrp x16, var_47 + ldrsb w4, [x16, #:lo12:var_47] + orr w0, w1, w4 + adrp x16, var_152 + strh w0, [x16, #:lo12:var_152] +.L127: + adrp x16, struct_obj_4 + ldrsh w0, [x16, #:lo12:struct_obj_4] + cmp w0, #0 + cset x0, ne + adrp x16, struct_obj_1 + 2 + ldrh w7, [x16, #:lo12:struct_obj_1 + 2] + adrp x16, var_18 + ldrsb w29, [x16, #:lo12:var_18] + cmp w7, w29 + cset x29, le + adrp x16, var_7 + ldrsb w3, [x16, #:lo12:var_7] + movz w16, #7701, lsl #0 + cmp w3, w16 + cset x2, ne + and w0, w29, w2 + adrp x16, var_1 + ldrh w0, [x16, #:lo12:var_1] + cbnz w0, .L133 + adrp x16, struct_obj_8 + 8 + ldrsb w0, [x16, #:lo12:struct_obj_8 + 8] + cmp w0, #0 + cset x0, ne + cbnz w0, .L133 + adrp x16, struct_obj_8 + 20 + ldrsh w0, [x16, #:lo12:struct_obj_8 + 20] + cbnz w0, .L133 + adrp x16, var_49 + ldrsb w0, [x16, #:lo12:var_49] + cmp w0, #0 + cset x0, ne + cbnz w0, .L133 + orr w0, wzr, #1 + orr w2, wzr, #1 + adrp x16, var_29 + ldrh w11, [x16, #:lo12:var_29] + cmp w11, #0 + csel x0, x0, x2, ne + cbnz w0, .L133 + adrp x16, struct_obj_6 + 2 + ldrh w0, [x16, #:lo12:struct_obj_6 + 2] + sbfiz w0, w0, 0, 16 + cmp w0, #0 + cset x0, eq + cbnz w0, .L134 +.L133: + adrp x16, var_48 + ldrh w0, [x16, #:lo12:var_48] + cbnz w0, .L135 + adrp x16, var_31 + ldrsh w0, [x16, #:lo12:var_31] + cmp w0, #0 + cset x0, ne + cbnz w0, .L135 + adrp x16, struct_obj_8 + 18 + ldrsh w0, [x16, #:lo12:struct_obj_8 + 18] + ubfiz w0, w0, 0, 16 + cbz w0, .L136 + adrp x16, var_25 + ldrsb w0, [x16, #:lo12:var_25] + cmp w0, #0 + cset x0, eq + b .L137 +.L136: + movz w0, #0, lsl #0 + b .L137 +.L135: + movz w0, #0, lsl #0 +.L137: + eor w0, w0, #1 + cbz w0, .L138 +.L134: + adrp x16, struct_obj_4 + 10 + ldrh w15, [x16, #:lo12:struct_obj_4 + 10] + adrp x16, struct_obj_8 + 20 + ldrsh w6, [x16, #:lo12:struct_obj_8 + 20] + orn w2, wzr, w6 + ubfiz w3, w2, 0, 16 + orn w9, wzr, w3 + sdiv w0, w15, w9 + adrp x16, var_156 + strb w0, [x16, #:lo12:var_156] + adrp x16, var_15 + ldrh w2, [x16, #:lo12:var_15] + adrp x16, struct_obj_8 + 26 + ldrsb w11, [x16, #:lo12:struct_obj_8 + 26] + movz w16, #17017, lsl #0 + and w17, w11, w16 + sbfiz w29, w17, 0, 8 + adrp x16, struct_obj_1 + 2 + ldrh w14, [x16, #:lo12:struct_obj_1 + 2] + adrp x16, var_39 + ldrh w10, [x16, #:lo12:var_39] + sub w7, w10, #24576 + sub w7, w7, #3586 + lsl w1, w14, w7 + adrp x16, struct_obj_1 + 4 + ldrh w12, [x16, #:lo12:struct_obj_1 + 4] + and w17, w1, w12 + sub w3, w17, #53248 + sub w3, w3, #2127 + asr w14, w29, w3 + lsl w13, w2, w14 + sbfiz w12, w13, 0, 8 + adrp x16, var_14 + ldrsb w8, [x16, #:lo12:var_14] + adrp x16, struct_obj_4 + 12 + ldrsb w6, [x16, #:lo12:struct_obj_4 + 12] + lsl w3, w8, w6 + ubfiz w6, w3, 0, 16 + movz w2, #19254, lsl #0 + movk w2, #42921, lsl #16 + adrp x16, struct_obj_8 + 30 + ldrsb w29, [x16, #:lo12:struct_obj_8 + 30] + cmp w29, #5 + cset x14, gt + madd w7, w14, w2, wzr + adrp x16, struct_obj_4 + 16 + ldrsb w7, [x16, #:lo12:struct_obj_4 + 16] + adrp x16, struct_obj_8 + 20 + ldrsh w6, [x16, #:lo12:struct_obj_8 + 20] + adrp x16, var_54 + ldrsh w5, [x16, #:lo12:var_54] + adrp x16, var_23 + ldrh w3, [x16, #:lo12:var_23] + orr w16, wzr, #2147483647 + add w4, w5, w16 + and w3, w3, w4 + cbz w3, .L139 + adrp x16, var_11 + ldrsh w5, [x16, #:lo12:var_11] + cbnz w5, .L140 + adrp x16, struct_obj_9 + 24 + ldrh w13, [x16, #:lo12:struct_obj_9 + 24] + cmp w13, #0 + cset x13, ne + cbz w13, .L139 +.L140: + adrp x16, struct_obj_9 + ldrsh w9, [x16, #:lo12:struct_obj_9] + cbz w9, .L139 + cbnz w7, .L139 + adrp x16, struct_obj_2 + 4 + ldrh w17, [x16, #:lo12:struct_obj_2 + 4] + cmp w17, #0 + cset x17, ne +.L139: + adrp x16, struct_obj_6 + 6 + ldrsh w4, [x16, #:lo12:struct_obj_6 + 6] + adrp x16, var_65 + ldrsh w17, [x16, #:lo12:var_65] + sub w7, w4, w17 + adrp x16, struct_obj_4 + 10 + ldrh w3, [x16, #:lo12:struct_obj_4 + 10] + sub w14, w3, #28672 + sub w14, w14, #2102 + lsl w29, w11, w14 + sub w0, w7, w29 + sbfiz w2, w0, 0, 8 + cbz w2, .L141 +.L141: + adrp x16, struct_obj_2 + 4 + ldrh w29, [x16, #:lo12:struct_obj_2 + 4] + cbnz w10, .L142 + adrp x16, struct_obj_4 + 26 + ldrsh w0, [x16, #:lo12:struct_obj_4 + 26] + cmp w0, #0 + cset x0, ne + b .L143 +.L142: + orr w0, wzr, #1 +.L143: + adrp x16, var_45 + ldrsb w1, [x16, #:lo12:var_45] + movz w16, #15962, lsl #0 + orr w14, w1, w16 + adrp x16, struct_obj_9 + 24 + ldrh w10, [x16, #:lo12:struct_obj_9 + 24] + movz w16, #64811, lsl #0 + eor w7, w10, w16 + orr w6, w14, w7 + cmp w29, w6 + cset x5, ge + orn w9, wzr, w0 + ubfiz w29, w9, 0, 16 + cmp w5, w29 + b.gt .L144 + adrp x16, var_3 + ldrsb w0, [x16, #:lo12:var_3] + adrp x16, struct_obj_9 + ldrsh w0, [x16, #:lo12:struct_obj_9] + cmp w0, #40 + b.lt .L145 + adrp x16, struct_obj_6 + ldrsh w14, [x16, #:lo12:struct_obj_6] + adrp x16, struct_obj_5 + 2 + ldrsh w13, [x16, #:lo12:struct_obj_5 + 2] + sdiv w8, w14, w13 + msub w0, w8, w13, w14 + cmp w0, #0 + cset x29, ne + b .L146 +.L145: + orr w29, wzr, #1 +.L146: + movz w6, #92, lsl #0 + movz w7, #0, lsl #0 + adrp x16, struct_obj_7 + 2 + ldrsh w17, [x16, #:lo12:struct_obj_7 + 2] + and w10, w17, w29 + sub w9, w7, w10 + add w4, w9, #32 + asr w0, w6, w4 + adrp x16, var_178 + strh w0, [x16, #:lo12:var_178] + adrp x16, struct_obj_4 + 4 + ldrsh w4, [x16, #:lo12:struct_obj_4 + 4] + adrp x16, var_4 + ldrh w0, [x16, #:lo12:var_4] + eor w4, w4, w0 + adrp x16, struct_obj_9 + 8 + ldrsh w29, [x16, #:lo12:struct_obj_9 + 8] + eor w0, w4, w29 + adrp x16, var_3 + ldrsb w0, [x16, #:lo12:var_3] + adrp x16, var_36 + ldrsh w0, [x16, #:lo12:var_36] + movz w16, #55161, lsl #0 + cmp w0, w16 + cset x8, gt + adrp x16, var_55 + ldrsb w13, [x16, #:lo12:var_55] + add w0, w8, w13 + sbfiz w0, w0, 0, 8 + cmp w0, #0 + cset x0, eq + orn w0, wzr, w0 + adrp x16, var_46 + strh w0, [x16, #:lo12:var_46] + b .L147 +.L144: + adrp x16, var_20 + ldrh w0, [x16, #:lo12:var_20] + cmp w0, #0 + cset x7, ne + adrp x16, struct_obj_6 + 2 + ldrh w17, [x16, #:lo12:struct_obj_6 + 2] + sbfx w5, w17, 30, 2 + orr w0, w7, w5 +.L147: + adrp x16, struct_obj_9 + 2 + ldrsb w0, [x16, #:lo12:struct_obj_9 + 2] + cmp w0, #0 + cset x17, eq + adrp x16, var_19 + ldrsb w10, [x16, #:lo12:var_19] + orn w4, wzr, w10 + madd w0, w17, w4, wzr + orn w0, wzr, w0 + cbz w0, .L138 + adrp x16, var_40 + ldrsb w0, [x16, #:lo12:var_40] + cmp w0, #0 + cset x0, ne + cbz w0, .L138 + adrp x16, var_48 + ldrh w0, [x16, #:lo12:var_48] +.L138: + adrp x16, struct_obj_7 + 2 + ldrsh w0, [x16, #:lo12:struct_obj_7 + 2] + cbnz w0, .L148 + adrp x16, var_57 + ldrsb w0, [x16, #:lo12:var_57] + cmp w0, #0 + cset x5, ne + b .L149 +.L148: + movz w5, #0, lsl #0 +.L149: + adrp x16, struct_obj_8 + 2 + ldrsh w10, [x16, #:lo12:struct_obj_8 + 2] + tbz w10, #5, .L150 + adrp x16, var_1 + ldrh w9, [x16, #:lo12:var_1] + adrp x16, struct_obj_2 + 6 + ldrsh w3, [x16, #:lo12:struct_obj_2 + 6] + sub w8, w9, w3 + sbfiz w9, w8, 0, 16 + cmp w9, #0 + cset x10, eq + b .L151 +.L150: + movz w10, #0, lsl #0 +.L151: + adrp x16, struct_obj_8 + 12 + ldrsb w9, [x16, #:lo12:struct_obj_8 + 12] + adrp x16, struct_obj_9 + 10 + ldrh w0, [x16, #:lo12:struct_obj_9 + 10] + orr w7, w9, w0 + adrp x16, var_11 + ldrsh w3, [x16, #:lo12:var_11] + ubfiz w0, w3, 0, 16 + and w11, w7, w0 + orn w14, wzr, w11 + orr w16, wzr, #2147483647 + add w4, w14, w16 + adrp x16, var_53 + ldrsh w6, [x16, #:lo12:var_53] + adrp x16, struct_obj_8 + ldrh w7, [x16, #:lo12:struct_obj_8] + cmp w6, w7 + cset x12, gt + sub w8, wzr, w3 + madd w0, w12, w8, wzr + madd w6, w5, w0, wzr + asr w0, w4, w6 + and w0, w0, w10 + cbz w0, .L100 + adrp x16, var_1 + ldrh w4, [x16, #:lo12:var_1] + adrp x16, struct_obj_4 + 26 + ldrsh w1, [x16, #:lo12:struct_obj_4 + 26] + movz w0, #21555, lsl #0 + adrp x16, var_39 + strh w0, [x16, #:lo12:var_39] + sub w0, wzr, w4 + adrp x16, var_46 + strh w0, [x16, #:lo12:var_46] + adrp x16, var_65 + ldrsh w0, [x16, #:lo12:var_65] + cbz w0, .L152 + adrp x16, var_7 + ldrsb w0, [x16, #:lo12:var_7] + cmp w0, #0 + cset x13, ne + b .L153 +.L152: + movz w13, #0, lsl #0 +.L153: + orr w3, wzr, #1 + movz w17, #0, lsl #0 + cmp w13, #0 + csel x0, x3, x17, ne + adrp x16, var_5 + ldrh w0, [x16, #:lo12:var_5] + cbnz w0, .L154 + adrp x16, struct_obj_2 + 2 + ldrh w0, [x16, #:lo12:struct_obj_2 + 2] + cbz w0, .L155 + adrp x16, var_43 + ldrh w0, [x16, #:lo12:var_43] + cmp w0, #0 + cset x0, ne + b .L156 +.L155: + movz w0, #0, lsl #0 + b .L156 +.L154: + orr w0, wzr, #1 +.L156: + cbnz w0, .L157 + movz w0, #0, lsl #0 + cbz w0, .L157 + adrp x16, struct_obj_4 + ldrsh w0, [x16, #:lo12:struct_obj_4] + sbfiz w0, w0, 0, 8 +.L157: + orr w3, wzr, #2147418112 + adrp x16, var_4 + ldrh w2, [x16, #:lo12:var_4] + movn w16, #6281, lsl #0 + orr w0, w2, w16 + add w15, w0, #4096 + add w15, w15, #130 + lsl w0, w3, w15 + orn w0, wzr, w0 + adrp x16, var_49 + strb w0, [x16, #:lo12:var_49] + adrp x16, var_54 + ldrsh w3, [x16, #:lo12:var_54] + adrp x16, struct_obj_8 + ldrh w8, [x16, #:lo12:struct_obj_8] + eor w5, w3, w8 + eor w0, w5, w3 + sbfiz w12, w0, 0, 8 + adrp x16, struct_obj_8 + 4 + ldrsb w13, [x16, #:lo12:struct_obj_8 + 4] + orn w13, wzr, w13 + movn w16, #20559, lsl #0 + orr w11, w13, w16 + movn w16, #26, lsl #0 + and w2, w11, w16 + sbfiz w13, w2, 0, 16 + and w0, w12, w13 + adrp x16, struct_obj_9 + 24 + ldrh w0, [x16, #:lo12:struct_obj_9 + 24] + adrp x16, var_43 + ldrh w2, [x16, #:lo12:var_43] + cmp w2, #0 + cset x1, eq + adrp x16, var_7 + ldrsb w17, [x16, #:lo12:var_7] + cmp w1, w17 + cset x17, le + adrp x16, var_28 + ldrsh w14, [x16, #:lo12:var_28] + movz w16, #24924, lsl #0 + and w13, w14, w16 + adrp x16, struct_obj_7 + ldrsb w5, [x16, #:lo12:struct_obj_7] + orn w3, w13, w5 + movz w16, #72, lsl #0 + eor w15, w3, w16 + cmp w17, w15 + cset x12, gt + lsl w0, w0, w12 + cbz w0, .L158 + adrp x16, struct_obj_10 + 6 + ldrsh w13, [x16, #:lo12:struct_obj_10 + 6] + adrp x16, struct_obj_4 + 4 + ldrsh w29, [x16, #:lo12:struct_obj_4 + 4] + adrp x16, var_41 + ldrh w12, [x16, #:lo12:var_41] + cbnz w12, .L159 + adrp x16, var_4 + ldrh w1, [x16, #:lo12:var_4] + cmp w1, #0 + cset x14, ne + cbnz w14, .L159 + adrp x16, var_1 + ldrh w1, [x16, #:lo12:var_1] + cmp w1, #0 + cset x7, eq + cbnz w7, .L159 + orr w15, wzr, #1 + orr w17, wzr, #1 + cmp w13, #0 + csel x3, x15, x17, ne + eor w8, w3, #1 + cbz w8, .L159 + adrp x16, var_42 + ldrsb w4, [x16, #:lo12:var_42] + ubfiz w7, w4, 0, 16 + cbnz w7, .L159 + cmp w29, #0 + cset x0, ne +.L159: + adrp x16, struct_obj_10 + 4 + ldrsb w0, [x16, #:lo12:struct_obj_10 + 4] + movn w16, #30699, lsl #0 + cmp w0, w16 + cset x14, ne + adrp x16, var_58 + ldrsb w5, [x16, #:lo12:var_58] + sub w0, w14, w5 + orn w0, wzr, w0 +.L158: + adrp x16, struct_obj_3 + 2 + ldrh w0, [x16, #:lo12:struct_obj_3 + 2] + movn w16, #11885, lsl #0 + and w0, w0, w16 + sub w0, wzr, w0 + adrp x16, var_217 + strb w0, [x16, #:lo12:var_217] + adrp x16, struct_obj_8 + ldrh w6, [x16, #:lo12:struct_obj_8] + adrp x16, var_54 + ldrsh w8, [x16, #:lo12:var_54] + cbz w8, .L160 + adrp x16, struct_obj_10 + 6 + ldrsh w2, [x16, #:lo12:struct_obj_10 + 6] + cbnz w2, .L161 + adrp x16, struct_obj_8 + 24 + ldrh w5, [x16, #:lo12:struct_obj_8 + 24] + cmp w5, #0 + cset x7, ne + cbnz w7, .L161 +.L160: + adrp x16, struct_obj_8 + 20 + ldrsh w8, [x16, #:lo12:struct_obj_8 + 20] + cbz w8, .L162 + adrp x16, struct_obj_3 + 4 + ldrh w13, [x16, #:lo12:struct_obj_3 + 4] + cmp w13, #0 + cset x11, ne + b .L163 +.L162: + movz w11, #0, lsl #0 +.L163: + eor w7, w11, #1 + cbz w7, .L164 +.L161: + adrp x16, struct_obj_4 + 2 + ldrsb w1, [x16, #:lo12:struct_obj_4 + 2] + cmp w1, #0 + cset x14, eq + cbnz w14, .L165 + orr w7, wzr, #1 + b .L166 +.L165: + orr w7, wzr, #1 + b .L166 +.L164: + movz w7, #0, lsl #0 +.L166: + adrp x16, struct_obj_1 + ldrsh w5, [x16, #:lo12:struct_obj_1] + movz w16, #43755, lsl #0 + eor w11, w5, w16 + adrp x16, var_29 + ldrh w4, [x16, #:lo12:var_29] + eor w3, w4, #124 + and w17, w11, w3 + eor w0, w17, #-128 + movz w16, #32295, lsl #0 + and w13, w0, w16 + movz w16, #110, lsl #0 + eor w0, w13, w16 + orn w2, wzr, w0 + orr w16, wzr, #2147483647 + add w4, w2, w16 + adrp x16, struct_obj_8 + 16 + ldrsb w2, [x16, #:lo12:struct_obj_8 + 16] + cmn w2, #601 + cset x11, le + cmp w6, #0 + cset x10, eq + cmp w11, w10 + cset x8, ne + cmp w13, #0 + cset x3, lt + cmp w8, w3 + cset x8, gt + asr w9, w4, w8 + cmp w7, w9 + b.gt .L167 + adrp x16, var_65 + strh w13, [x16, #:lo12:var_65] + adrp x16, struct_obj_4 + 16 + ldrsb w0, [x16, #:lo12:struct_obj_4 + 16] + orr w16, wzr, #2147483647 + add w15, w0, w16 + adrp x16, var_18 + ldrsb w13, [x16, #:lo12:var_18] + adrp x16, struct_obj_4 + 8 + ldrsh w1, [x16, #:lo12:struct_obj_4 + 8] + movz w16, #68, lsl #0 + orr w14, w1, w16 + adrp x16, struct_obj_1 + 4 + ldrh w1, [x16, #:lo12:struct_obj_1 + 4] + movn w16, #16241, lsl #0 + eor w5, w1, w16 + and w11, w14, w5 + add w9, w11, #57344 + add w9, w9, #1482 + lsl w13, w13, w9 + sub w10, w13, #5042176 + sub w10, w10, #4072 + asr w0, w15, w10 + adrp x16, var_32 + ldrh w0, [x16, #:lo12:var_32] + movn w16, #22, lsl #0 + and w0, w0, w16 + sub w0, wzr, w0 + b .L100 +.L167: + adrp x16, var_50 + ldrh w1, [x16, #:lo12:var_50] + orn w17, wzr, w1 + sbfiz w14, w17, 0, 8 + adrp x16, var_40 + ldrsb w17, [x16, #:lo12:var_40] + orr w4, w17, #6 + sbfiz w8, w4, 0, 16 + bic w10, w14, w8 + adrp x16, struct_obj_9 + 20 + ldrsh w1, [x16, #:lo12:struct_obj_9 + 20] + and w0, w2, w1 + movz w16, #61009, lsl #0 + orr w12, w0, w16 + sub w12, wzr, w12 + orr w16, wzr, #2147483647 + add w14, w12, w16 + movn w5, #52, lsl #0 + adrp x16, struct_obj_1 + 6 + ldrsh w11, [x16, #:lo12:struct_obj_1 + 6] + madd w3, w11, w5, wzr + madd w8, w13, w3, wzr + cmp w8, #0 + cset x29, eq + asr w1, w14, w29 + cmp w10, w1 + cset x0, le + adrp x16, var_234 + strh w0, [x16, #:lo12:var_234] + adrp x16, var_23 + ldrh w0, [x16, #:lo12:var_23] + cbnz w0, .L100 + adrp x16, var_2 + ldrh w0, [x16, #:lo12:var_2] +.L100: + adrp x16, struct_obj_9 + ldrsh w0, [x16, #:lo12:struct_obj_9] + movn w16, #48877, lsl #0 + and w0, w0, w16 + movn w16, #30503, lsl #0 + eor w0, w0, w16 + movz w16, #47, lsl #0 + tst w0, w16 + b.eq .L168 + adrp x16, var_16 + ldrh w0, [x16, #:lo12:var_16] + cbz w0, .L169 + adrp x16, var_37 + ldrsb w0, [x16, #:lo12:var_37] + cmp w0, #0 + cset x29, ne + b .L170 +.L169: + movz w29, #0, lsl #0 +.L170: + adrp x16, var_15 + ldrh w17, [x16, #:lo12:var_15] + adrp x16, var_65 + ldrsh w1, [x16, #:lo12:var_65] + ubfiz w0, w1, 0, 16 + add w10, w0, w29 + cmp w17, w10 + cset x6, le + orn w10, wzr, w6 + movz w16, #32708, lsl #0 + cmp w10, w16 + cset x6, lt + adrp x16, var_37 + ldrsb w0, [x16, #:lo12:var_37] + add w13, w0, w6 + cmn w13, #1594 + cset x4, ge + movz w16, #56889, lsl #0 + eor w8, w1, w16 + orr w16, wzr, #2147483647 + add w6, w8, w16 + adrp x16, struct_obj_9 + 20 + ldrsh w14, [x16, #:lo12:struct_obj_9 + 20] + sub w29, w14, #12288 + sub w29, w29, #1239 + lsl w15, w0, w29 + sub w8, w15, #15200256 + sub w8, w8, #4072 + asr w11, w6, w8 + orn w5, wzr, w11 + orr w16, wzr, #2147483647 + add w11, w5, w16 + adrp x16, struct_obj_1 + 6 + ldrsh w29, [x16, #:lo12:struct_obj_1 + 6] + movn w16, #29412, lsl #0 + orr w10, w29, w16 + adrp x16, var_61 + ldrsb w12, [x16, #:lo12:var_61] + orn w7, w10, w12 + ubfiz w2, w7, 0, 16 + sub w10, w2, #32768 + sub w10, w10, #4095 + lsl w9, w11, w10 + adrp x16, var_22 + ldrsb w5, [x16, #:lo12:var_22] + movn w16, #10106, lsl #0 + and w11, w5, w16 + adrp x16, struct_obj_10 + ldrsb w12, [x16, #:lo12:struct_obj_10] + movn w16, #7265, lsl #0 + orr w6, w12, w16 + add w10, w6, #4096 + add w10, w10, #3136 + lsl w12, w11, w10 + adrp x16, var_28 + ldrsh w3, [x16, #:lo12:var_28] + sbfiz w13, w3, 0, 8 + adrp x16, struct_obj_9 + 22 + ldrh w8, [x16, #:lo12:struct_obj_9 + 22] + sub w10, w8, #24576 + sub w10, w10, #2375 + asr w11, w4, w10 + and w5, w13, w11 + lsl w17, w12, w5 + adrp x16, struct_obj_8 + 24 + ldrh w8, [x16, #:lo12:struct_obj_8 + 24] + movz w16, #31750, lsl #0 + eor w15, w8, w16 + sbfiz w2, w15, 0, 16 + orr w16, wzr, #2147483647 + add w7, w2, w16 + adrp x16, struct_obj_4 + 22 + ldrh w11, [x16, #:lo12:struct_obj_4 + 22] + sbfiz w8, w11, 0, 8 + orn w6, wzr, w8 + add w14, w6, #113 + lsl w29, w7, w14 + movz w16, #45511, lsl #0 + movk w16, #32767, lsl #16 + sub w4, w29, w16 + lsl w2, w17, w4 + orr w0, w9, w2 + sbfiz w7, w0, 0, 8 + adrp x16, struct_obj_1 + ldrsh w5, [x16, #:lo12:struct_obj_1] + adrp x16, var_18 + ldrsb w6, [x16, #:lo12:var_18] + orn w8, wzr, w6 + adrp x16, var_38 + ldrsb w12, [x16, #:lo12:var_38] + eon w12, w8, w12 + bic w1, w5, w12 + adrp x16, struct_obj_8 + 6 + ldrsh w4, [x16, #:lo12:struct_obj_8 + 6] + movn w16, #74, lsl #0 + orr w15, w4, w16 + orn w29, wzr, w15 + madd w1, w1, w29, wzr + adrp x16, var_49 + strb w1, [x16, #:lo12:var_49] + adrp x16, var_30 + ldrh w9, [x16, #:lo12:var_30] + cbnz w9, .L171 + adrp x16, var_17 + ldrsh w8, [x16, #:lo12:var_17] + movz w16, #58592, lsl #0 + and w12, w8, w16 + adrp x16, struct_obj_8 + 18 + ldrsh w3, [x16, #:lo12:struct_obj_8 + 18] + movz w16, #32236, lsl #0 + eor w9, w3, w16 + eor w9, w12, w9 + cmp w9, #0 + cset x1, eq + sub w17, wzr, w1 + cmp w17, #0 + cset x13, eq + adrp x16, struct_obj_8 + strh w13, [x16, #:lo12:struct_obj_8] + adrp x16, var_64 + ldrsb w15, [x16, #:lo12:var_64] + adrp x16, var_32 + ldrh w29, [x16, #:lo12:var_32] + adrp x16, struct_obj_9 + 24 + ldrh w11, [x16, #:lo12:struct_obj_9 + 24] + adrp x16, var_17 + ldrsh w6, [x16, #:lo12:var_17] + sbfiz w8, w6, 0, 8 + adrp x16, struct_obj_8 + 26 + ldrsb w14, [x16, #:lo12:struct_obj_8 + 26] + and w6, w14, w11 + and w4, w8, w6 + orn w4, wzr, w4 + cbz w4, .L172 + adrp x16, var_16 + ldrh w13, [x16, #:lo12:var_16] + adrp x16, var_58 + ldrsb w2, [x16, #:lo12:var_58] + and w29, w13, w2 + sbfiz w17, w29, 0, 8 + movn w16, #29487, lsl #0 + orr w12, w17, w16 + ubfiz w10, w15, 0, 16 + cbnz w10, .L173 + adrp x16, struct_obj_4 + 18 + ldrsh w6, [x16, #:lo12:struct_obj_4 + 18] + cbnz w6, .L173 + adrp x16, var_10 + ldrh w14, [x16, #:lo12:var_10] + cmp w14, #0 + cset x8, ne + cbnz w8, .L173 + adrp x16, struct_obj_4 + 2 + ldrsb w0, [x16, #:lo12:struct_obj_4 + 2] +.L173: + movz w15, #26, lsl #0 + adrp x16, var_297 + strh w15, [x16, #:lo12:var_297] + adrp x16, var_53 + ldrsh w17, [x16, #:lo12:var_53] + adrp x16, var_42 + ldrsb w6, [x16, #:lo12:var_42] + adrp x16, var_65 + strh w6, [x16, #:lo12:var_65] + adrp x16, var_6 + ldrh w0, [x16, #:lo12:var_6] + adrp x16, var_15 + ldrh w1, [x16, #:lo12:var_15] + orn w12, w0, w1 + adrp x16, var_8 + ldrh w2, [x16, #:lo12:var_8] + movn w16, #90, lsl #0 + eor w1, w2, w16 + b .L174 +.L172: + orr w14, wzr, #1 + movz w13, #0, lsl #0 + adrp x16, struct_obj_8 + 18 + ldrsh w8, [x16, #:lo12:struct_obj_8 + 18] + cmp w8, #0 + csel x9, x14, x13, ne + cbz w9, .L174 + adrp x16, struct_obj_2 + 6 + ldrsh w5, [x16, #:lo12:struct_obj_2 + 6] + cbz w5, .L175 + adrp x16, var_20 + ldrh w8, [x16, #:lo12:var_20] + cmp w8, #0 + cset x3, ne +.L175: + adrp x16, var_24 + ldrsh w11, [x16, #:lo12:var_24] + sbfiz w8, w11, 0, 8 + cbnz w8, .L176 +.L176: +.L174: + adrp x16, struct_obj_6 + ldrsh w6, [x16, #:lo12:struct_obj_6] + and w3, w6, w7 + adrp x16, var_12 + ldrh w8, [x16, #:lo12:var_12] + bic w14, w3, w8 + orn w5, wzr, w14, lsl #15 + cbz w5, .L177 + movz w4, #1346, lsl #0 + adrp x16, var_48 + ldrh w12, [x16, #:lo12:var_48] + madd w5, w12, w4, wzr + sbfiz w15, w5, 0, 8 + cmp w15, w7 + cset x13, ne + movz w16, #19262, lsl #0 + cmp w13, w16 + cset x29, lt + cbz w29, .L177 + adrp x16, var_7 + ldrsb w15, [x16, #:lo12:var_7] + movn w13, #42, lsl #0 + adrp x16, struct_obj_4 + 12 + ldrsb w2, [x16, #:lo12:struct_obj_4 + 12] + adrp x16, struct_obj_8 + 16 + ldrsb w17, [x16, #:lo12:struct_obj_8 + 16] + madd w15, w2, w17, wzr + madd w29, w15, w13, wzr + movz w12, #86, lsl #0 + madd w5, w6, w12, wzr + orr w0, wzr, w5, lsr #31 + sxtw x13, w5 + movz x12, #51543, lsl #0 + movk x12, #15108, lsl #16 + madd x4, x13, x12, xzr + orr x1, xzr, x4, asr #32 + add w4, w0, w1, asr #24 + madd w10, w29, w4, wzr + orr w3, wzr, w10, lsl #24 + cmp w3, #0 + cset x8, eq + adrp x16, var_314 + strb w8, [x16, #:lo12:var_314] + adrp x16, struct_obj_7 + 2 + ldrsh w10, [x16, #:lo12:struct_obj_7 + 2] + sbfiz w14, w10, 0, 8 + cmp w14, #1 + cset x15, lt + orn w3, wzr, w15 + orr w14, wzr, #1 + cbz w14, .L178 + orr w29, wzr, #1 + b .L179 +.L178: + movz w29, #0, lsl #0 +.L179: + b .L180 +.L177: + adrp x16, var_28 + ldrsh w0, [x16, #:lo12:var_28] +.L180: + adrp x16, var_12 + ldrh w10, [x16, #:lo12:var_12] + adrp x16, var_62 + ldrh w1, [x16, #:lo12:var_62] + eor w5, w10, w1 + adrp x16, struct_obj_10 + 6 + ldrsh w12, [x16, #:lo12:struct_obj_10 + 6] + adrp x16, struct_obj_2 + ldrsh w8, [x16, #:lo12:struct_obj_2] + orr w14, w12, w8 + orr w1, w5, w14 + movz w16, #6229, lsl #0 + orr w17, w1, w16 + ubfiz w8, w17, 0, 16 + adrp x16, struct_obj_3 + 6 + ldrsh w11, [x16, #:lo12:struct_obj_3 + 6] + orr w2, w11, #8 + orn w2, wzr, w2 + movn w16, #3193, lsl #0 + eor w29, w2, w16 + adrp x16, var_8 + ldrh w0, [x16, #:lo12:var_8] + adrp x16, var_25 + ldrsb w9, [x16, #:lo12:var_25] + and w11, w0, w9 + movn w16, #12881, lsl #0 + and w13, w11, w16 + orn w15, w29, w13 + and w14, w8, w15 + cbnz w14, .L181 + adrp x16, var_46 + ldrh w5, [x16, #:lo12:var_46] + adrp x16, struct_obj_8 + 2 + ldrsh w10, [x16, #:lo12:struct_obj_8 + 2] + adrp x16, var_40 + ldrsb w5, [x16, #:lo12:var_40] + adrp x16, var_22 + ldrsb w6, [x16, #:lo12:var_22] + sdiv w29, w5, w6 + msub w3, w29, w6, w5 + eor w1, w10, w3 +.L181: + adrp x16, var_41 + ldrh w10, [x16, #:lo12:var_41] + adrp x16, struct_obj_4 + 24 + ldrh w3, [x16, #:lo12:struct_obj_4 + 24] + adrp x16, struct_obj_4 + 12 + ldrsb w4, [x16, #:lo12:struct_obj_4 + 12] + cbz w4, .L182 + cmp w3, #0 + cset x17, ne + b .L183 +.L182: + movz w17, #0, lsl #0 +.L183: + adrp x16, var_2 + ldrh w10, [x16, #:lo12:var_2] + adrp x16, var_16 + ldrh w1, [x16, #:lo12:var_16] + eor w2, w10, w1 + movz w16, #40083, lsl #0 + and w29, w1, w16 + sbfiz w5, w29, 0, 8 + cmp w2, w5 + cset x29, lt + movz w16, #14594, lsl #0 + cmp w29, w16 + cset x14, le + adrp x16, var_35 + ldrh w11, [x16, #:lo12:var_35] + sbfiz w29, w11, 0, 8 + movn w16, #31724, lsl #0 + cmp w29, w16 + cset x13, ne + movz w6, #55455, lsl #0 + sdiv w1, w6, w17 + cmp w13, w1 + cset x8, le + sbfiz w17, w0, 0, 8 + sub w6, wzr, w17 + orr w29, wzr, #-9 + sdiv w17, w6, w29 + msub w9, w17, w29, w6 + add w17, w9, #10 + asr w6, w8, w17 + sbfiz w11, w6, 0, 8 + cmp w14, w11 + cset x13, ne + adrp x16, var_358 + strh w13, [x16, #:lo12:var_358] + b .L184 +.L171: + adrp x16, var_33 + ldrh w8, [x16, #:lo12:var_33] + movz w16, #7439, lsl #0 + and w6, w8, w16 + orn w4, wzr, w6 + cbz w4, .L185 + adrp x16, var_27 + ldrsh w4, [x16, #:lo12:var_27] + adrp x16, struct_obj_9 + 24 + ldrh w15, [x16, #:lo12:struct_obj_9 + 24] + cmp w4, w15, lsl #8 + cset x4, ne + b .L186 +.L185: + movz w4, #0, lsl #0 +.L186: + orr w29, wzr, #31 + movz w15, #4200, lsl #0 + adrp x16, struct_obj_10 + ldrsb w13, [x16, #:lo12:struct_obj_10] + madd w15, w13, w15, wzr + madd w9, w15, w29, wzr + adrp x16, var_40 + ldrsb w15, [x16, #:lo12:var_40] + sub w10, wzr, w15 + orn w0, wzr, w10 + madd w15, w9, w0, wzr + sub w1, wzr, w15 + adrp x16, struct_obj_8 + 18 + ldrsh w2, [x16, #:lo12:struct_obj_8 + 18] + sbfiz w15, w2, 0, 8 + cmp w15, #0 + cset x14, eq + adrp x16, var_36 + ldrsh w5, [x16, #:lo12:var_36] + movz w16, #18436, lsl #0 + and w11, w5, w16 + cmp w14, w11 + cset x6, ge + cmp w4, w6 + cset x10, lt + cmp w1, w10 + b.lt .L187 + adrp x16, var_8 + ldrh w2, [x16, #:lo12:var_8] + adrp x16, struct_obj_9 + 10 + ldrh w12, [x16, #:lo12:struct_obj_9 + 10] + cbz w12, .L188 + adrp x16, var_20 + ldrh w9, [x16, #:lo12:var_20] + cmp w9, #0 + cset x1, ne + b .L189 +.L188: + movz w1, #0, lsl #0 +.L189: + orr w2, wzr, #1 + orr w0, wzr, #1 + cmp w1, #0 + csel x2, x2, x0, ne + cbnz w2, .L190 + adrp x16, struct_obj_9 + 22 + ldrh w3, [x16, #:lo12:struct_obj_9 + 22] + cmp w3, #0 + cset x11, ne + b .L191 +.L190: + orr w11, wzr, #1 +.L191: + movz w6, #29648, lsl #0 + movk w6, #1081, lsl #16 + asr w29, w6, w11 + adrp x16, var_240 + strb w29, [x16, #:lo12:var_240] + movz w5, #61679, lsl #0 + adrp x16, var_10 + ldrh w4, [x16, #:lo12:var_10] + madd w4, w4, w5, wzr + adrp x16, var_3 + ldrsb w3, [x16, #:lo12:var_3] + movn w12, #38, lsl #0 + sdiv w5, w3, w12 + msub w3, w5, w12, w3 + cmp w4, w3 + cset x15, gt + movz w2, #90, lsl #0 + adrp x16, var_14 + ldrsb w4, [x16, #:lo12:var_14] + sdiv w12, w2, w4 + orr w17, w15, w12, asr #28 + adrp x16, struct_obj_8 + 8 + ldrsb w8, [x16, #:lo12:struct_obj_8 + 8] + adrp x16, struct_obj_9 + 10 + ldrh w10, [x16, #:lo12:struct_obj_9 + 10] + cmp w8, w10 + cset x10, gt + cmn w10, #57 + cset x5, ge + adrp x16, var_62 + ldrh w6, [x16, #:lo12:var_62] + movz w16, #5083, lsl #0 + orr w15, w6, w16 + orn w3, wzr, w15 + sdiv w6, w5, w3 + cmp w17, w6 + cset x6, lt + sub w5, wzr, w6 + adrp x16, var_241 + strh w5, [x16, #:lo12:var_241] + adrp x16, struct_obj_4 + 26 + ldrsh w12, [x16, #:lo12:struct_obj_4 + 26] + adrp x16, var_33 + ldrh w9, [x16, #:lo12:var_33] + cmn w9, #2638 + cset x10, ge + movz w16, #65439, lsl #0 + movk w16, #127, lsl #16 + cmp w10, w16 + cset x17, lt + adrp x16, var_59 + ldrh w11, [x16, #:lo12:var_59] + orr w0, w11, #48 + sbfiz w8, w0, 0, 8 + orr w16, wzr, #2147483647 + add w29, w8, w16 + and w15, w12, w7 + orn w15, wzr, w15 + add w13, w15, #76 + lsl w4, w29, w13 + ubfiz w15, w4, 0, 16 + cmp w17, w15 + cset x29, ne + adrp x16, struct_obj_9 + 10 + strh w29, [x16, #:lo12:struct_obj_9 + 10] + adrp x16, var_22 + ldrsb w13, [x16, #:lo12:var_22] + sub w2, w9, #36864 + sub w2, w2, #3417 + asr w12, w13, w2 + sbfiz w3, w12, 0, 8 + orr w15, wzr, w3, lsr #31 + sxtw x5, w3 + movz x0, #20745, lsl #0 + movk x0, #21032, lsl #16 + madd x17, x5, x0, xzr + orr x4, xzr, x17, asr #32 + add w4, w15, w4, asr #13 + adrp x16, struct_obj_8 + 4 + ldrsb w1, [x16, #:lo12:struct_obj_8 + 4] + adrp x16, struct_obj_6 + 4 + ldrh w15, [x16, #:lo12:struct_obj_6 + 4] + orr w17, w15, #-127 + orr w14, w1, w17 + adrp x16, var_7 + ldrsb w6, [x16, #:lo12:var_7] + adrp x16, var_1 + ldrh w1, [x16, #:lo12:var_1] + and w5, w6, w1 + movz w16, #18007, lsl #0 + and w17, w5, w16 + eon w29, w14, w17 + adrp x16, var_57 + strb w29, [x16, #:lo12:var_57] + adrp x16, struct_obj_9 + 20 + ldrsh w9, [x16, #:lo12:struct_obj_9 + 20] +.L187: + adrp x16, var_20 + ldrh w29, [x16, #:lo12:var_20] + sbfiz w10, w29, 0, 8 + sub w3, wzr, w10 + adrp x16, struct_obj_8 + 2 + ldrsh w1, [x16, #:lo12:struct_obj_8 + 2] + adrp x16, struct_obj_9 + 2 + ldrsb w0, [x16, #:lo12:struct_obj_9 + 2] + eor w8, w1, w0 + adrp x16, var_45 + ldrsb w12, [x16, #:lo12:var_45] + movz w16, #58, lsl #0 + eor w0, w12, w16 + add w4, w0, #128 + lsl w29, w8, w4 + adrp x16, var_31 + ldrsh w9, [x16, #:lo12:var_31] + cmp w29, w9 + cset x11, eq + adrp x16, struct_obj_1 + 2 + ldrh w2, [x16, #:lo12:struct_obj_1 + 2] + movz w16, #37360, lsl #0 + orr w4, w2, w16 + adrp x16, var_5 + ldrh w8, [x16, #:lo12:var_5] + orn w8, w4, w8 + cmp w8, #8 + cset x17, le + eor w12, w11, w17 + cmp w3, w12 + b.le .L192 + adrp x16, var_58 + ldrsb w9, [x16, #:lo12:var_58] + cbz w9, .L193 + adrp x16, struct_obj_8 + 6 + ldrsh w8, [x16, #:lo12:struct_obj_8 + 6] + cmp w8, #0 + cset x12, ne + b .L194 +.L193: + movz w12, #0, lsl #0 +.L194: + movz w13, #20736, lsl #0 + movk w13, #64035, lsl #16 + orr w14, wzr, #-63 + adrp x16, struct_obj_8 + 8 + ldrsb w11, [x16, #:lo12:struct_obj_8 + 8] + madd w8, w11, w9, wzr + orn w10, wzr, w8 + madd w14, w10, w14, wzr + sdiv w1, w13, w14 + adrp x16, var_22 + ldrsb w10, [x16, #:lo12:var_22] + add w5, w10, #36 + adrp x16, struct_obj_4 + 24 + ldrh w15, [x16, #:lo12:struct_obj_4 + 24] + cmp w15, w12 + cset x15, gt + cmp w5, w15 + cset x14, lt + and w17, w1, w14 + adrp x16, var_52 + ldrsh w5, [x16, #:lo12:var_52] + sbfiz w29, w5, 0, 8 + adrp x16, struct_obj_4 + 26 + ldrsh w4, [x16, #:lo12:struct_obj_4 + 26] + sub w0, w4, #12288 + sub w0, w0, #1655 + movn w12, #37, lsl #0 + adrp x16, struct_obj_9 + 4 + ldrsh w15, [x16, #:lo12:struct_obj_9 + 4] + sub w8, wzr, w15 + sub w12, w12, w8 + add w15, w0, w12 + sub w15, w15, #16384 + sub w15, w15, #223 + movn w16, #27, lsl #0 + eor w6, w17, w16 + orn w13, wzr, w6 + movz w16, #28048, lsl #0 + orr w8, w13, w16 + sbfiz w10, w8, 0, 8 + eor w0, w15, w10 + adrp x16, struct_obj_9 + 24 + strh w0, [x16, #:lo12:struct_obj_9 + 24] + adrp x16, var_16 + ldrh w8, [x16, #:lo12:var_16] + adrp x16, var_58 + ldrsb w1, [x16, #:lo12:var_58] + adrp x16, struct_obj_4 + 10 + ldrh w6, [x16, #:lo12:struct_obj_4 + 10] + sub w11, w6, #28672 + sub w11, w11, #2095 + asr w9, w1, w11 + lsl w8, w8, w17 + sub w17, w8, #4096 + sub w17, w17, #3785 + asr w9, w9, w17 + cmn w9, #17 + cset x12, gt + adrp x16, struct_obj_8 + 16 + ldrsb w11, [x16, #:lo12:struct_obj_8 + 16] + movn w16, #7837, lsl #0 + and w10, w11, w16 + movz w16, #22400, lsl #0 + cmp w10, w16 + cset x13, ne + orn w1, wzr, w29 + eor w29, w13, w1 + sdiv w13, w12, w29 + adrp x16, var_260 + strb w13, [x16, #:lo12:var_260] + b .L195 +.L192: + adrp x16, var_8 + ldrh w10, [x16, #:lo12:var_8] + cbnz w10, .L196 + adrp x16, struct_obj_9 + 8 + ldrsh w2, [x16, #:lo12:struct_obj_9 + 8] + cmp w2, #0 + cset x5, ne + cbz w5, .L197 +.L196: + adrp x16, var_59 + ldrh w12, [x16, #:lo12:var_59] + sbfiz w0, w12, 0, 16 + cmp w0, #0 + cset x29, ne + cbnz w29, .L195 +.L197: + adrp x16, var_51 + ldrsh w17, [x16, #:lo12:var_51] +.L195: + adrp x16, var_39 + ldrh w13, [x16, #:lo12:var_39] + movz w16, #10137, lsl #0 + eor w14, w13, w16 + adrp x16, var_14 + ldrsb w29, [x16, #:lo12:var_14] + movz w16, #33, lsl #0 + eor w3, w29, w16 + and w11, w14, w3 + sbfiz w10, w11, 0, 8 + cbnz w10, .L198 + adrp x16, var_62 + ldrh w8, [x16, #:lo12:var_62] + orn w12, wzr, w8 + adrp x16, struct_obj_8 + 4 + strb w12, [x16, #:lo12:struct_obj_8 + 4] + adrp x16, var_24 + ldrsh w8, [x16, #:lo12:var_24] + adrp x16, var_16 + ldrh w17, [x16, #:lo12:var_16] + adrp x16, var_34 + ldrsb w15, [x16, #:lo12:var_34] + adrp x16, struct_obj_3 + 6 + ldrsh w5, [x16, #:lo12:struct_obj_3 + 6] + adrp x16, var_4 + ldrh w11, [x16, #:lo12:var_4] + adrp x16, struct_obj_9 + 8 + ldrsh w0, [x16, #:lo12:struct_obj_9 + 8] + adrp x16, struct_obj_9 + 10 + ldrh w6, [x16, #:lo12:struct_obj_9 + 10] + madd w29, w0, w6, wzr + sub w6, wzr, w29 + ubfiz w4, w6, 0, 16 + sub w17, wzr, w17 + madd w10, w17, w15, wzr + cmp w8, w10 + cset x0, le + cmp w0, w5 + cset x0, lt + add w8, w11, #24576 + add w8, w8, #1397 + orn w9, wzr, w8 + sbfiz w8, w9, 0, 8 + cmn w8, #123 + cset x13, le + orr w15, w0, w13 + orn w17, wzr, w15 + b .L199 +.L198: + adrp x16, var_51 + ldrsh w8, [x16, #:lo12:var_51] + ubfiz w4, w8, 0, 16 + cbnz w4, .L200 + adrp x16, struct_obj_8 + 16 + ldrsb w0, [x16, #:lo12:struct_obj_8 + 16] + cbz w0, .L201 + adrp x16, var_62 + ldrh w11, [x16, #:lo12:var_62] + cmp w11, #0 + cset x12, ne + b .L202 +.L201: + movz w12, #0, lsl #0 + b .L202 +.L200: + orr w12, wzr, #1 +.L202: + cbz w12, .L203 + adrp x16, var_8 + ldrh w0, [x16, #:lo12:var_8] + cbnz w0, .L203 + adrp x16, struct_obj_4 + 12 + ldrsb w0, [x16, #:lo12:struct_obj_4 + 12] + cmp w0, #0 + cset x0, ne +.L203: + adrp x16, var_21 + ldrsb w17, [x16, #:lo12:var_21] + adrp x16, struct_obj_8 + 28 + ldrsh w0, [x16, #:lo12:struct_obj_8 + 28] + sub w14, w0, w29 + adrp x16, var_17 + ldrsh w0, [x16, #:lo12:var_17] + sub w2, wzr, w0 + add w29, w14, w2 + sub w4, wzr, w29 + adrp x16, struct_obj_9 + 22 + ldrh w3, [x16, #:lo12:struct_obj_9 + 22] + add w11, w4, w3 + sub w8, w17, w11 + adrp x16, var_268 + strb w8, [x16, #:lo12:var_268] +.L199: + adrp x16, struct_obj_9 + 22 + ldrh w3, [x16, #:lo12:struct_obj_9 + 22] + orr w29, wzr, #1 + adrp x16, struct_obj_4 + 2 + ldrsb w10, [x16, #:lo12:struct_obj_4 + 2] + movn w16, #3614, lsl #0 + eor w14, w10, w16 + sbfiz w13, w14, 0, 8 + movn w16, #53, lsl #0 + eor w17, w13, w16 + sub w1, w17, #115 + asr w12, w29, w1 + adrp x16, var_29 + ldrh w11, [x16, #:lo12:var_29] + adrp x16, var_26 + ldrh w15, [x16, #:lo12:var_26] + cmp w11, w15 + cset x1, ne + movz w16, #53609, lsl #0 + eor w17, w1, w16 + adrp x16, var_48 + ldrh w4, [x16, #:lo12:var_48] + orr w2, wzr, w4, lsr #31 + sxtw x0, w4 + movz x11, #31139, lsl #0 + movk x11, #11586, lsl #16 + madd x1, x0, x11, xzr + orr x8, xzr, x1, asr #32 + add w29, w2, w8, asr #11 + movn w16, #23752, lsl #0 + orr w9, w29, w16 + cmp w17, w9 + cset x9, ge + eor w2, w9, #1 + adrp x16, var_284 + strh w2, [x16, #:lo12:var_284] + adrp x16, var_30 + ldrh w13, [x16, #:lo12:var_30] + adrp x16, var_5 + ldrh w0, [x16, #:lo12:var_5] + and w13, w13, w0 + orr w0, w13, #30 + eon w0, w0, w12 + movz w16, #65513, lsl #0 + and w4, w0, w16 + orn w8, wzr, w4 + orr w16, wzr, #2147483647 + add w0, w8, w16 + adrp x16, struct_obj_9 + 8 + ldrsh w29, [x16, #:lo12:struct_obj_9 + 8] + movz w16, #64443, lsl #0 + orr w5, w29, w16 + adrp x16, struct_obj_8 + 20 + ldrsh w6, [x16, #:lo12:struct_obj_8 + 20] + eor w8, w6, #-17 + adrp x16, struct_obj_2 + 4 + ldrh w14, [x16, #:lo12:struct_obj_2 + 4] + movz w16, #46991, lsl #0 + and w1, w14, w16 + orr w6, w8, w1 + sub w1, w6, #45056 + sub w1, w1, #1939 + asr w12, w5, w1 + sub w10, w12, #4091 + lsl w1, w0, w10 + adrp x16, struct_obj_8 + 18 + strh w1, [x16, #:lo12:struct_obj_8 + 18] +.L184: + movz w6, #0, lsl #0 + adrp x16, var_359 + strh w6, [x16, #:lo12:var_359] + adrp x16, var_43 + ldrh w0, [x16, #:lo12:var_43] + sbfiz w2, w0, 0, 16 + adrp x16, struct_obj_4 + 10 + ldrh w9, [x16, #:lo12:struct_obj_4 + 10] + orn w12, wzr, w9 + orr w16, wzr, #2147483647 + add w14, w12, w16 + adrp x16, struct_obj_2 + ldrsh w8, [x16, #:lo12:struct_obj_2] + movn w16, #15348, lsl #0 + and w8, w8, w16 + orr w16, wzr, #2147483647 + add w6, w8, w16 + movz w16, #33773, lsl #0 + movk w16, #32767, lsl #16 + sub w13, w6, w16 + asr w3, w14, w13 + orr w6, w2, w3 + adrp x16, var_7 + ldrsb w3, [x16, #:lo12:var_7] + adrp x16, struct_obj_4 + 22 + ldrh w4, [x16, #:lo12:struct_obj_4 + 22] + eor w13, w3, w4, lsl #5 + adrp x16, var_60 + ldrsh w14, [x16, #:lo12:var_60] + movz w16, #38, lsl #0 + and w15, w14, w16 + adrp x16, struct_obj_9 + 10 + ldrh w0, [x16, #:lo12:struct_obj_9 + 10] + adrp x16, var_50 + ldrh w12, [x16, #:lo12:var_50] + sub w4, w12, #45056 + sub w4, w4, #1901 + asr w0, w0, w4 + lsl w9, w15, w0 + lsl w10, w13, w9 + movz w14, #0, lsl #0 + orr w5, wzr, w14, lsl #11 + movn w16, #76, lsl #0 + orr w15, w5, w16 + bic w8, w10, w15 + and w6, w6, w8 + cbz w6, .L204 + adrp x16, struct_obj_9 + 2 + ldrsb w6, [x16, #:lo12:struct_obj_9 + 2] + movz w6, #18490, lsl #0 + movn w16, #34, lsl #0 + orr w17, w12, w16 + adrp x16, var_56 + ldrh w4, [x16, #:lo12:var_56] + eon w2, w17, w4 + sub w29, w2, #16384 + sub w29, w29, #3818 + lsl w11, w6, w29 + adrp x16, var_367 + strb w11, [x16, #:lo12:var_367] + adrp x16, var_46 + ldrh w0, [x16, #:lo12:var_46] + adrp x16, struct_obj_9 + 10 + ldrh w3, [x16, #:lo12:struct_obj_9 + 10] + adrp x16, var_35 + ldrh w8, [x16, #:lo12:var_35] + cbnz w8, .L205 + adrp x16, struct_obj_4 + 18 + ldrsh w6, [x16, #:lo12:struct_obj_4 + 18] + cmp w6, #0 + cset x8, ne + cbnz w8, .L205 + cbnz w3, .L206 + adrp x16, struct_obj_5 + ldrsb w6, [x16, #:lo12:struct_obj_5] + cmp w6, #0 + cset x17, ne + b .L207 +.L206: + orr w17, wzr, #1 + b .L207 +.L205: + orr w17, wzr, #1 +.L207: + adrp x16, struct_obj_8 + 26 + ldrsb w14, [x16, #:lo12:struct_obj_8 + 26] + adrp x16, struct_obj_1 + 6 + ldrsh w8, [x16, #:lo12:struct_obj_1 + 6] + eor w9, w14, w8 + movn w16, #14805, lsl #0 + eor w0, w0, w16 + eor w9, w9, w0 + cbz w9, .L208 + adrp x16, struct_obj_8 + 4 + ldrsb w15, [x16, #:lo12:struct_obj_8 + 4] + and w29, w8, w15 + adrp x16, struct_obj_5 + 6 + ldrsh w0, [x16, #:lo12:struct_obj_5 + 6] + bic w8, w29, w0 + cmp w8, #0 + cset x8, ne + b .L209 +.L208: + movz w8, #0, lsl #0 +.L209: + movz w14, #17, lsl #0 + adrp x16, var_56 + ldrh w1, [x16, #:lo12:var_56] + sub w3, w1, #16384 + sub w3, w3, #3797 + lsl w6, w14, w3 + orn w1, wzr, w6 + cmp w1, w17 + cset x17, gt + cmp w17, w8 + b.le .L210 + movz w17, #0, lsl #0 + orn w14, wzr, w7 + ubfiz w4, w14, 0, 16 + sdiv w15, w17, w4 + msub w13, w15, w4, w17 + movz w16, #14314, lsl #0 + cmp w13, w16 + cset x2, le + b .L211 +.L210: + orr w2, wzr, #1 +.L211: + adrp x16, var_46 + strh w2, [x16, #:lo12:var_46] + adrp x16, var_20 + ldrh w8, [x16, #:lo12:var_20] + adrp x16, var_24 + ldrsh w9, [x16, #:lo12:var_24] + adrp x16, struct_obj_8 + 20 + ldrsh w12, [x16, #:lo12:struct_obj_8 + 20] + add w3, w9, w12 + add w6, w3, #16384 + add w6, w6, #3130 + ubfiz w11, w6, 0, 16 + adrp x16, struct_obj_3 + 2 + ldrh w6, [x16, #:lo12:struct_obj_3 + 2] + movz w16, #24836, lsl #0 + and w1, w6, w16 + movz w16, #14314, lsl #0 + eor w5, w1, w16 + orn w15, wzr, w5 + sdiv w2, w11, w15 + msub w13, w2, w15, w11 +.L204: + adrp x16, struct_obj_8 + 12 + ldrsb w2, [x16, #:lo12:struct_obj_8 + 12] + sub w13, wzr, w2 + cbz w13, .L212 + orn w13, wzr, w7 + sub w2, wzr, w13 + adrp x16, var_392 + strh w2, [x16, #:lo12:var_392] + adrp x16, var_14 + ldrsb w6, [x16, #:lo12:var_14] + adrp x16, struct_obj_9 + 10 + ldrh w14, [x16, #:lo12:struct_obj_9 + 10] + cbnz w14, .L213 + adrp x16, var_47 + ldrsb w1, [x16, #:lo12:var_47] +.L213: + adrp x16, var_65 + ldrsh w29, [x16, #:lo12:var_65] + adrp x16, var_35 + ldrh w17, [x16, #:lo12:var_35] + sub w11, w17, #12288 + sub w11, w11, #2120 + asr w10, w17, w11 + ubfiz w17, w10, 0, 16 + adrp x16, struct_obj_10 + ldrsb w1, [x16, #:lo12:struct_obj_10] + ubfiz w29, w1, 0, 16 + cbnz w29, .L212 + adrp x16, var_63 + ldrsh w4, [x16, #:lo12:var_63] + cbz w4, .L212 + cbz w6, .L212 + adrp x16, var_3 + ldrsb w6, [x16, #:lo12:var_3] + cmp w6, #0 + cset x12, ne +.L212: + orr w10, wzr, #1 + movz w6, #0, lsl #0 + adrp x16, struct_obj_1 + 4 + ldrh w5, [x16, #:lo12:struct_obj_1 + 4] + cmp w5, #0 + csel x0, x10, x6, ne + cbz w0, .L214 + adrp x16, var_26 + ldrh w5, [x16, #:lo12:var_26] + cbnz w5, .L215 + cmp w7, #0 + cset x17, eq + cbnz w17, .L214 +.L215: + movz w1, #0, lsl #0 + b .L216 +.L214: + adrp x16, struct_obj_4 + 14 + ldrsh w3, [x16, #:lo12:struct_obj_4 + 14] + cmp w3, #0 + cset x8, ne + eor w1, w8, #1 +.L216: + cbz w1, .L217 + adrp x16, var_6 + ldrh w0, [x16, #:lo12:var_6] + orn w0, wzr, w0 + movz w16, #45366, lsl #0 + and w4, w0, w16 + adrp x16, struct_obj_8 + 4 + ldrsb w14, [x16, #:lo12:struct_obj_8 + 4] + adrp x16, struct_obj_8 + 12 + ldrsb w3, [x16, #:lo12:struct_obj_8 + 12] + and w3, w14, w3 + adrp x16, var_55 + ldrsb w13, [x16, #:lo12:var_55] + orn w0, w3, w13 + and w0, w4, w0 + sbfiz w0, w0, 0, 8 + orn w0, wzr, w0 + cbz w0, .L218 + adrp x16, struct_obj_6 + 4 + ldrh w0, [x16, #:lo12:struct_obj_6 + 4] + adrp x16, var_63 + ldrsh w0, [x16, #:lo12:var_63] + ubfiz w6, w0, 0, 16 + adrp x16, struct_obj_4 + 18 + ldrsh w11, [x16, #:lo12:struct_obj_4 + 18] + movz w16, #888, lsl #0 + eor w7, w11, w16 + eon w0, w6, w7 + adrp x16, var_61 + ldrsb w0, [x16, #:lo12:var_61] + cbz w0, .L219 + adrp x16, struct_obj_9 + 8 + ldrsh w0, [x16, #:lo12:struct_obj_9 + 8] +.L219: + orr w13, wzr, #1 + adrp x16, var_26 + ldrh w8, [x16, #:lo12:var_26] + cbnz w8, .L220 + orr w12, wzr, #1 + b .L221 +.L220: + movz w12, #0, lsl #0 +.L221: + cmp w13, #0 + cset x7, lt + adrp x16, struct_obj_4 + 14 + ldrsh w0, [x16, #:lo12:struct_obj_4 + 14] + sub w8, wzr, w0 + adrp x16, var_56 + ldrh w4, [x16, #:lo12:var_56] + sbfiz w5, w4, 0, 8 + cmp w8, w5 + cset x10, ne + cmp w12, w10 + cset x4, lt + asr w2, w7, w4 + adrp x16, var_52 + ldrsh w3, [x16, #:lo12:var_52] + movz w16, #6800, lsl #0 + eor w12, w3, w16 + orr w4, w12, #4 + movn w16, #20, lsl #0 + eor w10, w4, w16 + cmp w2, w10 + cset x0, eq + adrp x16, struct_obj_5 + 6 + strh w0, [x16, #:lo12:struct_obj_5 + 6] +.L218: + adrp x16, var_16 + ldrh w9, [x16, #:lo12:var_16] + adrp x16, var_60 + ldrsh w1, [x16, #:lo12:var_60] + eor w0, w9, w1 + movn w16, #8171, lsl #0 + eor w0, w0, w16 + sbfiz w11, w0, 0, 8 + adrp x16, var_63 + ldrsh w2, [x16, #:lo12:var_63] + eon w0, w11, w2 + cbz w0, .L222 + adrp x16, var_23 + ldrh w14, [x16, #:lo12:var_23] + adrp x16, var_30 + ldrh w2, [x16, #:lo12:var_30] + orn w29, wzr, w2 + cbz w29, .L222 +.L222: + movz w5, #29097, lsl #0 + movk w5, #32767, lsl #16 + adrp x16, struct_obj_1 + 6 + ldrsh w10, [x16, #:lo12:struct_obj_1 + 6] + adrp x16, var_2 + ldrh w11, [x16, #:lo12:var_2] + sub w1, w11, #16384 + sub w1, w1, #1397 + lsl w6, w10, w1 + sub w0, w6, #4096 + sub w0, w0, #1824 + lsl w15, w5, w0 + adrp x16, struct_obj_4 + 8 + ldrsh w3, [x16, #:lo12:struct_obj_4 + 8] + sbfiz w17, w3, 0, 8 + bic w5, w15, w17 + adrp x16, var_33 + ldrh w15, [x16, #:lo12:var_33] + orr w2, wzr, w15, lsl #11 + adrp x16, var_20 + ldrh w6, [x16, #:lo12:var_20] + sbfiz w6, w6, 0, 16 + add w17, w6, #12288 + add w17, w17, #3732 + asr w29, w2, w17 + movz w17, #65433, lsl #0 + movk w17, #32767, lsl #16 + adrp x16, struct_obj_4 + 20 + ldrsh w14, [x16, #:lo12:struct_obj_4 + 20] + movn w16, #7862, lsl #0 + eor w0, w14, w16 + sub w7, w0, #20480 + sub w7, w7, #1456 + asr w0, w17, w7 + eor w11, w29, w0 + eor w29, w5, w11 + adrp x16, struct_obj_4 + 16 + ldrsb w4, [x16, #:lo12:struct_obj_4 + 16] + orn w0, w29, w4 + cbz w0, .L223 + movz w0, #25335, lsl #0 + adrp x16, var_36 + strh w0, [x16, #:lo12:var_36] + adrp x16, struct_obj_2 + 4 + ldrh w0, [x16, #:lo12:struct_obj_2 + 4] + movz w16, #57552, lsl #0 + eor w2, w0, w16 + adrp x16, var_38 + ldrsb w7, [x16, #:lo12:var_38] + movz w16, #2460, lsl #0 + and w13, w7, w16 + asr w0, w2, w13 + adrp x16, var_37 + ldrsb w0, [x16, #:lo12:var_37] + orn w0, wzr, w0 +.L223: + adrp x16, struct_obj_8 + ldrh w13, [x16, #:lo12:struct_obj_8] + adrp x16, struct_obj_9 + 4 + ldrsh w7, [x16, #:lo12:struct_obj_9 + 4] + sub w2, w7, #28672 + sub w2, w2, #3284 + lsl w8, w13, w2 + adrp x16, struct_obj_8 + 8 + ldrsb w6, [x16, #:lo12:struct_obj_8 + 8] + bic w3, w8, w6 + adrp x16, var_56 + ldrh w17, [x16, #:lo12:var_56] + adrp x16, var_43 + ldrh w29, [x16, #:lo12:var_43] + adrp x16, var_13 + ldrsh w15, [x16, #:lo12:var_13] + add w8, w15, #20480 + add w8, w8, #3434 + asr w6, w29, w8 + adrp x16, struct_obj_4 + 14 + ldrsh w12, [x16, #:lo12:struct_obj_4 + 14] + adrp x16, var_6 + ldrh w2, [x16, #:lo12:var_6] + and w11, w12, w2 + sub w4, w11, #32768 + sub w4, w4, #2751 + asr w4, w6, w4 + orr w8, w17, w4 + eon w14, w3, w8 + cbz w14, .L224 + adrp x16, var_20 + ldrh w6, [x16, #:lo12:var_20] + adrp x16, var_18 + ldrsb w3, [x16, #:lo12:var_18] + and w0, w6, w3 + adrp x16, struct_obj_7 + ldrsb w12, [x16, #:lo12:struct_obj_7] + orn w13, w0, w12 + adrp x16, var_57 + ldrsb w29, [x16, #:lo12:var_57] + movn w16, #5371, lsl #0 + orr w10, w29, w16 + eon w29, w13, w10 + adrp x16, var_28 + ldrsh w2, [x16, #:lo12:var_28] + movn w11, #23905, lsl #0 + adrp x16, var_22 + ldrsb w9, [x16, #:lo12:var_22] + adrp x16, struct_obj_4 + 18 + ldrsh w13, [x16, #:lo12:struct_obj_4 + 18] + add w1, w9, w13 + sub w5, w11, w1 + sub w7, w2, w5 + adrp x16, var_2 + ldrh w8, [x16, #:lo12:var_2] + adrp x16, struct_obj_10 + ldrsb w12, [x16, #:lo12:struct_obj_10] + add w9, w8, w12 + adrp x16, struct_obj_10 + 4 + ldrsb w5, [x16, #:lo12:struct_obj_10 + 4] + add w14, w9, w5 + adrp x16, var_23 + ldrh w1, [x16, #:lo12:var_23] + sub w12, w1, #28672 + sub w12, w12, #777 + sub w6, wzr, w12 + add w8, w14, w6 + sub w8, w7, w8 + add w3, w8, #53248 + add w3, w3, #2668 + adrp x16, struct_obj_9 + 22 + ldrh w13, [x16, #:lo12:struct_obj_9 + 22] + adrp x16, struct_obj_9 + 10 + ldrh w9, [x16, #:lo12:struct_obj_9 + 10] + cbnz w15, .L225 + adrp x16, var_48 + ldrh w10, [x16, #:lo12:var_48] + cmp w10, #0 + cset x6, eq + b .L226 +.L225: + orr w6, wzr, #1 +.L226: + orr w8, wzr, #1 + movz w29, #0, lsl #0 + cmp w6, #0 + csel x13, x8, x29, ne +.L224: + adrp x16, var_60 + ldrsh w4, [x16, #:lo12:var_60] + movz w29, #59623, lsl #0 + adrp x16, struct_obj_2 + 6 + ldrsh w13, [x16, #:lo12:struct_obj_2 + 6] + adrp x16, var_16 + ldrh w15, [x16, #:lo12:var_16] + madd w10, w13, w15, wzr + sbfiz w9, w10, 0, 8 + adrp x16, var_34 + ldrsb w15, [x16, #:lo12:var_34] + adrp x16, var_24 + ldrsh w14, [x16, #:lo12:var_24] + sbfiz w10, w14, 0, 16 + cmp w15, w10 + cset x15, lt + adrp x16, var_14 + ldrsb w11, [x16, #:lo12:var_14] + adrp x16, var_33 + ldrh w7, [x16, #:lo12:var_33] + adrp x16, struct_obj_3 + ldrsh w2, [x16, #:lo12:struct_obj_3] + orn w0, wzr, w2 + adrp x16, struct_obj_6 + 4 + ldrh w3, [x16, #:lo12:struct_obj_6 + 4] + add w8, w3, w4 + madd w2, w0, w8, wzr + cbz w2, .L227 + movz w2, #0, lsl #0 + movz w3, #0, lsl #0 + adrp x16, struct_obj_6 + ldrsh w8, [x16, #:lo12:struct_obj_6] + cmp w8, #0 + csel x0, x2, x3, ne + sbfiz w13, w7, 0, 8 + cmp w0, w13 + cset x1, le + cbnz w1, .L228 +.L227: + madd w5, w9, w29, wzr + bic w12, w11, w11 + and w12, w15, w12 + madd w3, w5, w12, wzr + adrp x16, struct_obj_5 + 2 + ldrsh w5, [x16, #:lo12:struct_obj_5 + 2] + movz w16, #11652, lsl #0 + and w10, w5, w16 + bic w15, w3, w10 + sbfiz w7, w4, 0, 8 + ubfiz w11, w7, 0, 16 + orn w7, w15, w11 + cmp w7, #0 + cset x15, ne + cbnz w15, .L228 + orr w13, wzr, #1 + orr w15, wzr, #1 + adrp x16, struct_obj_4 + 22 + ldrh w29, [x16, #:lo12:struct_obj_4 + 22] + movn w16, #26751, lsl #0 + tst w29, w16 + csel x0, x13, x15, ne + adrp x16, var_32 + ldrh w15, [x16, #:lo12:var_32] + orr w6, wzr, #-65 + sdiv w1, w15, w6 + movz w16, #45959, lsl #0 + cmp w1, w16 + cset x3, ge + sub w0, w0, w3 + cbz w0, .L229 + adrp x16, struct_obj_3 + 6 + ldrsh w0, [x16, #:lo12:struct_obj_3 + 6] +.L229: + adrp x16, struct_obj_3 + 6 + ldrsh w0, [x16, #:lo12:struct_obj_3 + 6] + b .L168 +.L228: + adrp x16, var_18 + ldrsb w0, [x16, #:lo12:var_18] + cbz w0, .L230 + cmp w17, #0 + cset x0, ne + cbnz w0, .L168 +.L230: + adrp x16, struct_obj_5 + 6 + ldrsh w0, [x16, #:lo12:struct_obj_5 + 6] + b .L168 +.L217: + adrp x16, struct_obj_4 + 26 + ldrsh w0, [x16, #:lo12:struct_obj_4 + 26] + adrp x16, var_35 + ldrh w1, [x16, #:lo12:var_35] + sbfiz w14, w1, 0, 16 + adrp x16, struct_obj_4 + ldrsh w2, [x16, #:lo12:struct_obj_4] + orn w17, w14, w2 + cmp w0, w17 + cset x8, gt + adrp x16, struct_obj_4 + 8 + ldrsh w1, [x16, #:lo12:struct_obj_4 + 8] + movz w16, #39209, lsl #0 + eor w0, w1, w16 + cmp w8, w0 + cset x0, gt + adrp x16, var_14 + ldrsb w14, [x16, #:lo12:var_14] + adrp x16, struct_obj_3 + 4 + ldrh w29, [x16, #:lo12:struct_obj_3 + 4] + cmp w14, w29 + cset x14, eq + adrp x16, struct_obj_4 + 18 + ldrsh w9, [x16, #:lo12:struct_obj_4 + 18] + movz w16, #56773, lsl #0 + cmp w9, w16 + cset x17, ge + madd w14, w14, w17, wzr + sbfiz w4, w14, 0, 16 + adrp x16, var_13 + ldrsh w14, [x16, #:lo12:var_13] + orr w16, wzr, #2147483647 + add w11, w14, w16 + orr w14, wzr, w11, asr #29 + adrp x16, struct_obj_2 + 2 + ldrh w29, [x16, #:lo12:struct_obj_2 + 2] + sub w5, w29, #24576 + sub w5, w5, #1173 + lsl w9, w14, w5 + cmp w4, w9 + cset x8, le + cmp w0, w8 + cset x14, ne + cbz w14, .L168 + adrp x16, var_10 + ldrh w0, [x16, #:lo12:var_10] + sbfiz w0, w0, 0, 8 + orr w5, wzr, #1 + movz w12, #0, lsl #0 + adrp x16, var_23 + ldrh w17, [x16, #:lo12:var_23] + sub w2, wzr, w5 + movz w1, #44106, lsl #0 + movk w1, #32767, lsl #16 + asr w1, w1, w12 + cmp w2, w1 + cset x8, lt + cmp w17, w8 + cset x0, lt + adrp x16, var_53 + strh w0, [x16, #:lo12:var_53] + adrp x16, struct_obj_2 + 2 + ldrh w0, [x16, #:lo12:struct_obj_2 + 2] + orn w0, wzr, w0 + orn w0, wzr, w0 + movz w16, #41, lsl #0 + orr w0, w0, w16 + sbfiz w3, w0, 0, 8 + adrp x16, struct_obj_4 + 18 + ldrsh w11, [x16, #:lo12:struct_obj_4 + 18] + cmp w11, #0 + cset x0, eq + movz w1, #65006, lsl #0 + adrp x16, struct_obj_8 + 22 + ldrh w2, [x16, #:lo12:struct_obj_8 + 22] + madd w11, w2, w1, wzr + adrp x16, struct_obj_8 + 6 + ldrsh w15, [x16, #:lo12:struct_obj_8 + 6] + sub w1, wzr, w15 + sdiv w6, w11, w1 + ubfiz w4, w6, 0, 16 + madd w15, w0, w4, wzr + adrp x16, struct_obj_8 + 26 + ldrsb w11, [x16, #:lo12:struct_obj_8 + 26] + adrp x16, struct_obj_5 + ldrsb w6, [x16, #:lo12:struct_obj_5] + eor w9, w11, w6 + adrp x16, var_37 + ldrsb w29, [x16, #:lo12:var_37] + movz w16, #2436, lsl #0 + orr w14, w29, w16 + eor w6, w9, w14 + eon w14, w6, w3 + cmp w15, w14 + cset x0, lt + adrp x16, var_468 + strb w0, [x16, #:lo12:var_468] +.L168: + adrp x16, var_10 + ldrh w4, [x16, #:lo12:var_10] + adrp x16, struct_obj_2 + 2 + ldrh w9, [x16, #:lo12:struct_obj_2 + 2] + sub w10, w9, #24576 + sub w10, w10, #1167 + asr w4, w4, w10 + adrp x16, var_49 + ldrsb w6, [x16, #:lo12:var_49] + orn w10, wzr, w6 + add w7, w10, #31 + lsl w1, w4, w7 + orn w13, wzr, w1 + adrp x16, var_36 + ldrsh w14, [x16, #:lo12:var_36] + adrp x16, var_18 + ldrsb w9, [x16, #:lo12:var_18] + adrp x16, struct_obj_2 + ldrsh w3, [x16, #:lo12:struct_obj_2] + bic w1, w9, w3 + and w9, w14, w1 + eon w4, w13, w9 + sbfiz w14, w4, 0, 16 + adrp x16, var_9 + ldrh w4, [x16, #:lo12:var_9] + sbfiz w5, w4, 0, 8 + adrp x16, struct_obj_8 + 16 + ldrsb w2, [x16, #:lo12:struct_obj_8 + 16] + movn w16, #2066, lsl #0 + eor w13, w2, w16 + eon w6, w13, w6 + movz w7, #36764, lsl #0 + movk w7, #32767, lsl #16 + adrp x16, var_45 + ldrsb w8, [x16, #:lo12:var_45] + adrp x16, var_27 + ldrsh w9, [x16, #:lo12:var_27] + orr w8, w8, w9 + add w1, w8, #3 + lsl w15, w7, w1 + orr w0, w6, w15 + adrp x16, var_65 + ldrsh w15, [x16, #:lo12:var_65] + add w29, w15, #12288 + add w29, w29, #558 + lsl w6, w0, w29 + cmp w5, w6 + cset x15, ne + adrp x16, var_26 + ldrh w10, [x16, #:lo12:var_26] + movz w11, #5330, lsl #0 + adrp x16, struct_obj_1 + 4 + ldrh w29, [x16, #:lo12:struct_obj_1 + 4] + madd w0, w29, w11, wzr + movz w1, #101, lsl #0 + madd w17, w29, w1, wzr + sdiv w13, w0, w17 + orn w9, wzr, w13 + adrp x16, struct_obj_8 + 14 + ldrh w7, [x16, #:lo12:struct_obj_8 + 14] + madd w7, w9, w7, wzr + adrp x16, struct_obj_2 + 6 + ldrsh w29, [x16, #:lo12:struct_obj_2 + 6] + adrp x16, var_48 + ldrh w2, [x16, #:lo12:var_48] + madd w5, w29, w2, wzr + adrp x16, struct_obj_3 + 4 + ldrh w17, [x16, #:lo12:struct_obj_3 + 4] + sub w6, w5, w17 + add w9, w6, #4096 + add w9, w9, #3658 + orr w2, w7, w9 + ubfiz w1, w2, 0, 16 + adrp x16, var_47 + ldrsb w11, [x16, #:lo12:var_47] + orn w5, w10, w11 + movz w29, #33232, lsl #0 + adrp x16, var_43 + ldrh w12, [x16, #:lo12:var_43] + madd w13, w12, w29, wzr + sub w29, wzr, w13 + orn w13, wzr, w29 + movz w16, #2753, lsl #0 + and w6, w13, w16 + sdiv w7, w5, w6 + msub w11, w7, w6, w5 + ubfiz w0, w11, 0, 16 + adrp x16, struct_obj_10 + 4 + ldrsb w9, [x16, #:lo12:struct_obj_10 + 4] + adrp x16, struct_obj_1 + 2 + ldrh w7, [x16, #:lo12:struct_obj_1 + 2] + sdiv w29, w9, w7 + adrp x16, var_29 + ldrh w7, [x16, #:lo12:var_29] + sdiv w11, w29, w7 + msub w13, w11, w7, w29 + sbfiz w11, w13, 0, 8 + cmp w11, #1 + b.le .L231 + movn w29, #123, lsl #0 + adrp x16, var_33 + ldrh w11, [x16, #:lo12:var_33] + orn w8, wzr, w11 + sub w11, w29, w8 + orn w13, wzr, w11 + adrp x16, var_16 + ldrh w5, [x16, #:lo12:var_16] + adrp x16, struct_obj_6 + 2 + ldrh w12, [x16, #:lo12:struct_obj_6 + 2] + cmp w5, w12 + cset x5, ge + adrp x16, var_3 + ldrsb w2, [x16, #:lo12:var_3] + adrp x16, struct_obj_8 + 8 + ldrsb w8, [x16, #:lo12:struct_obj_8 + 8] + orr w29, w2, w8 + cmp w5, w29 + cset x2, ne + movn w16, #7351, lsl #0 + and w11, w2, w16 + cmp w13, w11 + cset x6, eq + sub w2, wzr, w6 + cbnz w2, .L232 + adrp x16, struct_obj_6 + 6 + ldrsh w7, [x16, #:lo12:struct_obj_6 + 6] + cbz w7, .L233 + adrp x16, struct_obj_7 + ldrsb w7, [x16, #:lo12:struct_obj_7] + cmp w7, #0 + cset x11, ne +.L233: + movn w8, #10, lsl #0 + adrp x16, var_522 + strb w8, [x16, #:lo12:var_522] + adrp x16, var_1 + ldrh w3, [x16, #:lo12:var_1] + adrp x16, var_30 + ldrh w13, [x16, #:lo12:var_30] + adrp x16, struct_obj_4 + 24 + ldrh w19, [x16, #:lo12:struct_obj_4 + 24] + adrp x16, struct_obj_5 + ldrsb w7, [x16, #:lo12:struct_obj_5] + cbz w17, .L234 + adrp x16, var_17 + ldrsh w2, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w11, [x16, #:lo12:var_9] + sub w11, w11, #12288 + sub w11, w11, #1187 + lsl w4, w2, w11 + cmp w4, #0 + cset x20, ne + b .L235 +.L234: + movz w20, #0, lsl #0 +.L235: + adrp x16, struct_obj_3 + 4 + ldrh w9, [x16, #:lo12:struct_obj_3 + 4] + cbz w9, .L236 + adrp x16, var_17 + ldrsh w29, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w17, [x16, #:lo12:var_9] + sub w17, w17, #12288 + sub w17, w17, #1187 + lsl w12, w29, w17 + cmp w12, #0 + cset x29, ne + b .L237 +.L236: + movz w29, #0, lsl #0 +.L237: + adrp x16, struct_obj_4 + 4 + ldrsh w2, [x16, #:lo12:struct_obj_4 + 4] + movz w16, #24281, lsl #0 + and w17, w2, w16 + movn w16, #76, lsl #0 + eor w11, w9, w16 + orr w8, wzr, w13, asr #7 + movz w16, #65483, lsl #0 + movk w16, #8191, lsl #16 + orr w6, w8, w16 + and w11, w11, w6 + adrp x16, struct_obj_2 + ldrsh w2, [x16, #:lo12:struct_obj_2] + sub w2, wzr, w2 + sub w12, wzr, w2 + sub w4, wzr, w3 + madd w2, w12, w4, wzr + cmp w29, #4 + cset x6, ne + cmp w2, w6 + cset x3, gt + cmp w11, w3 + cset x8, ge + asr w3, w17, w8 + sub w8, w13, #40960 + sub w8, w8, #1739 + asr w5, w3, w8 + cmp w5, #0 + cset x5, ne + adrp x16, var_36 + ldrsh w12, [x16, #:lo12:var_36] + tst w12, #126 + cset x13, eq + cmp w20, #4 + cset x6, ne + cmp w2, w6 + cset x2, gt + cmp w11, w2 + cset x29, ge + movn w16, #1113, lsl #0 + eor w2, w19, w16 + ubfiz w6, w2, 0, 16 + movn w16, #28029, lsl #0 + cmp w6, w16 + cset x17, ge + cmp w29, w17 + cset x29, gt + sub w29, w29, w5 + and w11, w13, w29 + cbnz w11, .L238 + adrp x16, struct_obj_4 + 20 + ldrsh w17, [x16, #:lo12:struct_obj_4 + 20] +.L238: + movn w9, #0, lsl #0 + movz w2, #10162, lsl #0 + adrp x16, struct_obj_1 + 2 + ldrh w17, [x16, #:lo12:struct_obj_1 + 2] + madd w29, w17, w2, wzr + ubfiz w6, w29, 0, 16 + sub w12, wzr, w6 + madd w2, w12, w9, wzr + cbnz w2, .L239 + cmp w7, #0 + cset x12, ne + b .L240 +.L239: + orr w12, wzr, #1 +.L240: + adrp x16, var_36 + strh w12, [x16, #:lo12:var_36] + b .L241 +.L232: + cbz w17, .L242 + adrp x16, var_17 + ldrsh w7, [x16, #:lo12:var_17] + sub w29, w4, #12288 + sub w29, w29, #1187 + lsl w4, w7, w29 + cmp w4, #0 + cset x13, ne + b .L243 +.L242: + movz w13, #0, lsl #0 +.L243: + movn w16, #76, lsl #0 + eor w7, w17, w16 + adrp x16, var_30 + ldrh w5, [x16, #:lo12:var_30] + orr w29, wzr, w5, asr #7 + movz w16, #65483, lsl #0 + movk w16, #8191, lsl #16 + orr w2, w29, w16 + and w12, w7, w2 + sub w11, wzr, w3 + sub w5, wzr, w11 + adrp x16, var_1 + ldrh w11, [x16, #:lo12:var_1] + sub w3, wzr, w11 + madd w6, w5, w3, wzr + cmp w13, #4 + cset x5, ne + cmp w6, w5 + cset x3, gt + adrp x16, struct_obj_4 + 22 + ldrh w9, [x16, #:lo12:struct_obj_4 + 22] + adrp x16, var_20 + ldrh w11, [x16, #:lo12:var_20] + bic w4, w11, w17 + adrp x16, struct_obj_4 + 16 + ldrsb w2, [x16, #:lo12:struct_obj_4 + 16] + adrp x16, struct_obj_8 + 30 + ldrsb w17, [x16, #:lo12:struct_obj_8 + 30] + and w13, w2, w17 + eon w17, w4, w13 + adrp x16, var_514 + strh w17, [x16, #:lo12:var_514] +.L241: + adrp x16, struct_obj_3 + 4 + ldrh w4, [x16, #:lo12:struct_obj_3 + 4] + cbz w4, .L244 + adrp x16, var_17 + ldrsh w17, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w12, [x16, #:lo12:var_9] + sub w12, w12, #12288 + sub w12, w12, #1187 + lsl w13, w17, w12 + cmp w13, #0 + cset x7, ne + b .L245 +.L244: + movz w7, #0, lsl #0 +.L245: + movn w16, #76, lsl #0 + eor w8, w4, w16 + adrp x16, var_30 + ldrh w17, [x16, #:lo12:var_30] + orr w9, wzr, w17, asr #7 + movz w16, #65483, lsl #0 + movk w16, #8191, lsl #16 + orr w11, w9, w16 + and w11, w8, w11 + adrp x16, struct_obj_2 + ldrsh w17, [x16, #:lo12:struct_obj_2] + sub w6, wzr, w17 + sub w2, wzr, w6 + adrp x16, var_1 + ldrh w6, [x16, #:lo12:var_1] + sub w6, wzr, w6 + madd w19, w2, w6, wzr + cmp w7, #4 + cset x12, ne + cmp w19, w12 + cset x2, gt + cbz w4, .L246 + adrp x16, var_17 + ldrsh w5, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w12, [x16, #:lo12:var_9] + sub w17, w12, #12288 + sub w17, w17, #1187 + lsl w5, w5, w17 + cmp w5, #0 + cset x2, ne + b .L247 +.L246: + movz w2, #0, lsl #0 +.L247: + orr w3, wzr, #1 + movz w29, #0, lsl #0 + sub w6, wzr, w4 + movz w16, #4355, lsl #0 + cmp w6, w16 + cset x12, gt + sub w6, w12, #1 + cmp w2, #4 + cset x17, ne + cmp w19, w17 + cset x5, gt + cmp w11, w5 + cset x12, ge + movz w16, #7584, lsl #0 + cmp w12, w16 + cset x2, le + cmp w6, w2 + csel x17, x3, x29, le + add w12, w4, #45056 + add w12, w12, #778 + cmp w12, #0 + cset x6, ne + sdiv w2, w17, w6 + msub w3, w2, w6, w17 + sbfiz w13, w3, 0, 8 + cbz w4, .L248 + adrp x16, var_17 + ldrsh w2, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w8, [x16, #:lo12:var_9] + sub w9, w8, #12288 + sub w9, w9, #1187 + lsl w5, w2, w9 + cmp w5, #0 + cset x7, ne + b .L249 +.L248: + movz w7, #0, lsl #0 +.L249: + cmp w7, #4 + cset x9, ne + cmp w19, w9 + cset x8, gt + cmp w11, w8 + cset x2, ge + orn w3, wzr, w2 + cmp w3, #0 + cset x5, eq + adrp x16, var_64 + strb w5, [x16, #:lo12:var_64] + orr w12, wzr, #1 + orr w29, wzr, #1 + adrp x16, struct_obj_4 + 12 + ldrsb w11, [x16, #:lo12:struct_obj_4 + 12] + cmp w11, #0 + csel x17, x12, x29, ne + orr w7, wzr, #1 + orr w6, wzr, #1 + adrp x16, var_43 + ldrh w3, [x16, #:lo12:var_43] + cmp w3, #0 + csel x7, x7, x6, ne + sdiv w8, w17, w7 + msub w17, w8, w7, w17 + adrp x16, var_52 + ldrsh w2, [x16, #:lo12:var_52] + orr w12, w17, w2 + orn w5, wzr, w12 + adrp x16, var_61 + ldrsb w8, [x16, #:lo12:var_61] + adrp x16, var_5 + ldrh w11, [x16, #:lo12:var_5] + orr w2, w8, w11 + adrp x16, struct_obj_8 + 22 + ldrh w3, [x16, #:lo12:struct_obj_8 + 22] + orn w17, w2, w3 + adrp x16, struct_obj_6 + 6 + ldrsh w12, [x16, #:lo12:struct_obj_6 + 6] + adrp x16, struct_obj_1 + 4 + ldrh w2, [x16, #:lo12:struct_obj_1 + 4] + adrp x16, struct_obj_6 + 2 + ldrh w29, [x16, #:lo12:struct_obj_6 + 2] + and w11, w2, w29 + eor w2, w12, w11 + orr w2, w17, w2 + sbfiz w3, w2, 0, 8 + cmp w5, w3 + b.gt .L250 + adrp x16, struct_obj_3 + 4 + ldrh w8, [x16, #:lo12:struct_obj_3 + 4] + cbnz w8, .L251 + adrp x16, var_17 + ldrsh w17, [x16, #:lo12:var_17] + sbfiz w12, w17, 0, 8 + cbnz w12, .L251 + adrp x16, var_38 + ldrsb w4, [x16, #:lo12:var_38] + cbz w4, .L252 + adrp x16, var_36 + ldrsh w2, [x16, #:lo12:var_36] + cmp w2, #0 + cset x17, ne + cbnz w17, .L251 +.L252: + adrp x16, var_3 + ldrsb w2, [x16, #:lo12:var_3] +.L251: + movn w16, #76, lsl #0 + eor w17, w8, w16 + adrp x16, var_30 + ldrh w2, [x16, #:lo12:var_30] + orr w4, wzr, w2, asr #7 + movz w16, #65483, lsl #0 + movk w16, #8191, lsl #16 + orr w12, w4, w16 + and w12, w17, w12 + adrp x16, struct_obj_2 + ldrsh w17, [x16, #:lo12:struct_obj_2] + sub w11, wzr, w17 + sub w3, wzr, w11 + adrp x16, var_1 + ldrh w5, [x16, #:lo12:var_1] + cbz w8, .L253 + adrp x16, var_17 + ldrsh w29, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w17, [x16, #:lo12:var_9] + sub w2, w17, #12288 + sub w2, w2, #1187 + lsl w17, w29, w2 + cmp w17, #0 + cset x11, ne + b .L254 +.L253: + movz w11, #0, lsl #0 +.L254: + sub w6, wzr, w5 + madd w17, w3, w6, wzr + cmp w11, #4 + cset x29, ne + cmp w17, w29 + cset x7, gt +.L250: + adrp x16, struct_obj_3 + 4 + ldrh w29, [x16, #:lo12:struct_obj_3 + 4] + cbz w29, .L255 + adrp x16, var_17 + ldrsh w5, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w9, [x16, #:lo12:var_9] + sub w17, w9, #12288 + sub w17, w17, #1187 + lsl w3, w5, w17 + cmp w3, #0 + cset x3, ne + b .L256 +.L255: + movz w3, #0, lsl #0 +.L256: + movn w16, #76, lsl #0 + eor w6, w29, w16 + adrp x16, var_30 + ldrh w17, [x16, #:lo12:var_30] + orr w2, wzr, w17, asr #7 + movz w16, #65483, lsl #0 + movk w16, #8191, lsl #16 + orr w12, w2, w16 + and w4, w6, w12 + adrp x16, struct_obj_2 + ldrsh w17, [x16, #:lo12:struct_obj_2] + sub w2, wzr, w17 + sub w7, wzr, w2 + adrp x16, var_1 + ldrh w17, [x16, #:lo12:var_1] + sub w17, wzr, w17 + madd w5, w7, w17, wzr + cmp w3, #4 + cset x3, ne + cmp w5, w3 + cset x7, gt + cbz w29, .L257 + adrp x16, var_17 + ldrsh w7, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w17, [x16, #:lo12:var_9] + sub w8, w17, #12288 + sub w8, w8, #1187 + lsl w17, w7, w8 + cmp w17, #0 + cset x11, ne + b .L258 +.L257: + movz w11, #0, lsl #0 +.L258: + adrp x16, var_59 + ldrh w17, [x16, #:lo12:var_59] + madd w2, w0, w17, wzr + sbfiz w17, w2, 0, 16 + adrp x16, var_63 + ldrsh w2, [x16, #:lo12:var_63] + madd w13, w2, w13, wzr + madd w9, w17, w13, wzr + sub w8, wzr, w9 + movz w3, #11697, lsl #0 + sub w17, wzr, w29 + movz w16, #4355, lsl #0 + cmp w17, w16 + cset x7, gt + sub w9, w7, #1 + cmp w11, #4 + cset x2, ne + cmp w5, w2 + cset x17, gt + cmp w4, w17 + cset x7, ge + movz w16, #7584, lsl #0 + cmp w7, w16 + cset x7, le + cmp w9, w7 + cset x13, le + madd w17, w13, w3, wzr + add w8, w8, w17 + add w8, w8, #1110016 + add w8, w8, #1199 + cbnz w8, .L259 + cbz w29, .L260 + adrp x16, var_17 + ldrsh w17, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w2, [x16, #:lo12:var_9] + sub w7, w2, #12288 + sub w7, w7, #1187 + lsl w11, w17, w7 + cmp w11, #0 + cset x2, ne + b .L261 +.L260: + movz w2, #0, lsl #0 +.L261: + cmp w2, #4 + cset x8, ne + cmp w5, w8 + cset x13, gt + cbz w29, .L262 + adrp x16, var_17 + ldrsh w7, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w2, [x16, #:lo12:var_9] + sub w8, w2, #12288 + sub w8, w8, #1187 + lsl w17, w7, w8 + cmp w17, #0 + cset x8, ne + b .L263 +.L262: + movz w8, #0, lsl #0 +.L263: + movz w13, #65414, lsl #0 + movk w13, #32767, lsl #16 + and w11, w6, w12 + cmp w8, #4 + cset x12, ne + cmp w5, w12 + cset x7, gt + cmp w11, w7 + cset x2, ge + movz w16, #7584, lsl #0 + cmp w2, w16 + cset x17, le + cmp w9, w17 + cset x2, le + asr w6, w13, w2 + movz w11, #64835, lsl #0 + adrp x16, var_25 + ldrsb w12, [x16, #:lo12:var_25] + orn w5, wzr, w12 + add w6, w5, #149 + asr w29, w11, w6 + adrp x16, struct_obj_7 + 4 + ldrsb w11, [x16, #:lo12:struct_obj_7 + 4] + adrp x16, struct_obj_4 + 4 + ldrsh w2, [x16, #:lo12:struct_obj_4 + 4] + orr w9, w11, w2 + add w2, w9, #128 + asr w9, w29, w2 + sub w4, wzr, w9 + adrp x16, struct_obj_4 + 18 + ldrsh w3, [x16, #:lo12:struct_obj_4 + 18] + orn w9, wzr, w3 + movz w16, #17255, lsl #0 + orr w11, w9, w16 + adrp x16, struct_obj_8 + 4 + ldrsb w7, [x16, #:lo12:struct_obj_8 + 4] + and w17, w11, w7 + adrp x16, var_2 + ldrh w29, [x16, #:lo12:var_2] + sbfiz w11, w29, 0, 8 + sub w13, wzr, w11 + orn w11, wzr, w13 + cmp w17, w11 + cset x29, ne + sdiv w17, w4, w29 + adrp x16, var_543 + strb w17, [x16, #:lo12:var_543] + adrp x16, var_42 + ldrsb w17, [x16, #:lo12:var_42] + madd w13, w17, w3, wzr + movz w8, #63174, lsl #0 + movk w8, #19, lsl #16 + adrp x16, var_53 + ldrsh w3, [x16, #:lo12:var_53] + sub w9, w8, w3 + sub w11, w9, #6 + sbfiz w2, w11, 0, 16 + add w8, w13, w2 + sub w9, w8, #117 + movz w5, #19559, lsl #0 + adrp x16, var_13 + ldrsh w13, [x16, #:lo12:var_13] + madd w2, w13, w5, wzr + adrp x16, var_46 + ldrh w5, [x16, #:lo12:var_46] + madd w17, w14, w5, wzr + madd w2, w2, w17, wzr + sub w5, wzr, w2 + movz w14, #65517, lsl #0 + movz w6, #20823, lsl #0 + adrp x16, var_4 + ldrh w3, [x16, #:lo12:var_4] + madd w13, w3, w6, wzr + sdiv w6, w14, w13 + movz w29, #45116, lsl #0 + movk w29, #14440, lsl #16 + adrp x16, var_24 + ldrsh w4, [x16, #:lo12:var_24] + sbfiz w11, w4, 0, 8 + sdiv w2, w29, w11 + madd w6, w6, w2, wzr + madd w2, w5, w6, wzr + cmp w9, w2 + cset x7, gt + adrp x16, var_544 + strh w7, [x16, #:lo12:var_544] + adrp x16, var_547 + strb w12, [x16, #:lo12:var_547] + adrp x16, struct_obj_3 + 4 + ldrh w3, [x16, #:lo12:struct_obj_3 + 4] + cbz w3, .L264 + adrp x16, var_17 + ldrsh w6, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w13, [x16, #:lo12:var_9] + sub w4, w13, #12288 + sub w4, w4, #1187 + lsl w6, w6, w4 + cmp w6, #0 + cset x14, ne + b .L265 +.L264: + movz w14, #0, lsl #0 +.L265: + movn w16, #76, lsl #0 + eor w17, w3, w16 + adrp x16, var_30 + ldrh w6, [x16, #:lo12:var_30] + orr w12, wzr, w6, asr #7 + movz w16, #65483, lsl #0 + movk w16, #8191, lsl #16 + orr w4, w12, w16 + and w13, w17, w4 + adrp x16, struct_obj_2 + ldrsh w2, [x16, #:lo12:struct_obj_2] + sub w11, wzr, w2 + sub w17, wzr, w11 + adrp x16, var_1 + ldrh w29, [x16, #:lo12:var_1] + sub w4, wzr, w29 + madd w17, w17, w4, wzr + cmp w14, #4 + cset x12, ne + cmp w17, w12 + cset x11, gt + cbz w3, .L266 + adrp x16, var_17 + ldrsh w9, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w12, [x16, #:lo12:var_9] + sub w2, w12, #12288 + sub w2, w2, #1187 + lsl w2, w9, w2 + cmp w2, #0 + cset x14, ne + b .L267 +.L266: + movz w14, #0, lsl #0 +.L267: + adrp x16, var_41 + ldrh w6, [x16, #:lo12:var_41] + adrp x16, var_16 + ldrh w2, [x16, #:lo12:var_16] + adrp x16, struct_obj_7 + ldrsb w29, [x16, #:lo12:struct_obj_7] + add w4, w29, #102 + asr w4, w2, w4 + adrp x16, struct_obj_4 + 24 + ldrh w8, [x16, #:lo12:struct_obj_4 + 24] + orn w9, w4, w8 + orr w16, wzr, #2147483647 + add w12, w9, w16 + adrp x16, struct_obj_8 + 8 + ldrsb w9, [x16, #:lo12:struct_obj_8 + 8] + sub w11, wzr, w3 + movz w16, #4355, lsl #0 + cmp w11, w16 + cset x29, gt + sub w29, w29, #1 + cmp w14, #4 + cset x11, ne + cmp w17, w11 + cset x17, gt + cmp w13, w17 + cset x14, ge + movz w16, #7584, lsl #0 + cmp w14, w16 + cset x2, le + cmp w29, w2 + cset x8, le + eor w3, w9, w8 + add w9, w3, #75 + lsl w8, w12, w9 + movz w16, #9477, lsl #0 + movk w16, #32767, lsl #16 + sub w5, w8, w16 + lsl w29, w6, w5 + orn w11, wzr, w29 + adrp x16, var_59 + strh w11, [x16, #:lo12:var_59] + b .L268 +.L259: + movz w17, #23716, lsl #0 + adrp x16, var_38 + ldrsb w3, [x16, #:lo12:var_38] + sub w8, w3, #38 + lsl w12, w17, w8 + adrp x16, struct_obj_9 + 8 + ldrsh w4, [x16, #:lo12:struct_obj_9 + 8] + asr w2, w4, w15 + orr w2, wzr, w2, lsl #16 + adrp x16, struct_obj_2 + 2 + ldrh w12, [x16, #:lo12:struct_obj_2 + 2] + adrp x16, var_27 + ldrsh w9, [x16, #:lo12:var_27] + cbnz w9, .L269 + adrp x16, var_24 + ldrsh w7, [x16, #:lo12:var_24] + cmp w7, #0 + cset x4, ne + b .L270 +.L269: + orr w4, wzr, #1 +.L270: + cbz w4, .L271 + adrp x16, var_17 + ldrsh w4, [x16, #:lo12:var_17] +.L271: + adrp x16, var_10 + ldrh w13, [x16, #:lo12:var_10] + adrp x16, var_62 + strh w13, [x16, #:lo12:var_62] + adrp x16, var_26 + ldrh w17, [x16, #:lo12:var_26] +.L268: + adrp x16, var_54 + ldrsh w14, [x16, #:lo12:var_54] + cbz w14, .L272 + adrp x16, var_11 + ldrsh w29, [x16, #:lo12:var_11] + cmp w29, #0 + cset x13, ne + cbz w13, .L272 + adrp x16, var_18 + ldrsb w8, [x16, #:lo12:var_18] + cbnz w8, .L273 + adrp x16, var_7 + ldrsb w2, [x16, #:lo12:var_7] + cmp w2, #0 + cset x4, ne + cbz w4, .L272 +.L273: + adrp x16, var_16 + ldrh w17, [x16, #:lo12:var_16] +.L272: + adrp x16, struct_obj_3 + 4 + ldrh w11, [x16, #:lo12:struct_obj_3 + 4] + cbz w11, .L274 + adrp x16, var_17 + ldrsh w17, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w12, [x16, #:lo12:var_9] + sub w12, w12, #12288 + sub w12, w12, #1187 + lsl w29, w17, w12 + cmp w29, #0 + cset x8, ne + b .L275 +.L274: + movz w8, #0, lsl #0 +.L275: + movn w16, #76, lsl #0 + eor w2, w11, w16 + adrp x16, var_30 + ldrh w12, [x16, #:lo12:var_30] + orr w12, wzr, w12, asr #7 + movz w16, #65483, lsl #0 + movk w16, #8191, lsl #16 + orr w9, w12, w16 + and w13, w2, w9 + adrp x16, struct_obj_2 + ldrsh w6, [x16, #:lo12:struct_obj_2] + sub w29, wzr, w6 + sub w17, wzr, w29 + adrp x16, var_1 + ldrh w12, [x16, #:lo12:var_1] + sub w29, wzr, w12 + madd w3, w17, w29, wzr + cmp w8, #4 + cset x2, ne + cmp w3, w2 + cset x9, gt + cbz w11, .L276 + adrp x16, var_17 + ldrsh w2, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w14, [x16, #:lo12:var_9] + sub w17, w14, #12288 + sub w17, w17, #1187 + lsl w2, w2, w17 + cmp w2, #0 + cset x9, ne + b .L277 +.L276: + movz w9, #0, lsl #0 +.L277: + cmp w9, #4 + cset x7, ne + cmp w3, w7 + cset x2, gt + cmp w13, w2 + cset x3, ge + orn w14, wzr, w3 + adrp x16, var_549 + strb w14, [x16, #:lo12:var_549] +.L231: + adrp x16, struct_obj_4 + 22 + ldrh w2, [x16, #:lo12:struct_obj_4 + 22] + cbz w2, .L278 + adrp x16, var_17 + ldrsh w9, [x16, #:lo12:var_17] + adrp x16, var_30 + ldrh w8, [x16, #:lo12:var_30] + adrp x16, struct_obj_6 + 6 + ldrsh w13, [x16, #:lo12:struct_obj_6 + 6] + adrp x16, struct_obj_3 + 4 + ldrh w5, [x16, #:lo12:struct_obj_3 + 4] + adrp x16, var_40 + ldrsb w11, [x16, #:lo12:var_40] + cbnz w11, .L279 + cbnz w10, .L280 + orr w2, wzr, #1 + b .L281 +.L280: + orr w2, wzr, #1 + b .L281 +.L279: + movz w2, #0, lsl #0 +.L281: + adrp x16, var_47 + ldrsb w6, [x16, #:lo12:var_47] + cbz w6, .L282 + cmp w5, #0 + cset x4, ne + cbz w4, .L282 + orr w12, wzr, #1 + b .L283 +.L282: + orr w7, wzr, #1 + orr w12, wzr, #1 + adrp x16, var_48 + ldrh w11, [x16, #:lo12:var_48] + cmp w11, #0 + csel x17, x7, x12, ne + cbz w17, .L284 + cmp w10, #0 + cset x12, eq + b .L283 +.L284: + movz w12, #0, lsl #0 +.L283: + adrp x16, var_18 + ldrsb w11, [x16, #:lo12:var_18] + orr w3, wzr, w11, lsr #31 + sxtw x29, w11 + movz x17, #30841, lsl #0 + movk x17, #30840, lsl #16 + madd x29, x29, x17, xzr + orr x10, xzr, x29, asr #32 + add w14, w3, w10, asr #3 + add w14, w14, w14, lsl #4 + sub w6, w11, w14 + sub w14, w2, w12 + cmp w6, w14 + b.le .L285 + cbz w5, .L286 + adrp x16, var_9 + ldrh w29, [x16, #:lo12:var_9] + sub w3, w29, #12288 + sub w3, w3, #1187 + lsl w2, w9, w3 + cmp w2, #0 + cset x2, ne + b .L287 +.L286: + movz w2, #0, lsl #0 +.L287: + cbz w5, .L288 + adrp x16, var_9 + ldrh w3, [x16, #:lo12:var_9] + sub w3, w3, #12288 + sub w3, w3, #1187 + lsl w3, w9, w3 + cmp w3, #0 + cset x10, ne + b .L289 +.L288: + movz w10, #0, lsl #0 +.L289: + adrp x16, var_24 + ldrsh w9, [x16, #:lo12:var_24] + adrp x16, var_41 + ldrh w14, [x16, #:lo12:var_41] + madd w4, w9, w14, wzr + movn w16, #76, lsl #0 + eor w7, w5, w16 + orr w17, wzr, w8, asr #7 + movz w16, #65483, lsl #0 + movk w16, #8191, lsl #16 + orr w13, w17, w16 + and w29, w7, w13 + adrp x16, struct_obj_2 + ldrsh w14, [x16, #:lo12:struct_obj_2] + sub w9, wzr, w14 + sub w17, wzr, w9 + adrp x16, var_1 + ldrh w6, [x16, #:lo12:var_1] + sub w6, wzr, w6 + madd w7, w17, w6, wzr + cmp w2, #4 + cset x3, ne + cmp w7, w3 + cset x6, gt + cmp w29, w6 + cset x13, ge + orn w12, wzr, w13 + madd w6, w4, w12, wzr + cmp w10, #4 + cset x13, ne + cmp w7, w13 + cset x2, gt + cmp w29, w2 + cset x7, ge + adrp x16, var_21 + ldrsb w2, [x16, #:lo12:var_21] + cmp w2, #0 + cset x8, eq + orn w4, wzr, w8 + orr w3, w4, #-2 + and w7, w7, w3 + and w8, w6, w7 + adrp x16, var_48 + strh w8, [x16, #:lo12:var_48] + cbz w5, .L290 + adrp x16, var_17 + ldrsh w4, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w2, [x16, #:lo12:var_9] + sub w17, w2, #12288 + sub w17, w17, #1187 + lsl w6, w4, w17 + cmp w6, #0 + cset x13, ne + b .L291 +.L290: + movz w13, #0, lsl #0 +.L291: + adrp x16, struct_obj_3 + 4 + ldrh w17, [x16, #:lo12:struct_obj_3 + 4] + movn w16, #76, lsl #0 + eor w3, w17, w16 + adrp x16, var_30 + ldrh w2, [x16, #:lo12:var_30] + orr w4, wzr, w2, asr #7 + movz w16, #65483, lsl #0 + movk w16, #8191, lsl #16 + orr w7, w4, w16 + and w4, w3, w7 + adrp x16, struct_obj_2 + ldrsh w29, [x16, #:lo12:struct_obj_2] + sub w2, wzr, w29 + sub w3, wzr, w2 + adrp x16, var_1 + ldrh w2, [x16, #:lo12:var_1] + sub w10, wzr, w2 + madd w14, w3, w10, wzr + cmp w13, #4 + cset x13, ne + cmp w14, w13 + cset x29, gt + adrp x16, var_26 + ldrh w7, [x16, #:lo12:var_26] + cbnz w7, .L292 +.L292: + cbz w17, .L293 + adrp x16, var_17 + ldrsh w9, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w12, [x16, #:lo12:var_9] + sub w29, w12, #12288 + sub w29, w29, #1187 + lsl w10, w9, w29 + cmp w10, #0 + cset x3, ne + b .L294 +.L293: + movz w3, #0, lsl #0 +.L294: + cmp w3, #4 + cset x9, ne + cmp w14, w9 + cset x7, gt + adrp x16, struct_obj_4 + 14 + ldrsh w17, [x16, #:lo12:struct_obj_4 + 14] + cbz w17, .L295 + adrp x16, struct_obj_6 + 4 + ldrh w2, [x16, #:lo12:struct_obj_6 + 4] + cmp w2, #0 + cset x17, ne + cbz w17, .L295 + orr w2, wzr, #1 + b .L296 +.L295: + adrp x16, var_60 + ldrsh w2, [x16, #:lo12:var_60] + cbnz w2, .L297 + adrp x16, struct_obj_4 + 16 + ldrsb w13, [x16, #:lo12:struct_obj_4 + 16] + cmp w13, #0 + cset x2, ne + b .L296 +.L297: + orr w2, wzr, #1 +.L296: + orr w3, wzr, #1 + orr w7, wzr, #1 + cmp w2, #0 + csel x3, x3, x7, ne + cbz w3, .L285 + adrp x16, var_65 + ldrsh w14, [x16, #:lo12:var_65] + cbz w14, .L298 + adrp x16, struct_obj_9 + 20 + ldrsh w5, [x16, #:lo12:struct_obj_9 + 20] + cmp w5, #0 + cset x9, ne + cbz w9, .L298 + adrp x16, var_3 + ldrsb w17, [x16, #:lo12:var_3] + cbz w17, .L299 + adrp x16, var_51 + ldrsh w7, [x16, #:lo12:var_51] + cmp w7, #0 + cset x14, ne + b .L300 +.L299: + movz w14, #0, lsl #0 + b .L300 +.L298: + movz w14, #0, lsl #0 +.L300: + eor w2, w14, #1 + cbz w2, .L285 + adrp x16, var_50 + ldrh w9, [x16, #:lo12:var_50] + cbz w9, .L301 + adrp x16, struct_obj_7 + ldrsb w14, [x16, #:lo12:struct_obj_7] + cmp w14, #0 + cset x5, ne + b .L302 +.L301: + movz w5, #0, lsl #0 +.L302: + cbnz w5, .L285 + orr w2, wzr, #1 + movz w11, #0, lsl #0 + adrp x16, var_45 + ldrsb w5, [x16, #:lo12:var_45] + cmp w5, #0 + csel x2, x2, x11, ne + cbnz w2, .L285 + adrp x16, var_19 + ldrsb w4, [x16, #:lo12:var_19] +.L285: + adrp x16, struct_obj_3 + 4 + ldrh w11, [x16, #:lo12:struct_obj_3 + 4] + cbz w11, .L303 + adrp x16, var_17 + ldrsh w29, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w12, [x16, #:lo12:var_9] + sub w5, w12, #12288 + sub w5, w5, #1187 + lsl w12, w29, w5 + cmp w12, #0 + cset x5, ne + b .L304 +.L303: + movz w5, #0, lsl #0 +.L304: + adrp x16, var_24 + ldrsh w12, [x16, #:lo12:var_24] + adrp x16, struct_obj_9 + 2 + ldrsb w29, [x16, #:lo12:struct_obj_9 + 2] + add w13, w12, w29 + adrp x16, struct_obj_2 + ldrsh w4, [x16, #:lo12:struct_obj_2] + sub w2, w4, #61440 + sub w2, w2, #4094 + add w3, w13, w2 + movz w14, #125, lsl #0 + adrp x16, var_40 + ldrsb w12, [x16, #:lo12:var_40] + sub w17, w14, w12 + sub w10, wzr, w17 + sub w13, w3, w10 + adrp x16, struct_obj_8 + ldrh w12, [x16, #:lo12:struct_obj_8] + adrp x16, var_6 + ldrh w8, [x16, #:lo12:var_6] + sub w10, w12, w8 + sub w9, wzr, w10 + movn w16, #76, lsl #0 + eor w17, w11, w16 + adrp x16, var_30 + ldrh w14, [x16, #:lo12:var_30] + orr w14, wzr, w14, asr #7 + movz w16, #65483, lsl #0 + movk w16, #8191, lsl #16 + orr w2, w14, w16 + and w17, w17, w2 + sub w11, wzr, w4 + sub w3, wzr, w11 + adrp x16, var_1 + ldrh w29, [x16, #:lo12:var_1] + sub w4, wzr, w29 + madd w10, w3, w4, wzr + cmp w5, #4 + cset x11, ne + cmp w10, w11 + cset x6, gt + cmp w17, w6 + cset x11, ge + madd w2, w9, w11, wzr + madd w17, w13, w2, wzr + orn w11, wzr, w17 + adrp x16, var_52 + strh w11, [x16, #:lo12:var_52] + adrp x16, var_57 + ldrsb w8, [x16, #:lo12:var_57] + cbnz w8, .L305 + adrp x16, var_39 + ldrh w11, [x16, #:lo12:var_39] + cmp w11, #0 + cset x14, eq + b .L306 +.L305: + movz w14, #0, lsl #0 +.L306: + adrp x16, var_29 + ldrh w2, [x16, #:lo12:var_29] + sub w7, wzr, w14 + asr w14, w2, w7 + orr w11, wzr, #1 + orr w0, w15, w0 + movn w16, #8063, lsl #0 + cmp w0, w16 + cset x5, lt + orn w12, wzr, w5 + sub w17, w11, w12 + sdiv w6, w14, w17 + msub w4, w6, w17, w14 + cbz w4, .L307 + adrp x16, struct_obj_3 + 4 + ldrh w9, [x16, #:lo12:struct_obj_3 + 4] + cbz w9, .L308 + adrp x16, var_17 + ldrsh w7, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w3, [x16, #:lo12:var_9] + sub w4, w3, #12288 + sub w4, w4, #1187 + lsl w11, w7, w4 + cmp w11, #0 + cset x10, ne + b .L309 +.L308: + movz w10, #0, lsl #0 +.L309: + movn w16, #76, lsl #0 + eor w15, w9, w16 + adrp x16, var_30 + ldrh w7, [x16, #:lo12:var_30] + orr w2, wzr, w7, asr #7 + movz w16, #65483, lsl #0 + movk w16, #8191, lsl #16 + orr w5, w2, w16 + and w3, w15, w5 + adrp x16, struct_obj_2 + ldrsh w8, [x16, #:lo12:struct_obj_2] + sub w5, wzr, w8 + sub w17, wzr, w5 + adrp x16, var_1 + ldrh w15, [x16, #:lo12:var_1] + sub w5, wzr, w15 + madd w7, w17, w5, wzr + cmp w10, #4 + cset x10, ne + cmp w7, w10 + cset x7, gt + cmp w3, w7 + cset x12, ge + adrp x16, struct_obj_4 + 22 + ldrh w8, [x16, #:lo12:struct_obj_4 + 22] + sbfiz w2, w8, 0, 8 + and w2, w12, w2 + adrp x16, var_8 + ldrh w9, [x16, #:lo12:var_8] + movz w0, #16848, lsl #0 + movk w0, #61777, lsl #16 + sdiv w12, w9, w0 + sbfiz w0, w12, 0, 16 + asr w11, w2, w0 + adrp x16, struct_obj_5 + ldrsb w13, [x16, #:lo12:struct_obj_5] + movn w7, #99, lsl #0 + adrp x16, var_19 + ldrsb w2, [x16, #:lo12:var_19] + madd w4, w2, w7, wzr + sub w7, wzr, w4 + sbfiz w17, w7, 0, 16 + cmp w13, w17 + cset x3, le + asr w9, w11, w3 + ubfiz w8, w9, 0, 16 + adrp x16, var_31 + ldrsh w7, [x16, #:lo12:var_31] + sub w2, w7, w8 + orn w4, wzr, w2 + movn w14, #19434, lsl #0 + adrp x16, struct_obj_9 + 2 + ldrsb w2, [x16, #:lo12:struct_obj_9 + 2] + sdiv w3, w14, w2 + msub w0, w3, w2, w14 + sbfiz w11, w0, 0, 8 + add w29, w11, #55 + asr w3, w4, w29 + orn w0, wzr, w3 + cmp w0, #0 + cset x9, eq + adrp x16, var_558 + strh w9, [x16, #:lo12:var_558] + adrp x16, struct_obj_6 + 4 + ldrh w2, [x16, #:lo12:struct_obj_6 + 4] + cbz w2, .L310 + adrp x16, struct_obj_4 + 2 + ldrsb w10, [x16, #:lo12:struct_obj_4 + 2] + cmp w10, #0 + cset x11, ne + b .L311 +.L310: + movz w11, #0, lsl #0 +.L311: + orn w6, wzr, w11 + sdiv w9, w1, w6 + msub w10, w9, w6, w1 + cbz w10, .L312 + orr w29, wzr, #1 + movz w10, #0, lsl #0 + movz w5, #0, lsl #0 + cmp w29, #0 + csel x11, x10, x5, ne + eor w15, w11, #1 + b .L313 +.L312: + movz w15, #0, lsl #0 +.L313: + adrp x16, struct_obj_1 + 6 + ldrsh w9, [x16, #:lo12:struct_obj_1 + 6] + cmp w15, w9 + cset x29, eq + adrp x16, var_64 + strb w29, [x16, #:lo12:var_64] + adrp x16, struct_obj_3 + 4 + ldrh w17, [x16, #:lo12:struct_obj_3 + 4] + cbz w17, .L314 + adrp x16, var_17 + ldrsh w9, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w14, [x16, #:lo12:var_9] + sub w0, w14, #12288 + sub w0, w0, #1187 + lsl w15, w9, w0 + cmp w15, #0 + cset x29, ne + b .L315 +.L314: + movz w29, #0, lsl #0 +.L315: + movn w16, #76, lsl #0 + eor w3, w17, w16 + adrp x16, var_30 + ldrh w8, [x16, #:lo12:var_30] + orr w5, wzr, w8, asr #7 + movz w16, #65483, lsl #0 + movk w16, #8191, lsl #16 + orr w8, w5, w16 + and w12, w3, w8 + adrp x16, struct_obj_2 + ldrsh w11, [x16, #:lo12:struct_obj_2] + sub w10, wzr, w11 + sub w13, wzr, w10 + adrp x16, var_1 + ldrh w15, [x16, #:lo12:var_1] + sub w14, wzr, w15 + madd w7, w13, w14, wzr + cmp w29, #4 + cset x13, ne + cmp w7, w13 + cset x5, gt + cbz w17, .L316 + adrp x16, var_17 + ldrsh w5, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w4, [x16, #:lo12:var_9] + sub w10, w4, #12288 + sub w10, w10, #1187 + lsl w8, w5, w10 + cmp w8, #0 + cset x8, ne + b .L317 +.L316: + movz w8, #0, lsl #0 +.L317: + cmp w8, #4 + cset x2, ne + cmp w7, w2 + cset x8, gt + orn w13, wzr, w17 + adrp x16, struct_obj_5 + 2 + ldrsh w14, [x16, #:lo12:struct_obj_5 + 2] +.L307: + adrp x16, struct_obj_3 + 4 + ldrh w15, [x16, #:lo12:struct_obj_3 + 4] + adrp x16, var_1 + ldrh w11, [x16, #:lo12:var_1] + movn w16, #23820, lsl #0 + eor w0, w11, w16 + orn w8, wzr, w0 + cbnz w8, .L318 + cbz w15, .L319 + adrp x16, var_17 + ldrsh w7, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w6, [x16, #:lo12:var_9] + sub w12, w6, #12288 + sub w12, w12, #1187 + lsl w10, w7, w12 + cmp w10, #0 + cset x17, ne + b .L320 +.L319: + movz w17, #0, lsl #0 +.L320: + movn w16, #76, lsl #0 + eor w8, w15, w16 + adrp x16, var_30 + ldrh w29, [x16, #:lo12:var_30] + orr w9, wzr, w29, asr #7 + movz w16, #65483, lsl #0 + movk w16, #8191, lsl #16 + orr w5, w9, w16 + and w9, w8, w5 + adrp x16, struct_obj_2 + ldrsh w7, [x16, #:lo12:struct_obj_2] + sub w29, wzr, w7 + sub w7, wzr, w29 + sub w8, wzr, w11 + madd w12, w7, w8, wzr + cmp w17, #4 + cset x17, ne + cmp w12, w17 + cset x8, gt + movz w13, #55, lsl #0 + adrp x16, var_51 + strh w13, [x16, #:lo12:var_51] + cbz w15, .L321 + adrp x16, var_17 + ldrsh w4, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w15, [x16, #:lo12:var_9] + sub w9, w15, #12288 + sub w9, w9, #1187 + lsl w17, w4, w9 + cmp w17, #0 + cset x12, ne + b .L322 +.L321: + movz w12, #0, lsl #0 +.L322: + adrp x16, struct_obj_3 + 4 + ldrh w13, [x16, #:lo12:struct_obj_3 + 4] + movn w16, #76, lsl #0 + eor w2, w13, w16 + adrp x16, var_30 + ldrh w5, [x16, #:lo12:var_30] + orr w3, wzr, w5, asr #7 + movz w16, #65483, lsl #0 + movk w16, #8191, lsl #16 + orr w0, w3, w16 + and w17, w2, w0 + adrp x16, struct_obj_2 + ldrsh w9, [x16, #:lo12:struct_obj_2] + sub w15, wzr, w9 + sub w11, wzr, w15 + adrp x16, var_1 + ldrh w8, [x16, #:lo12:var_1] + sub w0, wzr, w8 + madd w3, w11, w0, wzr + cmp w12, #4 + cset x10, ne + cmp w3, w10 + cset x0, gt + cbz w13, .L323 + adrp x16, var_17 + ldrsh w14, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w0, [x16, #:lo12:var_9] + sub w8, w0, #12288 + sub w8, w8, #1187 + lsl w2, w14, w8 + cmp w2, #0 + cset x11, ne + b .L324 +.L323: + movz w11, #0, lsl #0 +.L324: + cmp w11, #4 + cset x29, ne + cmp w3, w29 + cset x5, gt + b .L278 +.L318: + cbz w15, .L325 + adrp x16, var_17 + ldrsh w9, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w8, [x16, #:lo12:var_9] + sub w10, w8, #12288 + sub w10, w10, #1187 + lsl w4, w9, w10 + cmp w4, #0 + cset x3, ne + b .L326 +.L325: + movz w3, #0, lsl #0 +.L326: + movn w16, #76, lsl #0 + eor w14, w15, w16 + adrp x16, var_30 + ldrh w2, [x16, #:lo12:var_30] + orr w10, wzr, w2, asr #7 + movz w16, #65483, lsl #0 + movk w16, #8191, lsl #16 + orr w17, w10, w16 + and w7, w14, w17 + adrp x16, struct_obj_2 + ldrsh w6, [x16, #:lo12:struct_obj_2] + sub w12, wzr, w6 + sub w12, wzr, w12 + sub w4, wzr, w11 + madd w2, w12, w4, wzr + cmp w3, #4 + cset x12, ne + cmp w2, w12 + cset x13, gt + cbz w15, .L327 + adrp x16, var_17 + ldrsh w10, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w6, [x16, #:lo12:var_9] + sub w17, w6, #12288 + sub w17, w17, #1187 + lsl w8, w10, w17 + cmp w8, #0 + cset x6, ne + b .L328 +.L327: + movz w6, #0, lsl #0 +.L328: + movn w3, #54, lsl #0 + adrp x16, var_41 + ldrh w4, [x16, #:lo12:var_41] + madd w0, w4, w3, wzr + sbfiz w0, w0, 0, 16 + sub w3, wzr, w15 + movz w16, #4355, lsl #0 + cmp w3, w16 + cset x10, gt + sub w4, w10, #1 + cmp w6, #4 + cset x5, ne + cmp w2, w5 + cset x2, gt + cmp w7, w2 + cset x10, ge + movz w16, #7584, lsl #0 + cmp w10, w16 + cset x5, le + cmp w4, w5 + cset x14, le + sub w4, wzr, w14 + cmp w4, #0 + cset x11, eq + madd w10, w0, w11, wzr + adrp x16, struct_obj_8 + 28 + ldrsh w12, [x16, #:lo12:struct_obj_8 + 28] + orn w4, wzr, w12 + adrp x16, struct_obj_5 + 2 + ldrsh w12, [x16, #:lo12:struct_obj_5 + 2] + orn w0, w4, w12 + orr w10, wzr, #1 + adrp x16, var_2 + ldrh w17, [x16, #:lo12:var_2] + adrp x16, var_34 + ldrsb w11, [x16, #:lo12:var_34] + sdiv w17, w17, w11 + orn w13, wzr, w17 + sub w11, w13, #233 + lsl w10, w10, w11 + movn w16, #49, lsl #0 + orr w10, w10, w16 + orr w17, w0, w10 + adrp x16, struct_obj_8 + 8 + ldrsb w2, [x16, #:lo12:struct_obj_8 + 8] + bic w2, w17, w2 + cbz w2, .L278 +.L278: + adrp x16, var_62 + ldrh w17, [x16, #:lo12:var_62] + adrp x16, var_8 + ldrh w9, [x16, #:lo12:var_8] + cmp w9, #0 + cset x12, le + and w9, w17, w12 + cbz w9, .L329 + adrp x16, struct_obj_1 + ldrsh w4, [x16, #:lo12:struct_obj_1] + adrp x16, struct_obj_3 + 4 + ldrh w8, [x16, #:lo12:struct_obj_3 + 4] + cbz w8, .L330 + adrp x16, var_17 + ldrsh w9, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w12, [x16, #:lo12:var_9] + sub w7, w12, #12288 + sub w7, w7, #1187 + lsl w6, w9, w7 + cmp w6, #0 + cset x10, ne + b .L331 +.L330: + movz w10, #0, lsl #0 +.L331: + adrp x16, var_27 + ldrsh w6, [x16, #:lo12:var_27] + cmp w6, #0 + cset x2, eq + adrp x16, var_10 + ldrh w6, [x16, #:lo12:var_10] + adrp x16, var_60 + ldrsh w29, [x16, #:lo12:var_60] + cmp w6, w29 + cset x5, le + sub w17, w2, w5 + cbz w17, .L332 + movn w17, #19779, lsl #0 + orr w7, wzr, #-128 + adrp x16, var_40 + ldrsb w9, [x16, #:lo12:var_40] + madd w14, w9, w7, wzr + madd w29, w14, w17, wzr + cmp w29, #0 + cset x2, ne + b .L333 +.L332: + movz w2, #0, lsl #0 +.L333: + movn w16, #76, lsl #0 + eor w9, w8, w16 + adrp x16, var_30 + ldrh w12, [x16, #:lo12:var_30] + orr w5, wzr, w12, asr #7 + movz w16, #65483, lsl #0 + movk w16, #8191, lsl #16 + orr w14, w5, w16 + and w0, w9, w14 + adrp x16, struct_obj_2 + ldrsh w3, [x16, #:lo12:struct_obj_2] + sub w11, wzr, w3 + sub w11, wzr, w11 + adrp x16, var_1 + ldrh w5, [x16, #:lo12:var_1] + sub w15, wzr, w5 + madd w11, w11, w15, wzr + cmp w10, #4 + cset x13, ne + cmp w11, w13 + cset x4, gt + cmp w0, w4 + cset x15, ge + adrp x16, struct_obj_9 + 8 + ldrsh w3, [x16, #:lo12:struct_obj_9 + 8] + add w12, w15, w3 + add w3, w12, #57344 + add w3, w3, #1750 + sbfiz w17, w3, 0, 8 + cmp w17, w2 + cset x15, gt + adrp x16, var_43 + ldrh w17, [x16, #:lo12:var_43] + adrp x16, struct_obj_5 + 6 + ldrsh w7, [x16, #:lo12:struct_obj_5 + 6] + add w12, w17, w7 + movz w16, #26468, lsl #0 + cmp w12, w16 + cset x10, lt + sub w2, wzr, w10 + cmp w2, #43 + cset x29, gt + and w15, w15, w29 + adrp x16, var_53 + ldrsh w12, [x16, #:lo12:var_53] + cbnz w12, .L334 + adrp x16, var_61 + ldrsb w13, [x16, #:lo12:var_61] + ubfiz w13, w13, 0, 16 + cmp w13, #0 + cset x13, ne + cbnz w13, .L334 + orr w2, wzr, #1 + cbnz w2, .L334 + cbnz w6, .L334 + adrp x16, var_44 + ldrh w10, [x16, #:lo12:var_44] + cmp w10, #0 + cset x4, ne +.L334: + adrp x16, struct_obj_4 + 10 + ldrh w7, [x16, #:lo12:struct_obj_4 + 10] + cbz w8, .L335 + adrp x16, var_17 + ldrsh w12, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w6, [x16, #:lo12:var_9] + sub w6, w6, #12288 + sub w6, w6, #1187 + lsl w13, w12, w6 + cmp w13, #0 + cset x10, ne + b .L336 +.L335: + movz w10, #0, lsl #0 +.L336: + cmp w10, #4 + cset x4, ne + cmp w11, w4 + cset x17, gt + cbz w8, .L337 + adrp x16, var_17 + ldrsh w12, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w3, [x16, #:lo12:var_9] + sub w0, w3, #12288 + sub w0, w0, #1187 + lsl w10, w12, w0 + cmp w10, #0 + cset x12, ne + b .L338 +.L337: + movz w12, #0, lsl #0 +.L338: + adrp x16, struct_obj_4 + 16 + ldrsb w2, [x16, #:lo12:struct_obj_4 + 16] + movn w16, #27631, lsl #0 + and w29, w2, w16 + sub w17, wzr, w8 + movz w16, #4355, lsl #0 + cmp w17, w16 + cset x5, gt + sub w10, w5, #1 + and w13, w9, w14 + cmp w12, #4 + cset x14, ne + cmp w11, w14 + cset x9, gt + cmp w13, w9 + cset x5, ge + movz w16, #7584, lsl #0 + cmp w5, w16 + cset x8, le + cmp w10, w8 + cset x6, le + eor w5, w29, w6 + sub w29, wzr, w5 + sub w9, wzr, w29 + adrp x16, struct_obj_10 + 4 + strb w9, [x16, #:lo12:struct_obj_10 + 4] + orr w2, wzr, #1 + movz w12, #0, lsl #0 + adrp x16, var_43 + ldrh w8, [x16, #:lo12:var_43] + cmp w8, #0 + csel x4, x2, x12, ne + cbnz w4, .L339 + adrp x16, var_25 + ldrsb w0, [x16, #:lo12:var_25] + cmp w0, #0 + cset x8, ne + b .L340 +.L339: + orr w8, wzr, #1 +.L340: + adrp x16, struct_obj_3 + 4 + ldrh w6, [x16, #:lo12:struct_obj_3 + 4] + cbz w6, .L341 + adrp x16, var_17 + ldrsh w17, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w7, [x16, #:lo12:var_9] + sub w2, w7, #12288 + sub w2, w2, #1187 + lsl w9, w17, w2 + cmp w9, #0 + cset x9, ne + b .L342 +.L341: + movz w9, #0, lsl #0 +.L342: + movn w16, #76, lsl #0 + eor w12, w6, w16 + adrp x16, var_30 + ldrh w3, [x16, #:lo12:var_30] + orr w3, wzr, w3, asr #7 + movz w16, #65483, lsl #0 + movk w16, #8191, lsl #16 + orr w13, w3, w16 + and w0, w12, w13 + adrp x16, struct_obj_2 + ldrsh w7, [x16, #:lo12:struct_obj_2] + sub w13, wzr, w7 + sub w11, wzr, w13 + adrp x16, var_1 + ldrh w29, [x16, #:lo12:var_1] + sub w19, wzr, w29 + madd w7, w11, w19, wzr + cmp w9, #4 + cset x10, ne + cmp w7, w10 + cset x17, gt + cbz w6, .L343 + adrp x16, var_17 + ldrsh w4, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w17, [x16, #:lo12:var_9] + sub w13, w17, #12288 + sub w13, w13, #1187 + lsl w10, w4, w13 + cmp w10, #0 + cset x17, ne + b .L344 +.L343: + movz w17, #0, lsl #0 +.L344: + adrp x16, var_7 + ldrsb w4, [x16, #:lo12:var_7] + sub w2, wzr, w4 + cbnz w2, .L345 + adrp x16, struct_obj_4 + 16 + ldrsb w5, [x16, #:lo12:struct_obj_4 + 16] + cbnz w5, .L346 + adrp x16, var_12 + ldrh w5, [x16, #:lo12:var_12] + cmp w5, #0 + cset x10, ne + b .L347 +.L346: + orr w10, wzr, #1 + b .L347 +.L345: + orr w10, wzr, #1 +.L347: + orr w9, wzr, #1 + sub w13, wzr, w6 + movz w16, #4355, lsl #0 + cmp w13, w16 + cset x2, gt + sub w2, w2, #1 + cmp w17, #4 + cset x4, ne + cmp w7, w4 + cset x5, gt + cmp w0, w5 + cset x5, ge + movz w16, #7584, lsl #0 + cmp w5, w16 + cset x14, le + cmp w2, w14 + cset x13, le + orn w2, wzr, w13 + cmp w2, w10 + cset x2, eq + adrp x16, var_27 + ldrsh w17, [x16, #:lo12:var_27] + movn w16, #97, lsl #0 + and w13, w17, w16 + cmp w9, w6 + cset x29, ne + cmp w13, w29 + cset x9, le + cmp w2, w9 + cset x5, le + cmp w8, w5 + b.eq .L348 + cbz w6, .L349 + adrp x16, var_17 + ldrsh w9, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w8, [x16, #:lo12:var_9] + sub w4, w8, #12288 + sub w4, w4, #1187 + lsl w15, w9, w4 + cmp w15, #0 + cset x4, ne + b .L350 +.L349: + movz w4, #0, lsl #0 +.L350: + cmp w4, #4 + cset x9, ne + cmp w7, w9 + cset x15, gt + cbz w6, .L351 + adrp x16, var_17 + ldrsh w2, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w8, [x16, #:lo12:var_9] + sub w29, w8, #12288 + sub w29, w29, #1187 + lsl w29, w2, w29 + cmp w29, #0 + cset x14, ne + b .L352 +.L351: + movz w14, #0, lsl #0 +.L352: + cmp w14, #4 + cset x8, ne + cmp w7, w8 + cset x1, gt + movz w16, #65483, lsl #0 + movk w16, #8191, lsl #16 + orr w13, w3, w16 + cbz w6, .L353 + adrp x16, var_17 + ldrsh w15, [x16, #:lo12:var_17] + adrp x16, var_9 + ldrh w1, [x16, #:lo12:var_9] + sub w1, w1, #12288 + sub w1, w1, #1187 + lsl w4, w15, w1 + cmp w4, #0 + cset x3, ne + b .L354 +.L353: + movz w3, #0, lsl #0 +.L354: + and w15, w12, w13 + madd w1, w11, w19, wzr + cmp w3, #4 + cset x17, ne + cmp w1, w17 + cset x9, gt + b .L355 +.L348: + adrp x16, struct_obj_8 + 24 + ldrh w12, [x16, #:lo12:struct_obj_8 + 24] + orr w8, w15, w12 + cbnz w8, .L356 + adrp x16, var_22 + ldrsb w6, [x16, #:lo12:var_22] + cmp w6, #0 + cset x5, ne + b .L357 +.L356: + orr w5, wzr, #1 +.L357: + orn w3, wzr, w5 + adrp x16, struct_obj_4 + 2 + ldrsb w14, [x16, #:lo12:struct_obj_4 + 2] + cmp w14, #30 + cset x4, ge + adrp x16, struct_obj_8 + 26 + ldrsb w9, [x16, #:lo12:struct_obj_8 + 26] + adrp x16, struct_obj_8 + 2 + ldrsh w8, [x16, #:lo12:struct_obj_8 + 2] + cbnz w8, .L358 + adrp x16, var_38 + ldrsb w5, [x16, #:lo12:var_38] + cmp w5, #0 + cset x4, ne + b .L359 +.L358: + orr w4, wzr, #1 +.L359: + adrp x16, var_57 + ldrsb w10, [x16, #:lo12:var_57] + adrp x16, var_37 + ldrsb w11, [x16, #:lo12:var_37] + and w7, w10, w11 + cbnz w7, .L360 + adrp x16, var_5 + ldrh w10, [x16, #:lo12:var_5] + orn w6, wzr, w10 + cmp w6, #0 + cset x8, ne + b .L361 +.L360: + orr w8, wzr, #1 +.L361: + adrp x16, var_21 + ldrsb w3, [x16, #:lo12:var_21] + cmp w3, #0 + cset x2, eq + adrp x16, var_55 + ldrsb w3, [x16, #:lo12:var_55] + madd w7, w3, w1, wzr + madd w2, w2, w7, wzr + ubfiz w11, w2, 0, 16 + adrp x16, var_56 + ldrh w10, [x16, #:lo12:var_56] + madd w1, w10, w9, wzr + cmp w4, w1 + cset x9, le + cmp w9, w8 + cset x12, gt + cmp w11, w12 + cset x4, le + adrp x16, var_62 + ldrh w14, [x16, #:lo12:var_62] + cmp w4, w14 + cset x0, le + adrp x16, var_42 + strb w0, [x16, #:lo12:var_42] +.L355: + movn w11, #94, lsl #0 + adrp x16, struct_obj_9 + 8 + ldrsh w2, [x16, #:lo12:struct_obj_9 + 8] + sub w17, w2, #38 + adrp x16, var_48 + ldrh w9, [x16, #:lo12:var_48] + madd w17, w17, w9, wzr + madd w7, w17, w11, wzr + cmp w7, #110 + b.ge .L362 + movz w10, #5919, lsl #0 + movk w10, #5, lsl #16 + movn w13, #974, lsl #0 + adrp x16, struct_obj_9 + 2 + ldrsb w8, [x16, #:lo12:struct_obj_9 + 2] + madd w12, w8, w13, wzr + adrp x16, var_9 + ldrh w15, [x16, #:lo12:var_9] + adrp x16, struct_obj_3 + ldrsh w3, [x16, #:lo12:struct_obj_3] + madd w2, w15, w3, wzr + sdiv w9, w12, w2 + movz w7, #9108, lsl #0 + movk w7, #2, lsl #16 + adrp x16, struct_obj_8 + 6 + ldrsh w6, [x16, #:lo12:struct_obj_8 + 6] + cmp w6, #0 + cset x13, eq + madd w17, w13, w7, wzr + madd w5, w9, w17, wzr + madd w5, w5, w10, wzr + cbnz w5, .L363 + adrp x16, struct_obj_4 + 2 + ldrsb w9, [x16, #:lo12:struct_obj_4 + 2] + ubfiz w3, w9, 0, 16 +.L363: + adrp x16, struct_obj_3 + 4 + ldrh w14, [x16, #:lo12:struct_obj_3 + 4] + cbz w14, .L364 + adrp x16, var_17 + ldrsh w7, [x16, #:lo12:var_17] + sub w12, w15, #12288 + sub w12, w12, #1187 + lsl w1, w7, w12 + cmp w1, #0 + cset x6, ne + b .L365 +.L364: + movz w6, #0, lsl #0 +.L365: + movn w16, #76, lsl #0 + eor w10, w14, w16 + adrp x16, var_30 + ldrh w13, [x16, #:lo12:var_30] + orr w11, wzr, w13, asr #7 + movz w16, #65483, lsl #0 + movk w16, #8191, lsl #16 + orr w9, w11, w16 + and w5, w10, w9 + adrp x16, struct_obj_2 + ldrsh w3, [x16, #:lo12:struct_obj_2] + sub w12, wzr, w3 + sub w2, wzr, w12 + adrp x16, var_1 + ldrh w9, [x16, #:lo12:var_1] + sub w29, wzr, w9 + madd w2, w2, w29, wzr + cmp w6, #4 + cset x29, ne + cmp w2, w29 + cset x4, gt + adrp x16, var_7 + ldrsb w10, [x16, #:lo12:var_7] + sub w4, wzr, w10 + cbnz w4, .L366 + adrp x16, struct_obj_4 + 16 + ldrsb w7, [x16, #:lo12:struct_obj_4 + 16] +.L366: + sub w6, wzr, w14 + movz w16, #4355, lsl #0 + cmp w6, w16 + cset x7, gt + adrp x16, var_27 + ldrsh w3, [x16, #:lo12:var_27] + movn w16, #97, lsl #0 + and w0, w3, w16 + adrp x16, var_18 + ldrsb w12, [x16, #:lo12:var_18] + ubfiz w3, w12, 0, 16 + cbnz w3, .L367 + cbz w14, .L368 + adrp x16, var_17 + ldrsh w1, [x16, #:lo12:var_17] + sub w9, w15, #12288 + sub w9, w9, #1187 + lsl w8, w1, w9 + cmp w8, #0 + cset x29, ne + b .L369 +.L368: + movz w29, #0, lsl #0 +.L369: + cmp w29, #4 + cset x6, ne + cmp w2, w6 + cset x6, gt + cbz w14, .L370 + adrp x16, var_17 + ldrsh w6, [x16, #:lo12:var_17] + sub w3, w15, #12288 + sub w3, w3, #1187 + lsl w15, w6, w3 + cmp w15, #0 + cset x10, ne + b .L371 +.L370: + movz w10, #0, lsl #0 +.L371: + cbnz w4, .L372 + adrp x16, struct_obj_4 + 16 + ldrsb w13, [x16, #:lo12:struct_obj_4 + 16] + cbnz w13, .L373 + adrp x16, var_12 + ldrh w17, [x16, #:lo12:var_12] + cmp w17, #0 + cset x1, ne + b .L374 +.L373: + orr w1, wzr, #1 + b .L374 +.L372: + orr w1, wzr, #1 +.L374: + orr w11, wzr, #1 + sub w12, w7, #1 + cmp w10, #4 + cset x15, ne + cmp w2, w15 + cset x29, gt + cmp w5, w29 + cset x3, ge + movz w16, #7584, lsl #0 + cmp w3, w16 + cset x5, le + cmp w12, w5 + cset x29, le + orn w12, wzr, w29 + cmp w12, w1 + cset x8, eq + cmp w11, w14 + cset x17, ne + cmp w0, w17 + cset x15, le + cmp w8, w15 + b.gt .L375 + adrp x16, struct_obj_8 + 18 + ldrsh w0, [x16, #:lo12:struct_obj_8 + 18] + cmp w0, #0 + cset x0, ne + cbnz w0, .L367 +.L375: + orr w0, wzr, #1 + eor w0, w0, #1 + cbz w0, .L329 +.L367: + orr w0, wzr, #1 + cbnz w0, .L329 + adrp x16, var_45 + ldrsb w0, [x16, #:lo12:var_45] + cbz w0, .L329 + adrp x16, struct_obj_8 + 26 + ldrsb w0, [x16, #:lo12:struct_obj_8 + 26] + cbnz w0, .L329 + adrp x16, var_23 + ldrh w0, [x16, #:lo12:var_23] + cmp w0, #0 + cset x0, ne + b .L329 +.L362: + adrp x16, var_17 + ldrsh w12, [x16, #:lo12:var_17] + adrp x16, var_60 + ldrsh w3, [x16, #:lo12:var_60] + cbnz w3, .L376 + adrp x16, struct_obj_9 + 26 + ldrsh w11, [x16, #:lo12:struct_obj_9 + 26] + cmp w11, #0 + cset x7, ne + b .L377 +.L376: + orr w7, wzr, #1 +.L377: + sbfiz w9, w3, 0, 8 + adrp x16, struct_obj_8 + 28 + ldrsh w8, [x16, #:lo12:struct_obj_8 + 28] + and w5, w9, w8 + asr w7, w5, w7 + cbnz w7, .L378 + adrp x16, struct_obj_3 + 4 + ldrh w5, [x16, #:lo12:struct_obj_3 + 4] +.L378: + adrp x16, var_62 + ldrh w5, [x16, #:lo12:var_62] + add w6, w2, w5 + adrp x16, struct_obj_2 + ldrsh w5, [x16, #:lo12:struct_obj_2] + cmp w5, #0 + cset x15, eq + adrp x16, struct_obj_3 + 4 + ldrh w11, [x16, #:lo12:struct_obj_3 + 4] + cbz w11, .L379 + adrp x16, var_9 + ldrh w4, [x16, #:lo12:var_9] + sub w13, w4, #12288 + sub w13, w13, #1187 + lsl w9, w12, w13 + cmp w9, #0 + cset x12, ne + b .L380 +.L379: + movz w12, #0, lsl #0 +.L380: + movn w16, #76, lsl #0 + eor w14, w11, w16 + adrp x16, var_30 + ldrh w4, [x16, #:lo12:var_30] + orr w15, wzr, w4, asr #7 + movz w16, #65483, lsl #0 + movk w16, #8191, lsl #16 + orr w13, w15, w16 + and w13, w14, w13 + sub w15, wzr, w5 + sub w17, wzr, w15 + adrp x16, var_1 + ldrh w7, [x16, #:lo12:var_1] + sub w14, wzr, w7 + madd w3, w17, w14, wzr + cmp w12, #4 + cset x5, ne + cmp w3, w5 + cset x8, gt + adrp x16, var_7 + ldrsb w0, [x16, #:lo12:var_7] + sub w0, wzr, w0 + cbnz w0, .L381 + adrp x16, struct_obj_4 + 16 + ldrsb w0, [x16, #:lo12:struct_obj_4 + 16] +.L381: + adrp x16, var_37 + ldrsb w0, [x16, #:lo12:var_37] + movz w0, #0, lsl #0 + adrp x16, var_52 + strh w0, [x16, #:lo12:var_52] +.L329: + ldr x19, [sp, #16] + ldr x20, [sp, #24] + ldr x30, [sp, #8] + add sp, sp, #32 + ret x30 + .type foo, @function + .size foo, . - foo diff --git a/multiple_labels_crash_test/hash.c b/multiple_labels_crash_test/hash.c new file mode 100644 index 00000000..a979bdc1 --- /dev/null +++ b/multiple_labels_crash_test/hash.c @@ -0,0 +1,3 @@ +void hash(unsigned long long int *seed, unsigned long long int const v) { + *seed ^= v + 0x9e3779b9 + ((*seed)<<6) + ((*seed)>>2); +} diff --git a/multiple_labels_crash_test/init.c b/multiple_labels_crash_test/init.c new file mode 100644 index 00000000..d3c7cfcc --- /dev/null +++ b/multiple_labels_crash_test/init.c @@ -0,0 +1,209 @@ +#include "init.h" + +const unsigned short var_1 = 64966; +const unsigned short var_2 = 17784; +signed char var_3 = 58; +const unsigned short var_4 = 3656; +unsigned short var_5 = 17583; +const unsigned short var_6 = 40663; +const signed char var_7 = 42; +unsigned short var_8 = 14662; +unsigned short var_9 = 13482; +unsigned short var_10 = 21751; +const short var_11 = 9782; +const unsigned short var_12 = 29985; +short var_13 = -23903; +const signed char var_14 = 26; +const unsigned short var_15 = 38613; +unsigned short var_16 = 7910; +short var_17 = 32667; +signed char var_18 = 77; +signed char var_19 = 69; +unsigned short var_20 = 49524; +const signed char var_21 = -59; +const signed char var_22 = 114; +const unsigned short var_23 = 43999; +short var_24 = -4596; +signed char var_25 = 127; +const unsigned short var_26 = 14598; +const short var_27 = 15321; +short var_28 = 13394; +const unsigned short var_29 = 51752; +const unsigned short var_30 = 42705; +const short var_31 = -23514; +unsigned short var_32 = 46800; +const unsigned short var_33 = 40302; +const signed char var_34 = -74; +unsigned short var_35 = 14428; + + +short var_36 = 27385; +signed char var_37 = 116; +signed char var_38 = 47; +unsigned short var_39 = 28164; +signed char var_40 = 68; +unsigned short var_41 = 48535; +signed char var_42 = -56; +unsigned short var_43 = 63272; +unsigned short var_44 = 53605; +signed char var_45 = -76; +unsigned short var_46 = 37656; +signed char var_47 = -2; +unsigned short var_48 = 20934; +signed char var_49 = -21; +unsigned short var_50 = 46979; +short var_51 = -11787; +short var_52 = 9874; +short var_53 = 13740; +short var_54 = -24909; +signed char var_55 = -12; +unsigned short var_56 = 20186; +signed char var_57 = -80; +signed char var_58 = 48; +unsigned short var_59 = 59812; +short var_60 = 21585; +signed char var_61 = -16; +unsigned short var_62 = 49246; +short var_63 = 21666; +signed char var_64 = -18; +short var_65 = -12846; + + +signed char var_70 = 63; +short var_78 = -3444; +unsigned short var_82 = 58294; +short var_90 = -25718; +unsigned short var_94 = 54118; +short var_100 = 16012; +short var_106 = 6394; +unsigned short var_123 = 42864; +short var_129 = 18229; +signed char var_143 = 92; +short var_152 = -25759; +signed char var_156 = -88; +signed char var_162 = 86; +short var_178 = -15567; +signed char var_217 = 37; +short var_234 = 29976; +signed char var_240 = 29; +unsigned short var_241 = 39297; +signed char var_260 = -30; +signed char var_268 = 13; +short var_284 = -4345; +unsigned short var_297 = 16067; +signed char var_314 = -126; +unsigned short var_358 = 48899; +short var_359 = 5585; +signed char var_367 = 57; +unsigned short var_392 = 6146; +signed char var_468 = -7; +signed char var_500 = 28; +short var_514 = -27356; +signed char var_522 = 67; +signed char var_543 = -115; +unsigned short var_544 = 38397; +signed char var_547 = 105; +signed char var_549 = 62; +short var_558 = -1976; +signed char var_591 = 78; + + +struct_5 struct_obj_1; +struct_5 struct_obj_2; +struct_5 struct_obj_3; +struct_2 struct_obj_4; + + +struct_1 struct_obj_5; +struct_5 struct_obj_6; +struct_1 struct_obj_7; +struct_4 struct_obj_8; +struct_2 struct_obj_9; +struct_1 struct_obj_10; + + + + + + + + + + + + +void init () { + struct_obj_1.member_5_0 = (short) (-13981); + struct_obj_1.member_5_1 = (unsigned short) (32569); + struct_obj_1.member_5_2 = (unsigned short) (55905); + struct_obj_1.member_5_3 = (short) (740); + struct_obj_2.member_5_0 = (short) (-16520); + struct_obj_2.member_5_1 = (unsigned short) (25768); + struct_obj_2.member_5_2 = (unsigned short) (41445); + struct_obj_2.member_5_3 = (short) (25458); + struct_obj_3.member_5_0 = (short) (-27814); + struct_obj_3.member_5_1 = (unsigned short) (32840); + struct_obj_3.member_5_2 = (unsigned short) (59825); + struct_obj_3.member_5_3 = (short) (-26656); + struct_obj_4.member_2_0 = (short) (7610); + struct_obj_4.member_2_1.member_1_0 = (signed char) (86); + struct_obj_4.member_2_1.member_1_1 = (short) (-29951); + struct_obj_4.member_2_1.member_1_2 = (signed char) (-57); + struct_obj_4.member_2_1.member_1_3 = (short) (-1514); + struct_obj_4.member_2_2 = (unsigned short) (30795); + struct_obj_4.member_2_3.member_1_0 = (signed char) (17); + struct_obj_4.member_2_3.member_1_1 = (short) (-21792); + struct_obj_4.member_2_3.member_1_2 = (signed char) (-78); + struct_obj_4.member_2_3.member_1_3 = (short) (-19417); + struct_obj_4.member_2_4 = (short) (-19205); + struct_obj_4.member_2_5 = (unsigned short) (10096); + struct_obj_4.member_2_6 = (unsigned short) (56048); + struct_obj_4.member_2_7 = (short) (-9525); + struct_obj_5.member_1_0 = (signed char) (-105); + struct_obj_5.member_1_1 = (short) (28953); + struct_obj_5.member_1_2 = (signed char) (-80); + struct_obj_5.member_1_3 = (short) (-20984); + struct_obj_6.member_5_0 = (short) (30730); + struct_obj_6.member_5_1 = (unsigned short) (44652); + struct_obj_6.member_5_2 = (unsigned short) (45968); + struct_obj_6.member_5_3 = (short) (12419); + struct_obj_7.member_1_0 = (signed char) (-74); + struct_obj_7.member_1_1 = (short) (-6639); + struct_obj_7.member_1_2 = (signed char) (-119); + struct_obj_7.member_1_3 = (short) (13879); + struct_obj_8.member_4_0 = (unsigned short) (17346); + struct_obj_8.member_4_1.member_3_0 = (short) (657); + struct_obj_8.member_4_1.member_3_1.member_1_0 = (signed char) (-103); + struct_obj_8.member_4_1.member_3_1.member_1_1 = (short) (25291); + struct_obj_8.member_4_1.member_3_1.member_1_2 = (signed char) (-76); + struct_obj_8.member_4_1.member_3_1.member_1_3 = (short) (-25024); + struct_obj_8.member_4_2 = (signed char) (42); + struct_obj_8.member_4_3 = (unsigned short) (57223); + struct_obj_8.member_4_4 = (signed char) (58); + struct_obj_8.member_4_5 = (short) (-1330); + struct_obj_8.member_4_6 = (short) (-13828); + struct_obj_8.member_4_7 = (unsigned short) (26678); + struct_obj_8.member_4_8 = (unsigned short) (52711); + struct_obj_8.member_4_9.member_1_0 = (signed char) (6); + struct_obj_8.member_4_9.member_1_1 = (short) (13897); + struct_obj_8.member_4_9.member_1_2 = (signed char) (-94); + struct_obj_8.member_4_9.member_1_3 = (short) (-30110); + struct_obj_9.member_2_0 = (short) (-24156); + struct_obj_9.member_2_1.member_1_0 = (signed char) (40); + struct_obj_9.member_2_1.member_1_1 = (short) (31967); + struct_obj_9.member_2_1.member_1_2 = (signed char) (-36); + struct_obj_9.member_2_1.member_1_3 = (short) (21679); + struct_obj_9.member_2_2 = (unsigned short) (40629); + struct_obj_9.member_2_3.member_1_0 = (signed char) (116); + struct_obj_9.member_2_3.member_1_1 = (short) (-741); + struct_obj_9.member_2_3.member_1_2 = (signed char) (101); + struct_obj_9.member_2_3.member_1_3 = (short) (24485); + struct_obj_9.member_2_4 = (short) (13544); + struct_obj_9.member_2_5 = (unsigned short) (26978); + struct_obj_9.member_2_6 = (unsigned short) (9057); + struct_obj_9.member_2_7 = (short) (21085); + struct_obj_10.member_1_0 = (signed char) (94); + struct_obj_10.member_1_1 = (short) (28577); + struct_obj_10.member_1_2 = (signed char) (-56); + struct_obj_10.member_1_3 = (short) (-21782); +}
\ No newline at end of file diff --git a/multiple_labels_crash_test/init.h b/multiple_labels_crash_test/init.h new file mode 100644 index 00000000..d3b5b008 --- /dev/null +++ b/multiple_labels_crash_test/init.h @@ -0,0 +1,181 @@ +void hash(unsigned long long int *seed, unsigned long long int const v); + +extern const unsigned short var_1; +extern const unsigned short var_2; +extern signed char var_3; +extern const unsigned short var_4; +extern unsigned short var_5; +extern const unsigned short var_6; +extern const signed char var_7; +extern unsigned short var_8; +extern unsigned short var_9; +extern unsigned short var_10; +extern const short var_11; +extern const unsigned short var_12; +extern short var_13; +extern const signed char var_14; +extern const unsigned short var_15; +extern unsigned short var_16; +extern short var_17; +extern signed char var_18; +extern signed char var_19; +extern unsigned short var_20; +extern const signed char var_21; +extern const signed char var_22; +extern const unsigned short var_23; +extern short var_24; +extern signed char var_25; +extern const unsigned short var_26; +extern const short var_27; +extern short var_28; +extern const unsigned short var_29; +extern const unsigned short var_30; +extern const short var_31; +extern unsigned short var_32; +extern const unsigned short var_33; +extern const signed char var_34; +extern unsigned short var_35; + + +extern short var_36; +extern signed char var_37; +extern signed char var_38; +extern unsigned short var_39; +extern signed char var_40; +extern unsigned short var_41; +extern signed char var_42; +extern unsigned short var_43; +extern unsigned short var_44; +extern signed char var_45; +extern unsigned short var_46; +extern signed char var_47; +extern unsigned short var_48; +extern signed char var_49; +extern unsigned short var_50; +extern short var_51; +extern short var_52; +extern short var_53; +extern short var_54; +extern signed char var_55; +extern unsigned short var_56; +extern signed char var_57; +extern signed char var_58; +extern unsigned short var_59; +extern short var_60; +extern signed char var_61; +extern unsigned short var_62; +extern short var_63; +extern signed char var_64; +extern short var_65; + + +extern signed char var_70; +extern short var_78; +extern unsigned short var_82; +extern short var_90; +extern unsigned short var_94; +extern short var_100; +extern short var_106; +extern unsigned short var_123; +extern short var_129; +extern signed char var_143; +extern short var_152; +extern signed char var_156; +extern signed char var_162; +extern short var_178; +extern signed char var_217; +extern short var_234; +extern signed char var_240; +extern unsigned short var_241; +extern signed char var_260; +extern signed char var_268; +extern short var_284; +extern unsigned short var_297; +extern signed char var_314; +extern unsigned short var_358; +extern short var_359; +extern signed char var_367; +extern unsigned short var_392; +extern signed char var_468; +extern signed char var_500; +extern short var_514; +extern signed char var_522; +extern signed char var_543; +extern unsigned short var_544; +extern signed char var_547; +extern signed char var_549; +extern short var_558; +extern signed char var_591; + + +typedef struct { + signed char member_1_0; + short member_1_1; + signed char member_1_2; + short member_1_3; +} struct_1; + +typedef struct { + short member_2_0; + struct_1 member_2_1; + unsigned short member_2_2; + struct_1 member_2_3; + short member_2_4; + unsigned short member_2_5; + unsigned short member_2_6; + short member_2_7; +} struct_2; + +typedef struct { + short member_3_0; + struct_1 member_3_1; +} struct_3; + +typedef struct { + unsigned short member_4_0; + struct_3 member_4_1; + signed char member_4_2; + unsigned short member_4_3; + signed char member_4_4; + short member_4_5; + short member_4_6; + unsigned short member_4_7; + unsigned short member_4_8; + struct_1 member_4_9; +} struct_4; + +typedef struct { + short member_5_0; + unsigned short member_5_1; + unsigned short member_5_2; + short member_5_3; +} struct_5; + +typedef struct { + signed char member_6_0; + unsigned short member_6_1; + short member_6_2; + struct_3 member_6_3; + struct_3 member_6_4; + signed char member_6_5; + short member_6_6; +} struct_6; + + + +extern struct_5 struct_obj_1; +extern struct_5 struct_obj_2; +extern struct_5 struct_obj_3; +extern struct_2 struct_obj_4; + + +extern struct_1 struct_obj_5; +extern struct_5 struct_obj_6; +extern struct_1 struct_obj_7; +extern struct_4 struct_obj_8; +extern struct_2 struct_obj_9; +extern struct_1 struct_obj_10; + + + + diff --git a/test/aarch64/README.md b/test/aarch64/README.md new file mode 100644 index 00000000..f943489c --- /dev/null +++ b/test/aarch64/README.md @@ -0,0 +1,15 @@ +# Testing the Machblock --> Asmblock translation +1. Get the reference version of compcert-aarch in the father's directory if this repo (checkout `aarch64-ref`) +2. Compile both repo for aarch64 +3. CD in this folder (`test/aarch64`) +4. Launch `./asmb_aarch64_gen_test.sh` + +## Options +The script takes following options : +- `-c` to clear generated files at the end +- `-w` to suppress warnings from Compcert + +## Tests files +The variable `DIRS` in the script takes the list of directories containing c files. +The tests under `test/aarch64/c` are simpler and useful to debug only one feature at a time. +Most of them comes from [here](https://cis.temple.edu/~ingargio/cis71/code/). diff --git a/test/aarch64/c/add_return.c b/test/aarch64/c/add_return.c new file mode 100644 index 00000000..c29aeb16 --- /dev/null +++ b/test/aarch64/c/add_return.c @@ -0,0 +1 @@ +int main(int r) { return r+1; } diff --git a/test/aarch64/c/addresses.c b/test/aarch64/c/addresses.c new file mode 100644 index 00000000..e3cb5201 --- /dev/null +++ b/test/aarch64/c/addresses.c @@ -0,0 +1,32 @@ +/* addresses.c -- Playing with addresses of variables and their contents: + * what is done by C with variables, addresses, and values. + */ + +#include <stdio.h> + +void moo(int a, int * b); + +int main(void) { + int x; + int *y; + + x=1; + y=&x; + printf("Address of x = %d, value of x = %d\n", &x, x); + printf("Address of y = %d, value of y = %d, value of *y = %d\n", &y, y, *y); + moo(9,y); +} + +void moo(int a, int *b){ + printf("Address of a = %d, value of a = %d\n", &a, a); + printf("Address of b = %d, value of b = %d, value of *b = %d\n", &b, b, *b); +} + +/* Output from running this program on my computer: + +Address of x = 536869640, value of x = 1 +Address of y = 536869632, value of y = 536869640, value of *y = 1 +Address of a = 536869608, value of a = 9 +Address of b = 536869600, value of b = 536869640, value of *b = 1 + + */ diff --git a/test/aarch64/c/arith.c b/test/aarch64/c/arith.c new file mode 100644 index 00000000..02df141b --- /dev/null +++ b/test/aarch64/c/arith.c @@ -0,0 +1,16 @@ +int main(int num1, int num2) +{ + int sum, sub, mult, mod; + float div; + + /* + * Perform all arithmetic operations + */ + sum = num1 + num2; + sub = num1 - num2; + mult = num1 * num2; + div = (float)num1 / num2; + mod = num1 % num2; + + return sum + sub + mult + div + mod; +} diff --git a/test/aarch64/c/arith_print.c b/test/aarch64/c/arith_print.c new file mode 100644 index 00000000..d404a151 --- /dev/null +++ b/test/aarch64/c/arith_print.c @@ -0,0 +1,19 @@ +int main() +{ + int num1 = 2; + int num2 = 4; + int sum, sub, mult, mod; + float div; + + /* + * Perform all arithmetic operations + */ + sum = num1 + num2; + sub = num1 - num2; + mult = num1 * num2; + div = (float)num1 / num2; + mod = num1 % num2; + + printf("%d", sum + sub + mult + div + mod); + return; +} diff --git a/test/aarch64/c/armstrong.c b/test/aarch64/c/armstrong.c new file mode 100644 index 00000000..c5d838f9 --- /dev/null +++ b/test/aarch64/c/armstrong.c @@ -0,0 +1,21 @@ +int main() +{ + int n,sum,i,t,a,z; + + for(i = 1; i <= 500; i++) + { + t = i; // as we need to retain the original number + sum = 0; + while(t != 0) + { + a = t%10; + sum += a*a*a; + t = t/10; + } + + if(sum == i) + z += i; + } + + return 0; +} diff --git a/test/aarch64/c/array1.c b/test/aarch64/c/array1.c new file mode 100644 index 00000000..5840ca66 --- /dev/null +++ b/test/aarch64/c/array1.c @@ -0,0 +1,64 @@ +/* array1.c -- Simple operations with arrays. + */ + +#include <stdio.h> +#define N 10 + +void oneWay(void); +void anotherWay(void); + +int main(void) { + printf("\noneWay:\n"); + oneWay(); + printf("\nantherWay:\n"); + anotherWay(); +} + +/*Array initialized with aggregate */ +void oneWay(void) { + int vect[N] = {1,2,3,4,5,6,7,8,9,0}; + int i; + + for (i=0; i<N; i++) + printf("i = %2d vect[i] = %2d\n", i, vect[i]); +} + +/*Array initialized with loop */ +void anotherWay(void) { + int vect[N]; + int i; + + for (i=0; i<N; i++) + vect[i] = i+1; + + for (i=0; i<N; i++) + printf("i = %2d vect[i] = %2d\n", i, vect[i]); +} + +/* The output of this program is + +oneWay: +i = 0 vect[i] = 1 +i = 1 vect[i] = 2 +i = 2 vect[i] = 3 +i = 3 vect[i] = 4 +i = 4 vect[i] = 5 +i = 5 vect[i] = 6 +i = 6 vect[i] = 7 +i = 7 vect[i] = 8 +i = 8 vect[i] = 9 +i = 9 vect[i] = 0 + +antherWay: +i = 0 vect[i] = 1 +i = 1 vect[i] = 2 +i = 2 vect[i] = 3 +i = 3 vect[i] = 4 +i = 4 vect[i] = 5 +i = 5 vect[i] = 6 +i = 6 vect[i] = 7 +i = 7 vect[i] = 8 +i = 8 vect[i] = 9 +i = 9 vect[i] = 10 + + */ diff --git a/test/aarch64/c/array2.c b/test/aarch64/c/array2.c new file mode 100644 index 00000000..389e1596 --- /dev/null +++ b/test/aarch64/c/array2.c @@ -0,0 +1,74 @@ +/* array2.c -- Read/writing/reversing integer arrays + */ + +#include <stdio.h> + +#define NMAX 10 + +void intSwap(int *x, int *y); +int getIntArray(int a[], int nmax, int sentinel); +void printIntArray(int a[], int n); +void reverseIntArray(int a[], int n); + +int main(void) { + int x[NMAX]; + int hmny; + + hmny = getIntArray(x, NMAX, 0); + printf("The array was: \n"); + printIntArray(x,hmny); + reverseIntArray(x,hmny); + printf("after reverse it is:\n"); + printIntArray(x,hmny); +} + +void intSwap(int *x, int *y) + /* It swaps the content of x and y */ +{ + int temp = *x; + *x = *y; + *y = temp; +} + +void printIntArray(int a[], int n) + /* n is the number of elements in the array a. + * These values are printed out, five per line. */ +{ + int i; + + for (i=0; i<n; ){ + printf("\t%d ", a[i++]); + if (i%5==0) + printf("\n"); + } + printf("\n"); +} + +int getIntArray(int a[], int nmax, int sentinel) + /* It reads up to nmax integers and stores then in a; sentinel + * terminates input. */ +{ + int n = 0; + int temp; + + do { + printf("Enter integer [%d to terminate] : ", sentinel); + scanf("%d", &temp); + if (temp==sentinel) break; + if (n==nmax) + printf("array is full\n"); + else + a[n++] = temp; + }while (1); + return n; +} + +void reverseIntArray(int a[], int n) + /* It reverse the order of the first n elements of a */ +{ + int i; + + for(i=0;i<n/2;i++){ + intSwap(&a[i],&a[n-i-1]); + } +} diff --git a/test/aarch64/c/biggest_of_3_int.c b/test/aarch64/c/biggest_of_3_int.c new file mode 100644 index 00000000..346908fc --- /dev/null +++ b/test/aarch64/c/biggest_of_3_int.c @@ -0,0 +1,10 @@ +int main(int a, int b, int c) { + if ((a > b) && (a > c)) { + return a; + } else if (b > c) { + return b; + } else { + return c; + } + return 0; +} diff --git a/test/aarch64/c/bitwise1.c b/test/aarch64/c/bitwise1.c new file mode 100644 index 00000000..d20641de --- /dev/null +++ b/test/aarch64/c/bitwise1.c @@ -0,0 +1,8 @@ +int main() +{ + int x = 6, y = 4; + x = x^y; + y = x^876987^x | y << 42; + + return ~x^y; +} diff --git a/test/aarch64/c/cpintarray.c b/test/aarch64/c/cpintarray.c new file mode 100644 index 00000000..8049fdfb --- /dev/null +++ b/test/aarch64/c/cpintarray.c @@ -0,0 +1,108 @@ +/* cpintarray.c -- Example showing how addresses and arrays are alike + */ + +#include <stdio.h> +#define SIZE 8 + +void cpIntArray(int *a, int *b, int n) +/*It copies n integers starting at b into a*/ +{ + for(;n>0;n--) + *a++=*b++; +} + + +void printIntArray(int a[], int n) + /* n is the number of elements in the array a. + * These values are printed out, five per line. */ +{ + int i; + + for (i=0; i<n; ){ + printf("\t%d ", a[i++]); + if (i%5==0) + printf("\n"); + } + printf("\n"); +} + +int getIntArray(int a[], int nmax, int sentinel) + /* It reads up to nmax integers and stores then in a; sentinel + * terminates input. */ +{ + int n = 0; + int temp; + + do { + printf("Enter integer [%d to terminate] : ", sentinel); + scanf("%d", &temp); + if (temp==sentinel) break; + if (n==nmax) + printf("array is full\n"); + else + a[n++] = temp; + }while (1); + return n; +} + +int main(void){ + int x[SIZE], nx; + int y[SIZE], ny; + + printf("Read the x array:\n"); + nx = getIntArray(x,SIZE,0); + printf("The x array is:\n"); + printIntArray(x,nx); + + printf("Read the y array:\n"); + ny = getIntArray(y,SIZE,0); + printf("The y array is:\n"); + printIntArray(y,ny); + + cpIntArray(x+2,y+3,4); + /*Notice the expression 'x+2'. x is interpreted as the address for + the beginning of the x array. +2 sais to increment that address + by two units, in accordance with the type of x, which is + an integer array. Thus we move from x to two integer locations + past it, that is to the location of x[2]. The same reasoning applied + to 'y+3'. + */ + printf("Printing x after having copied 4 elements\n" + "from y starting at y[3] into x starting at x[2]\n"); + printIntArray(x,nx); +} + +/* Here is the interaction in a run of this program: + +Read the x array: +Enter integer [0 to terminate] : 1 +Enter integer [0 to terminate] : 3 +Enter integer [0 to terminate] : 5 +Enter integer [0 to terminate] : 7 +Enter integer [0 to terminate] : 9 +Enter integer [0 to terminate] : 11 +Enter integer [0 to terminate] : 13 +Enter integer [0 to terminate] : 15 +Enter integer [0 to terminate] : 0 +The x array is: + 1 3 5 7 9 + 11 13 15 +Read the y array: +Enter integer [0 to terminate] : 2 +Enter integer [0 to terminate] : 4 +Enter integer [0 to terminate] : 6 +Enter integer [0 to terminate] : 8 +Enter integer [0 to terminate] : 10 +Enter integer [0 to terminate] : 12 +Enter integer [0 to terminate] : 14 +Enter integer [0 to terminate] : 16 +Enter integer [0 to terminate] : 0 +The y array is: + 2 4 6 8 10 + 12 14 16 +Printing x after having copied 4 elements +from y starting at y[3] into x starting at x[2] + 1 3 8 10 12 + 14 13 15 + + */ diff --git a/test/aarch64/c/enum1.c b/test/aarch64/c/enum1.c new file mode 100644 index 00000000..d1f6b48d --- /dev/null +++ b/test/aarch64/c/enum1.c @@ -0,0 +1,52 @@ +/* enum1.c -- Starting to use enumerated types: Printing for each + * day of the week, today, yesterday, and tomorrow, both + * as a string and as a number. + */ + +#include <stdio.h> + +/* Introducing an enumerated data type */ +enum days {monday,tuesday,wednesday,thursday,friday,saturday,sunday}; +typedef enum days days; // This allows us to use "days" as an abbreviation + // for "enum days" + +/* Two useful functions */ +days yesterday(days today){ + return (today+6)%7; +} +days tomorrow(days today){ + return (today+1)%7; +} + +// A useful array: thedays is an array of constant (i.e you cannot +// modify them) pointers to constant (i.e. you cannot modify them) strings +const char * const thedays[] = + {"monday", "tuesday", "wednesday", "thursday", + "friday", "saturday", "sunday"}; + +int main(void){ + days today; + + printf("today \tyesterday \ttomorrow\n" + "============================================\n"); + for (today=monday;today<=sunday;today++) + printf("%s = %d \t %s = %d \t %s = %d\n", + thedays[today], today, + thedays[yesterday(today)], yesterday(today), + thedays[tomorrow(today)], tomorrow(today)); +} + +/* + The output is: + +today yesterday tomorrow +============================================ +monday = 0 sunday = 6 tuesday = 1 +tuesday = 1 monday = 0 wednesday = 2 +wednesday = 2 tuesday = 1 thursday = 3 +thursday = 3 wednesday = 2 friday = 4 +friday = 4 thursday = 3 saturday = 5 +saturday = 5 friday = 4 sunday = 6 +sunday = 6 saturday = 5 monday = 0 + +*/ diff --git a/test/aarch64/c/enum2.c b/test/aarch64/c/enum2.c new file mode 100644 index 00000000..a18acb80 --- /dev/null +++ b/test/aarch64/c/enum2.c @@ -0,0 +1,50 @@ +/* enum2.c -- Starting to use enumerated types: Printing for each + * day of the week, today, yesterday, and tomorrow, both + * as a string and as a number. We use typedef + */ + +#include <stdio.h> + +/* Introducing an enumerated data type */ +typedef enum {monday,tuesday,wednesday,thursday,friday,saturday,sunday} days; + +/* Two useful functions */ +days yesterday(days today); +days tomorrow(days today); + +char *thedays[] = {"monday", "tuesday", "wednesday", "thursday", + "friday", "saturday", "sunday"}; + +int main(void){ + days today; + + printf("today \tyesterday \ttomorrow\n" + "============================================\n"); + for (today=monday;today<=sunday;today++) + printf("%s = %d \t %s = %d \t %s = %d\n", + thedays[today], today, + thedays[yesterday(today)], yesterday(today), + thedays[tomorrow(today)], tomorrow(today)); +} + +days yesterday(days today){ + return (today+6)%7; +} +days tomorrow(days today){ + return (today+1)%7; +} + +/* + The output is: + +today yesterday tomorrow +============================================ +monday = 0 sunday = 6 tuesday = 1 +tuesday = 1 monday = 0 wednesday = 2 +wednesday = 2 tuesday = 1 thursday = 3 +thursday = 3 wednesday = 2 friday = 4 +friday = 4 thursday = 3 saturday = 5 +saturday = 5 friday = 4 sunday = 6 +sunday = 6 saturday = 5 monday = 0 + +*/ diff --git a/test/aarch64/c/floop.c b/test/aarch64/c/floop.c new file mode 100644 index 00000000..30270892 --- /dev/null +++ b/test/aarch64/c/floop.c @@ -0,0 +1,8 @@ +int main(int x) +{ + int y = 4; + int s = 23; + for(int i = 0; i <= x; i++) + y << s; + return y; +} diff --git a/test/aarch64/c/floor.c b/test/aarch64/c/floor.c new file mode 100644 index 00000000..33a57af3 --- /dev/null +++ b/test/aarch64/c/floor.c @@ -0,0 +1,29 @@ +int main(int n) +{ + int x = 1, i; + + /* for positive values */ + if (n > 0) + { + for (; x <= n >> 1;) + { + x = x << 1; + } + n = x; + } + /* for negative values */ + else + { + n = ~n; + n = n + 1; + for (; x <= n >> 1;) + { + x = x << 1; + } + x = x << 1; + x = ~x; + x = x + 1; + n = x; + } + return n; +} diff --git a/test/aarch64/c/funcs.c b/test/aarch64/c/funcs.c new file mode 100644 index 00000000..49e610d6 --- /dev/null +++ b/test/aarch64/c/funcs.c @@ -0,0 +1,36 @@ +/* funcs.c -- More examples of functions + */ + +#include <stdio.h> + +int getint(void); /*It prompts user to enter an integer, which it returns*/ + +int getmax(int a, int b, int c); /*It returns value of largest of a, b, c*/ + +/* Main program: Using the various functions */ +int main (void) { + int x, y, z; + + x = getint(); + y = getint(); + z = getint(); + printf("The largest of %d, %d, and %d is %d\n", x, y, z, getmax(x,y,z)); +} + +int getint(void) { + int a; + + printf("Please enter an integer > "); + scanf("%d", &a); + return(a); +} + +int getmax(int a, int b, int c){ + int m = a; + + if (m<b) + m = b; + if (m<c) + m = c; + return(m); +} diff --git a/test/aarch64/c/hello.c b/test/aarch64/c/hello.c new file mode 100644 index 00000000..0279269e --- /dev/null +++ b/test/aarch64/c/hello.c @@ -0,0 +1,6 @@ +#include <stdio.h> + +int main(void) { + printf("Hello World!\n"); + return 0; +} diff --git a/test/aarch64/c/if.c b/test/aarch64/c/if.c new file mode 100644 index 00000000..7d2e249a --- /dev/null +++ b/test/aarch64/c/if.c @@ -0,0 +1,7 @@ +int main(int x) +{ + if (x > 27) + return 11; + else x--; + return x; +} diff --git a/test/aarch64/c/msb_pos.c b/test/aarch64/c/msb_pos.c new file mode 100644 index 00000000..f2e7fe09 --- /dev/null +++ b/test/aarch64/c/msb_pos.c @@ -0,0 +1,20 @@ +/* Function to find the MSB bit position */ +int main(int n) +{ + int i = 0, bit; + while (i < 32) + { + bit = n & 0x80000000; + if (bit == -0x80000000) + { + bit = 1; + } + + if (bit == 1) + break; + + n = n << 1; + i++; + } + return i; +} diff --git a/test/aarch64/c/power2.c b/test/aarch64/c/power2.c new file mode 100644 index 00000000..64707df9 --- /dev/null +++ b/test/aarch64/c/power2.c @@ -0,0 +1,42 @@ +/* power2.c -- Print out powers of 2: 1, 2, 4, 8, .. up to 2^N + */ + +#include <stdio.h> +#define N 16 + +int main(void) { + int n; /* The current exponent */ + int val = 1; /* The current power of 2 */ + + printf("\t n \t 2^n\n"); + printf("\t================\n"); + for (n=0; n<=N; n++) { + printf("\t%3d \t %6d\n", n, val); + val = 2*val; + } + return 0; +} + +/* It prints out : + + n 2^n + ================ + 0 1 + 1 2 + 2 4 + 3 8 + 4 16 + 5 32 + 6 64 + 7 128 + 8 256 + 9 512 + 10 1024 + 11 2048 + 12 4096 + 13 8192 + 14 16384 + 15 32768 + 16 65536 + +*/ diff --git a/test/aarch64/c/prime.c b/test/aarch64/c/prime.c new file mode 100644 index 00000000..6c51db32 --- /dev/null +++ b/test/aarch64/c/prime.c @@ -0,0 +1,23 @@ +/* prime1.c It prompts the user to enter an integer N. It prints out + * if it is a prime or not. If not, it prints out a factor of N. + */ + +#include <stdio.h> + +int main(int n) { + int i; + int flag; + + flag = 1; + for (i=2; (i<(n/2)) && flag; ) { /* May be we do not need to test + values of i greater than the square root of n? */ + if ((n % i) == 0) /* If true n is divisible by i */ + flag = 0; + else + i++; + } + + if (flag) + return 1; + return 0; +} diff --git a/test/aarch64/c/random.c b/test/aarch64/c/random.c new file mode 100644 index 00000000..50aa5737 --- /dev/null +++ b/test/aarch64/c/random.c @@ -0,0 +1,50 @@ +/* Generating random number sequences using the formula (linear congruence) + x[k+1] = (a*x[k] + c)mod m + where a, c, and m are parameters set by the user and passed as command line + parameters together with a seed i.e. x[0] + As a simple example try a=7, c=1, m=13, and seed=5 + A more sophisticated selection would be a=69069, c=0, + m=2^32=4294967296, and seed=31 + It will print out, in a sort of random order, up to m-1 distinct values. + Then it loops. + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> + +static long seed = 13; +static long a; +static long c; +static long m; + +void random_init(long s) { + if (s != 0) seed = s; +} + +long random() { + seed = (a*seed + c)%m; + return seed; + } + +int main(int argc, char * argv[]) { + if (argc != 5) { + printf("usage: %s a, c, m, seed\n", argv[0]); + return 1; + } + a = atoi(argv[1]); + c = atoi(argv[2]); + m = atoi(argv[3]); + long s = atoi(argv[4]); + random_init(s); + int k; + for (k = 0; k < m-1; k++) { + printf("%8ld", random()); + if (k % 8 == 7) { // after 8 elements go to a new line + printf("\n"); + sleep(1); // sleep for a second + } + } + printf("\n"); + return 0; +} diff --git a/test/aarch64/c/simple_op.c b/test/aarch64/c/simple_op.c new file mode 100644 index 00000000..7c43b081 --- /dev/null +++ b/test/aarch64/c/simple_op.c @@ -0,0 +1,8 @@ +int main(int argc, char ** argv) +{ + int n, m; + n = n + 1; + n = n * 7; + n / (8 - 2); + return n; +} diff --git a/test/aarch64/c/wloop.c b/test/aarch64/c/wloop.c new file mode 100644 index 00000000..5ba67419 --- /dev/null +++ b/test/aarch64/c/wloop.c @@ -0,0 +1,8 @@ +int main(int x) +{ + int y = 4; + int s = 23; + while(s < x) + y << s; + return y; +} diff --git a/test/aarch64/gen_tests/asmb_aarch64_gen_test.sh b/test/aarch64/gen_tests/asmb_aarch64_gen_test.sh new file mode 100755 index 00000000..660ff7aa --- /dev/null +++ b/test/aarch64/gen_tests/asmb_aarch64_gen_test.sh @@ -0,0 +1,106 @@ +#!/bin/bash + +CLEAN=0 +WOFF=0 +while getopts ':cw' 'OPTKEY'; do + case ${OPTKEY} in + c) CLEAN=1;; + w) WOFF=1;; + esac +done + +DIRS=( + ../c/*.c # Special simple tests + ../../c/*.c + ../../clightgen/*.c + ../../compression/*.c + ../../cse2/*.c + + # Monniaux test directory + ../../monniaux/binary_search/*.c + ../../monniaux/complex/*.c + #../../monniaux/crypto-algorithms/*.c # Warnings + ../../monniaux/cse2/*.c + #../../monniaux/des/*.c # Unsupported feature? + ../../monniaux/expect/*.c + ../../monniaux/fill_buffer/*.c + ../../monniaux/genann/*.c + #../../monniaux/heptagon_radio_transmitter/*.c # Warnings + ../../monniaux/idea/*.c + ../../monniaux/jumptable/*.c + ../../monniaux/licm/*.c + ../../monniaux/longjmp/*.c + ../../monniaux/loop/*.c + ../../monniaux/lustrev4_lustrec_heater_control/*.c + ../../monniaux/lustrev4_lv4_heater_control/*.c + ../../monniaux/lustrev4_lv6-en-2cgc_heater_control/*.c + #../../monniaux/lustrev6-carlightV2/*.c # Warnings + #../../monniaux/lustrev6-convertible-2cgc/*.c # Unsupported feature? + ../../monniaux/lustrev6-convertible-en-2cgc/*.c + #../../monniaux/lustrev6-convertible/*.c # Warnings + ../../monniaux/madd/*.c + #../../monniaux/math/*.c # Unsupported feature? + ../../monniaux/memcpy/*.c + #../../monniaux/micro-bunzip/*.c # Warnings + ../../monniaux/moves/*.c + ../../monniaux/multithreaded_volatile/*.c + ../../monniaux/nand/*.c + #../../monniaux/ncompress/*.c # Warnings + ../../monniaux/number_theoretic_transform/*.c + ../../monniaux/predicated/*.c + ../../monniaux/regalloc/*.c + ../../monniaux/rotate/*.c + ../../monniaux/scheduling/*.c + ../../monniaux/send_through/*.c + ../../monniaux/tiny-AES-c/*.c + ../../monniaux/varargs/*.c + ../../monniaux/xor_and_mat/*.c + #../../monniaux/zlib-1.2.11/*.c # Warnings +) +#FILES=../c/*.c +CCOMP_BBLOCKS="../../../ccomp -fno-postpass" +CCOMP_REF="../../../../CompCert_aarch64-ref/ccomp" +COUNT=0 + +if [ $WOFF -eq 1 ] +then + CCOMP_BBLOCKS="${CCOMP_BBLOCKS} -w" + CCOMP_REF="${CCOMP_REF} -w" +fi + +for files in ${DIRS[@]} +do + for f in $files + do + BNAME=$(basename -s .c $f) + SNAME="$BNAME".s + SREFNAME="$BNAME"_ref.s + ./$CCOMP_BBLOCKS -S $f -o $SNAME + ./$CCOMP_REF -dmach -S $f -o $SREFNAME + #diff -I '^//*' <(cut -c-5 $SNAME) <(cut -c-5 $SREFNAME) > /dev/null 2>&1 + diff -I '^//*' $SNAME $SREFNAME > /dev/null 2>&1 + + error=$? + if [ $error -eq 0 ] + then + echo "[$BNAME] OK" + COUNT=$((COUNT + 1)) + elif [ $error -eq 1 ] + then + echo "[$BNAME] FAIL" + diff -I '^//*' -y $SNAME $SREFNAME + exit 1 + else + echo "[$BNAME] FAIL" + echo "[WARNING] There was something wrong with the diff command !" + exit 1 + fi + done +done + +echo "[TOTAL] $COUNT tests PASSED" + +if [ $CLEAN -eq 1 ] +then + rm *.s *.mach +fi diff --git a/test/aarch64/postpass_tests/postpass_exec_c_test.sh b/test/aarch64/postpass_tests/postpass_exec_c_test.sh new file mode 100755 index 00000000..73422990 --- /dev/null +++ b/test/aarch64/postpass_tests/postpass_exec_c_test.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +CLEAN=0 +WOFF=0 +SRC="" +while getopts ':cwi:' 'OPTKEY'; do + case ${OPTKEY} in + c) CLEAN=1;; + w) WOFF=1;; + i) SRC=${OPTARG};; + esac +done + +CCOMP="../../../ccomp -static" + +if [ $WOFF -eq 1 ] +then + CCOMP="${CCOMP} -w" +fi + +BNAME=$(basename -s .c $SRC) +SNAME="$BNAME".s +SREFNAME="$BNAME"_ref.s +ENAME="$BNAME" +EREFNAME="$BNAME"_ref +./$CCOMP -S $SRC -o $SNAME +./$CCOMP -fno-postpass -S $SRC -o $SREFNAME +./$CCOMP $SRC -o $ENAME +./$CCOMP -fno-postpass $SRC -o $EREFNAME + +#diff -I '^//*' -y $SNAME $SREFNAME + +if [ $CLEAN -eq 1 ] +then + rm $SNAME $SREFNAME $ENAME $EREFNAME +fi |